From: TimePath Date: Mon, 28 Sep 2015 05:29:21 +0000 (+1000) Subject: Turrets: cleanup X-Git-Tag: xonotic-v0.8.2~1874^2~72 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=129cf6ae83fa24855423c8edec3ad2cb072cb4cd;p=xonotic%2Fxonotic-data.pk3dir.git Turrets: cleanup --- diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index ca31f32f7..8bb66c874 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -146,7 +146,6 @@ void CSQC_Init(void) // needs to be done so early because of the constants they create static_init(); - CALL_ACCUMULATED_FUNCTION(RegisterTurrets); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); diff --git a/qcsrc/client/progs.inc b/qcsrc/client/progs.inc index 1b9c587ab..449692d5f 100644 --- a/qcsrc/client/progs.inc +++ b/qcsrc/client/progs.inc @@ -55,11 +55,11 @@ #include "../common/items/all.qc" #include "../common/monsters/all.qc" #include "../common/mutators/all.qc" +#include "../common/turrets/all.qc" #include "../common/vehicles/all.qc" #include "../common/weapons/all.qc" #include "../common/turrets/cl_turrets.qc" -#include "../common/turrets/all.qc" #include "../common/triggers/include.qc" diff --git a/qcsrc/common/nades.qc b/qcsrc/common/nades.qc index f361730ba..d75087125 100644 --- a/qcsrc/common/nades.qc +++ b/qcsrc/common/nades.qc @@ -78,7 +78,7 @@ void ent_healer() {SELFPARAM(); int sf = ReadByte(); - if(sf & TNSF_SETUP) + if(sf & 1) { self.origin_x = ReadCoord(); self.origin_y = ReadCoord(); diff --git a/qcsrc/common/turrets/all.inc b/qcsrc/common/turrets/all.inc index 04bb10f6a..5c9f1e16f 100644 --- a/qcsrc/common/turrets/all.inc +++ b/qcsrc/common/turrets/all.inc @@ -1,12 +1,12 @@ -#include "unit/ewheel.qc" -#include "unit/flac.qc" -#include "unit/fusionreactor.qc" -#include "unit/hellion.qc" -#include "unit/hk.qc" -#include "unit/machinegun.qc" -#include "unit/mlrs.qc" -#include "unit/phaser.qc" -#include "unit/plasma.qc" -#include "unit/plasma_dual.qc" -#include "unit/tesla.qc" -#include "unit/walker.qc" +#include "turret/ewheel.qc" +#include "turret/flac.qc" +#include "turret/fusionreactor.qc" +#include "turret/hellion.qc" +#include "turret/hk.qc" +#include "turret/machinegun.qc" +#include "turret/mlrs.qc" +#include "turret/phaser.qc" +#include "turret/plasma.qc" +#include "turret/plasma_dual.qc" +#include "turret/tesla.qc" +#include "turret/walker.qc" diff --git a/qcsrc/common/turrets/all.qc b/qcsrc/common/turrets/all.qc index f0fc7195a..c23a13861 100644 --- a/qcsrc/common/turrets/all.qc +++ b/qcsrc/common/turrets/all.qc @@ -1,5 +1,22 @@ #include "all.qh" +Turret get_turretinfo(int id) +{ + if (id < 1 || id > TUR_COUNT - 1) + return TUR_Null; + Turret m = turret_info[id]; + if (m) return m; + return TUR_Null; +} + +#ifdef SVQC +#include "sv_turrets.qh" +#endif + +#ifdef CSQC +#include "cl_turrets.qh" +#endif + #define IMPLEMENTATION #include "all.inc" #undef IMPLEMENTATION diff --git a/qcsrc/common/turrets/all.qh b/qcsrc/common/turrets/all.qh index 4f8a72802..3e4af08f6 100644 --- a/qcsrc/common/turrets/all.qh +++ b/qcsrc/common/turrets/all.qh @@ -1,147 +1,8 @@ -#ifndef TURRETS_H -#define TURRETS_H +#ifndef TURRETS_ALL_H +#define TURRETS_ALL_H -// turret requests -#define TR_SETUP 1 // (BOTH) setup turret data -#define TR_THINK 2 // (SERVER) logic to run every frame -#define TR_DEATH 3 // (SERVER) called when turret dies -#define TR_PRECACHE 4 // (BOTH) precaches models/sounds used by this turret -#define TR_ATTACK 5 // (SERVER) called when turret attacks -#define TR_CONFIG 6 // (ALL) +#include "turret.qh" -// functions: -entity get_turretinfo(int id); - -// fields: -.entity tur_head; - -// target selection flags -.int target_select_flags; -.int target_validate_flags; -const int TFL_TARGETSELECT_NO = 2; // don't automatically find targets -const int TFL_TARGETSELECT_LOS = 4; // require line of sight to find targets -const int TFL_TARGETSELECT_PLAYERS = 8; // target players -const int TFL_TARGETSELECT_MISSILES = 16; // target projectiles -const int TFL_TARGETSELECT_TRIGGERTARGET = 32; // respond to turret_trigger_target events -const int TFL_TARGETSELECT_ANGLELIMITS = 64; // apply extra angular limits to target selection -const int TFL_TARGETSELECT_RANGELIMITS = 128; // limit target selection range -const int TFL_TARGETSELECT_TEAMCHECK = 256; // don't attack teammates -const int TFL_TARGETSELECT_NOBUILTIN = 512; // only attack targets when triggered -const int TFL_TARGETSELECT_OWNTEAM = 1024; // only attack teammates -const int TFL_TARGETSELECT_NOTURRETS = 2048; // don't attack other turrets -const int TFL_TARGETSELECT_FOV = 4096; // extra limits to attack range -const int TFL_TARGETSELECT_MISSILESONLY = 8192; // only attack missiles - -// aim flags -.int aim_flags; -const int TFL_AIM_NO = 1; // no aiming -const int TFL_AIM_SPLASH = 2; // aim for ground around the target's feet -const int TFL_AIM_LEAD = 4; // try to predict target movement -const int TFL_AIM_SHOTTIMECOMPENSATE = 8; // compensate for shot traveltime when leading -const int TFL_AIM_ZPREDICT = 16; // predict target's z position at impact -const int TFL_AIM_SIMPLE = 32; // aim at player's current location - -// tracking flags -.int track_flags; -const int TFL_TRACK_NO = 2; // don't move head -const int TFL_TRACK_PITCH = 4; // pitch head -const int TFL_TRACK_ROTATE = 8; // rotate head - -// prefire checks -.int firecheck_flags; -const int TFL_FIRECHECK_DEAD = 4; // don't attack dead targets (zombies?) -const int TFL_FIRECHECK_DISTANCES = 8; // another range check -const int TFL_FIRECHECK_LOS = 16; // line of sight -const int TFL_FIRECHECK_AIMDIST = 32; // consider distance impactpoint<->aimspot -const int TFL_FIRECHECK_REALDIST = 64; // consider enemy origin<->impactpoint -const int TFL_FIRECHECK_ANGLEDIST = 128; // consider angular diff head<->aimspot -const int TFL_FIRECHECK_TEAMCHECK = 256; // don't attack teammates -const int TFL_FIRECHECK_AFF = 512; // try to avoid any friendly fire -const int TFL_FIRECHECK_AMMO_OWN = 1024; // own ammo needs to be larger than damage dealt -const int TFL_FIRECHECK_AMMO_OTHER = 2048; // target's ammo needs to be less than max -const int TFL_FIRECHECK_REFIRE = 4096; // check single attack finished delays -const int TFL_FIRECHECK_NO = 16384; // no prefire checks - -// attack flags -.int shoot_flags; -const int TFL_SHOOT_NO = 64; // no attacking -const int TFL_SHOOT_VOLLY = 2; // fire in vollies -const int TFL_SHOOT_VOLLYALWAYS = 4; // always do a full volly, even if target is lost -const int TFL_SHOOT_HITALLVALID = 8; // loop through all valid targets -const int TFL_SHOOT_CLEARTARGET = 16; // lose target after attack (after volly is done if in volly mode) -const int TFL_SHOOT_CUSTOM = 32; // custom attacking - -// turret capabilities -.int turret_flags; -const int TUR_FLAG_NONE = 0; // no abilities -const int TUR_FLAG_SNIPER = 2; // sniping turret -const int TUR_FLAG_SPLASH = 4; // can deal splash damage -const int TUR_FLAG_HITSCAN = 8; // hit scan -const int TUR_FLAG_MULTIGUN = 16; // multiple guns -const int TUR_FLAG_GUIDED = 32; // laser guided projectiles -const int TUR_FLAG_SLOWPROJ = 64; // turret fires slow projectiles -const int TUR_FLAG_MEDPROJ = 128; // turret fires medium projectiles -const int TUR_FLAG_FASTPROJ = 256; // turret fires fast projectiles -const int TUR_FLAG_PLAYER = 512; // can damage players -const int TUR_FLAG_MISSILE = 1024; // can damage missiles -const int TUR_FLAG_SUPPORT = 2048; // supports other units -const int TUR_FLAG_AMMOSOURCE = 4096; // can provide ammunition -const int TUR_FLAG_RECIEVETARGETS = 8192; // can recieve targets from external sources -const int TUR_FLAG_MOVE = 16384; // can move -const int TUR_FLAG_ROAM = 32768; // roams around if not attacking -const int TUR_FLAG_ISTURRET = 65536; // identifies this unit as a turret - -// ammo types -#define ammo_flags currentammo -const int TFL_AMMO_NONE = 64; // doesn't use ammo -const int TFL_AMMO_ENERGY = 2; // uses power -const int TFL_AMMO_BULLETS = 4; // uses bullets -const int TFL_AMMO_ROCKETS = 8; // uses explosives -const int TFL_AMMO_RECHARGE = 16; // regenerates ammo -const int TFL_AMMO_RECIEVE = 32; // can recieve ammo from support units - -// damage flags -.int damage_flags; -const int TFL_DMG_NO = 256; // doesn't take damage -const int TFL_DMG_YES = 2; // can be damaged -const int TFL_DMG_TEAM = 4; // can be damaged by teammates -const int TFL_DMG_RETALIATE = 8; // target attackers -const int TFL_DMG_RETALIATE_TEAM = 16; // target attackers, even if on same team -const int TFL_DMG_TARGETLOSS = 32; // loses target when damaged -const int TFL_DMG_AIMSHAKE = 64; // damage throws off aim -const int TFL_DMG_HEADSHAKE = 128; // damage shakes head -const int TFL_DMG_DEATH_NORESPAWN = 256; // no re-spawning - -// spawn flags -const int TSF_SUSPENDED = 1; -const int TSF_TERRAINBASE = 2; // currently unused -const int TSF_NO_AMMO_REGEN = 4; // disable builtin ammo regeneration -const int TSF_NO_PATHBREAK = 8; // don't break path to chase enemies, will still fire at them if possible -const int TSL_NO_RESPAWN = 16; // don't re-spawn -const int TSL_ROAM = 32; // roam while idle - -// send flags -const int TNSF_UPDATE = 2; -const int TNSF_STATUS = 4; -const int TNSF_SETUP = 8; -const int TNSF_ANG = 16; -const int TNSF_AVEL = 32; -const int TNSF_MOVE = 64; -.float anim_start_time; -const int TNSF_ANIM = 128; - -const int TNSF_FULL_UPDATE = 16777215; - - -// other useful macros -#define TUR_ACTION(turrettype,mrequest) (get_turretinfo(turrettype)).turret_func(mrequest) -#define TUR_NAME(turrettype) (get_turretinfo(turrettype)).turret_name - -// ===================== -// Turret Registration -// ===================== - -float t_null(float dummy); void register_turret(entity e, float(float) func, float turretflags, vector min_s, vector max_s, string modelname, string headmodelname, string shortname, string mname); const int TUR_MAXCOUNT = 24; @@ -164,37 +25,6 @@ REGISTER_REGISTRY(RegisterTurrets) _REGISTER_TURRET(id,func,turretflags,min_s,max_s,modelname,headmodelname,shortname,mname) #endif -float t_null(float dummy) { return 0; } - -CLASS(Turret, Object) - ATTRIB(Turret, m_id, int, 0) - - ATTRIB(Turret, turretid, int, 0) - /** short name */ - ATTRIB(Turret, netname, string, string_null) - /** human readable name */ - ATTRIB(Turret, turret_name, string, string_null) - /** t_... */ - ATTRIB(Turret, turret_func, float(float), t_null) - /** currently a copy of the model */ - ATTRIB(Turret, mdl, string, string_null) - /** full name of model */ - ATTRIB(Turret, model, string, string_null) - /** full name of tur_head model */ - ATTRIB(Turret, head_model, string, string_null) - /** TODO: deprecate! */ - ATTRIB(Turret, cvar_basename, string, string_null) - - ATTRIB(Turret, spawnflags, int, 0) - /** turret hitbox size */ - ATTRIB(Turret, mins, vector, '0 0 0') - /** turret hitbox size */ - ATTRIB(Turret, maxs, vector, '0 0 0') - - METHOD(Turret, display, void(entity this, void(string name, string icon) returns)) { - returns(this.turret_name, string_null); - } - void register_turret(Turret e, float(float) func, float turretflags, vector min_s, vector max_s, string modelname, string headmodelname, string shortname, string mname) { e.classname = "turret_info"; @@ -210,8 +40,8 @@ void register_turret(Turret e, float(float) func, float turretflags, vector min_ e.model = strzone(strcat("models/turrets/", modelname)); e.head_model = strzone(strcat("models/turrets/", headmodelname)); } -ENDCLASS(Turret) +entity get_turretinfo(int id); REGISTER_TURRET(Null, t_null, @@ -224,17 +54,6 @@ REGISTER_TURRET(Null, "Turret" ); -entity get_turretinfo(float id) -{ - entity m; - if(id < 1 || id > TUR_COUNT - 1) - return TUR_Null; - m = turret_info[id]; - if(m) - return m; - return TUR_Null; -} - #include "all.inc" #endif diff --git a/qcsrc/common/turrets/cl_turrets.qc b/qcsrc/common/turrets/cl_turrets.qc index b2a0fe1b5..94fb4ae3f 100644 --- a/qcsrc/common/turrets/cl_turrets.qc +++ b/qcsrc/common/turrets/cl_turrets.qc @@ -1,5 +1,3 @@ -#include "all.qh" - void turret_remove() {SELFPARAM(); remove(self.tur_head); diff --git a/qcsrc/common/turrets/cl_turrets.qh b/qcsrc/common/turrets/cl_turrets.qh index f8ea64ad1..0f8ff9485 100644 --- a/qcsrc/common/turrets/cl_turrets.qh +++ b/qcsrc/common/turrets/cl_turrets.qh @@ -1,8 +1,6 @@ #ifndef CL_TURRETS_H #define CL_TURRETS_H -#include "all.qh" - void ent_turret(); #endif diff --git a/qcsrc/common/turrets/sv_turrets.qc b/qcsrc/common/turrets/sv_turrets.qc index c17061b22..337b2789a 100644 --- a/qcsrc/common/turrets/sv_turrets.qc +++ b/qcsrc/common/turrets/sv_turrets.qc @@ -1,5 +1,4 @@ #ifdef SVQC -#include "all.qh" #include "../../server/autocvars.qh" // Generic aiming diff --git a/qcsrc/common/turrets/sv_turrets.qh b/qcsrc/common/turrets/sv_turrets.qh index 1a4ade680..4eca2c6fb 100644 --- a/qcsrc/common/turrets/sv_turrets.qh +++ b/qcsrc/common/turrets/sv_turrets.qh @@ -1,7 +1,11 @@ #ifndef SV_TURRETS_H #define SV_TURRETS_H -#include "all.qh" +entity turret_projectile(string _snd, float _size, float _health, float _death, float _proj_type, float _cull, float _cli_anim); +void turret_projectile_explode(); +float turret_validate_target(entity e_turret, entity e_target, float validate_flags); +float turret_firecheck(); +entity turret_select_target(); // turret fields .float ticrate; // interal ai think rate diff --git a/qcsrc/common/turrets/turret.qh b/qcsrc/common/turrets/turret.qh new file mode 100644 index 000000000..e31d93fd2 --- /dev/null +++ b/qcsrc/common/turrets/turret.qh @@ -0,0 +1,173 @@ +#ifndef TURRET_H +#define TURRET_H + +// turret requests +const int TR_SETUP = 1; // (BOTH) setup turret data +const int TR_THINK = 2; // (SERVER) logic to run every frame +const int TR_DEATH = 3; // (SERVER) called when turret dies +const int TR_PRECACHE = 4; // (BOTH) precaches models/sounds used by this turret +const int TR_ATTACK = 5; // (SERVER) called when turret attacks +const int TR_CONFIG = 6; // (ALL) + +// functions: +entity get_turretinfo(int id); + +// fields: +.entity tur_head; + +// target selection flags +.int target_select_flags; +.int target_validate_flags; +const int TFL_TARGETSELECT_NO = 2; // don't automatically find targets +const int TFL_TARGETSELECT_LOS = 4; // require line of sight to find targets +const int TFL_TARGETSELECT_PLAYERS = 8; // target players +const int TFL_TARGETSELECT_MISSILES = 16; // target projectiles +const int TFL_TARGETSELECT_TRIGGERTARGET = 32; // respond to turret_trigger_target events +const int TFL_TARGETSELECT_ANGLELIMITS = 64; // apply extra angular limits to target selection +const int TFL_TARGETSELECT_RANGELIMITS = 128; // limit target selection range +const int TFL_TARGETSELECT_TEAMCHECK = 256; // don't attack teammates +const int TFL_TARGETSELECT_NOBUILTIN = 512; // only attack targets when triggered +const int TFL_TARGETSELECT_OWNTEAM = 1024; // only attack teammates +const int TFL_TARGETSELECT_NOTURRETS = 2048; // don't attack other turrets +const int TFL_TARGETSELECT_FOV = 4096; // extra limits to attack range +const int TFL_TARGETSELECT_MISSILESONLY = 8192; // only attack missiles + +// aim flags +.int aim_flags; +const int TFL_AIM_NO = 1; // no aiming +const int TFL_AIM_SPLASH = 2; // aim for ground around the target's feet +const int TFL_AIM_LEAD = 4; // try to predict target movement +const int TFL_AIM_SHOTTIMECOMPENSATE = 8; // compensate for shot traveltime when leading +const int TFL_AIM_ZPREDICT = 16; // predict target's z position at impact +const int TFL_AIM_SIMPLE = 32; // aim at player's current location + +// tracking flags +.int track_flags; +const int TFL_TRACK_NO = 2; // don't move head +const int TFL_TRACK_PITCH = 4; // pitch head +const int TFL_TRACK_ROTATE = 8; // rotate head + +// prefire checks +.int firecheck_flags; +const int TFL_FIRECHECK_DEAD = 4; // don't attack dead targets (zombies?) +const int TFL_FIRECHECK_DISTANCES = 8; // another range check +const int TFL_FIRECHECK_LOS = 16; // line of sight +const int TFL_FIRECHECK_AIMDIST = 32; // consider distance impactpoint<->aimspot +const int TFL_FIRECHECK_REALDIST = 64; // consider enemy origin<->impactpoint +const int TFL_FIRECHECK_ANGLEDIST = 128; // consider angular diff head<->aimspot +const int TFL_FIRECHECK_TEAMCHECK = 256; // don't attack teammates +const int TFL_FIRECHECK_AFF = 512; // try to avoid any friendly fire +const int TFL_FIRECHECK_AMMO_OWN = 1024; // own ammo needs to be larger than damage dealt +const int TFL_FIRECHECK_AMMO_OTHER = 2048; // target's ammo needs to be less than max +const int TFL_FIRECHECK_REFIRE = 4096; // check single attack finished delays +const int TFL_FIRECHECK_NO = 16384; // no prefire checks + +// attack flags +.int shoot_flags; +const int TFL_SHOOT_NO = 64; // no attacking +const int TFL_SHOOT_VOLLY = 2; // fire in vollies +const int TFL_SHOOT_VOLLYALWAYS = 4; // always do a full volly, even if target is lost +const int TFL_SHOOT_HITALLVALID = 8; // loop through all valid targets +const int TFL_SHOOT_CLEARTARGET = 16; // lose target after attack (after volly is done if in volly mode) +const int TFL_SHOOT_CUSTOM = 32; // custom attacking + +// turret capabilities +.int turret_flags; +const int TUR_FLAG_NONE = 0; // no abilities +const int TUR_FLAG_SNIPER = 2; // sniping turret +const int TUR_FLAG_SPLASH = 4; // can deal splash damage +const int TUR_FLAG_HITSCAN = 8; // hit scan +const int TUR_FLAG_MULTIGUN = 16; // multiple guns +const int TUR_FLAG_GUIDED = 32; // laser guided projectiles +const int TUR_FLAG_SLOWPROJ = 64; // turret fires slow projectiles +const int TUR_FLAG_MEDPROJ = 128; // turret fires medium projectiles +const int TUR_FLAG_FASTPROJ = 256; // turret fires fast projectiles +const int TUR_FLAG_PLAYER = 512; // can damage players +const int TUR_FLAG_MISSILE = 1024; // can damage missiles +const int TUR_FLAG_SUPPORT = 2048; // supports other units +const int TUR_FLAG_AMMOSOURCE = 4096; // can provide ammunition +const int TUR_FLAG_RECIEVETARGETS = 8192; // can recieve targets from external sources +const int TUR_FLAG_MOVE = 16384; // can move +const int TUR_FLAG_ROAM = 32768; // roams around if not attacking +const int TUR_FLAG_ISTURRET = 65536; // identifies this unit as a turret + +// ammo types +#define ammo_flags currentammo +const int TFL_AMMO_NONE = 64; // doesn't use ammo +const int TFL_AMMO_ENERGY = 2; // uses power +const int TFL_AMMO_BULLETS = 4; // uses bullets +const int TFL_AMMO_ROCKETS = 8; // uses explosives +const int TFL_AMMO_RECHARGE = 16; // regenerates ammo +const int TFL_AMMO_RECIEVE = 32; // can recieve ammo from support units + +// damage flags +.int damage_flags; +const int TFL_DMG_NO = 256; // doesn't take damage +const int TFL_DMG_YES = 2; // can be damaged +const int TFL_DMG_TEAM = 4; // can be damaged by teammates +const int TFL_DMG_RETALIATE = 8; // target attackers +const int TFL_DMG_RETALIATE_TEAM = 16; // target attackers, even if on same team +const int TFL_DMG_TARGETLOSS = 32; // loses target when damaged +const int TFL_DMG_AIMSHAKE = 64; // damage throws off aim +const int TFL_DMG_HEADSHAKE = 128; // damage shakes head +const int TFL_DMG_DEATH_NORESPAWN = 256; // no re-spawning + +// spawn flags +const int TSF_SUSPENDED = 1; +const int TSF_TERRAINBASE = 2; // currently unused +const int TSF_NO_AMMO_REGEN = 4; // disable builtin ammo regeneration +const int TSF_NO_PATHBREAK = 8; // don't break path to chase enemies, will still fire at them if possible +const int TSL_NO_RESPAWN = 16; // don't re-spawn +const int TSL_ROAM = 32; // roam while idle + +// send flags +const int TNSF_UPDATE = 2; +const int TNSF_STATUS = 4; +const int TNSF_SETUP = 8; +const int TNSF_ANG = 16; +const int TNSF_AVEL = 32; +const int TNSF_MOVE = 64; +.float anim_start_time; +const int TNSF_ANIM = 128; + +const int TNSF_FULL_UPDATE = 16777215; + + +// other useful macros +#define TUR_ACTION(turrettype,mrequest) (get_turretinfo(turrettype)).turret_func(mrequest) +#define TUR_NAME(turrettype) (get_turretinfo(turrettype)).turret_name + +float t_null(float dummy) { return 0; } + +CLASS(Turret, Object) + ATTRIB(Turret, m_id, int, 0) + + ATTRIB(Turret, turretid, int, 0) + /** short name */ + ATTRIB(Turret, netname, string, string_null) + /** human readable name */ + ATTRIB(Turret, turret_name, string, string_null) + /** t_... */ + ATTRIB(Turret, turret_func, float(float), t_null) + /** currently a copy of the model */ + ATTRIB(Turret, mdl, string, string_null) + /** full name of model */ + ATTRIB(Turret, model, string, string_null) + /** full name of tur_head model */ + ATTRIB(Turret, head_model, string, string_null) + /** TODO: deprecate! */ + ATTRIB(Turret, cvar_basename, string, string_null) + + ATTRIB(Turret, spawnflags, int, 0) + /** turret hitbox size */ + ATTRIB(Turret, mins, vector, '-0 -0 -0') + /** turret hitbox size */ + ATTRIB(Turret, maxs, vector, '0 0 0') + + METHOD(Turret, display, void(entity this, void(string name, string icon) returns)) { + returns(this.turret_name, string_null); + } + +ENDCLASS(Turret) + +#endif diff --git a/qcsrc/common/turrets/turret/ewheel.qc b/qcsrc/common/turrets/turret/ewheel.qc new file mode 100644 index 000000000..a27860bc4 --- /dev/null +++ b/qcsrc/common/turrets/turret/ewheel.qc @@ -0,0 +1,312 @@ +#ifndef TUR_EWHEEL_H +#define TUR_EWHEEL_H +REGISTER_TURRET( +/* TUR_##id */ EWHEEL, +/* function */ t_ewheel, +/* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM, +/* mins,maxs */ '-32 -32 0', '32 32 48', +/* model */ "ewheel-base2.md3", +/* head_model */ "ewheel-gun1.md3", +/* netname */ "ewheel", +/* fullname */ _("eWheel Turret") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +float autocvar_g_turrets_unit_ewheel_speed_fast; +float autocvar_g_turrets_unit_ewheel_speed_slow; +float autocvar_g_turrets_unit_ewheel_speed_slower; +float autocvar_g_turrets_unit_ewheel_speed_stop; +float autocvar_g_turrets_unit_ewheel_turnrate; + +const float ewheel_anim_stop = 0; +const float ewheel_anim_fwd_slow = 1; +const float ewheel_anim_fwd_fast = 2; +const float ewheel_anim_bck_slow = 3; +const float ewheel_anim_bck_fast = 4; + +//#define EWHEEL_FANCYPATH +void ewheel_move_path() +{SELFPARAM(); +#ifdef EWHEEL_FANCYPATH + // Are we close enougth to a path node to switch to the next? + if (vlen(self.origin - self.pathcurrent.origin) < 64) + if (self.pathcurrent.path_next == world) + { + // Path endpoint reached + pathlib_deletepath(self.pathcurrent.owner); + self.pathcurrent = world; + + if (self.pathgoal) + { + if (self.pathgoal.use) + self.pathgoal.use(); + + if (self.pathgoal.enemy) + { + self.pathcurrent = pathlib_astar(self.pathgoal.origin,self.pathgoal.enemy.origin); + self.pathgoal = self.pathgoal.enemy; + } + } + else + self.pathgoal = world; + } + else + self.pathcurrent = self.pathcurrent.path_next; + +#else + if (vlen(self.origin - self.pathcurrent.origin) < 64) + self.pathcurrent = self.pathcurrent.enemy; +#endif + + if (self.pathcurrent) + { + + self.moveto = self.pathcurrent.origin; + self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); + + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4); + } +} + +void ewheel_move_enemy() +{SELFPARAM(); + float newframe; + + self.steerto = steerlib_arrive(self.enemy.origin,self.target_range_optimal); + + self.moveto = self.origin + self.steerto * 128; + + if (self.tur_dist_enemy > self.target_range_optimal) + { + if ( self.tur_head.spawnshieldtime < 1 ) + { + newframe = ewheel_anim_fwd_fast; + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4); + } + else if (self.tur_head.spawnshieldtime < 2) + { + + newframe = ewheel_anim_fwd_slow; + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4); + } + else + { + newframe = ewheel_anim_fwd_slow; + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slower), 0.4); + } + } + else if (self.tur_dist_enemy < self.target_range_optimal * 0.5) + { + newframe = ewheel_anim_bck_slow; + movelib_move_simple(v_forward * -1, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4); + } + else + { + newframe = ewheel_anim_stop; + movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop)); + } + + turrets_setframe(newframe, false); +} + +void ewheel_move_idle() +{SELFPARAM(); + if(self.frame != 0) + { + self.SendFlags |= TNSF_ANIM; + self.anim_start_time = time; + } + + self.frame = 0; + if (vlen(self.velocity)) + movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop)); +} + +void spawnfunc_turret_ewheel() { SELFPARAM(); if(!turret_initialize(TUR_EWHEEL.m_id)) remove(self); } + +float t_ewheel(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + float i; + entity _mis; + + for (i = 0; i < 1; ++i) + { + turret_do_updates(self); + + _mis = turret_projectile(SND(LASERGUN_FIRE), 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_BLASTER, TRUE, TRUE); + _mis.missile_flags = MIF_SPLASH; + + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + self.tur_head.frame += 2; + + if (self.tur_head.frame > 3) + self.tur_head.frame = 0; + } + + return true; + } + case TR_THINK: + { + float vz; + vector wish_angle, real_angle; + + vz = self.velocity_z; + + self.angles_x = anglemods(self.angles_x); + self.angles_y = anglemods(self.angles_y); + + fixedmakevectors(self.angles); + + wish_angle = normalize(self.steerto); + wish_angle = vectoangles(wish_angle); + real_angle = wish_angle - self.angles; + real_angle = shortangle_vxy(real_angle, self.tur_head.angles); + + self.tur_head.spawnshieldtime = fabs(real_angle_y); + real_angle_y = bound(-self.tur_head.aim_speed, real_angle_y, self.tur_head.aim_speed); + self.angles_y = (self.angles_y + real_angle_y); + + if(self.enemy) + ewheel_move_enemy(); + else if(self.pathcurrent) + ewheel_move_path(); + else + ewheel_move_idle(); + + self.velocity_z = vz; + + if(vlen(self.velocity)) + self.SendFlags |= TNSF_MOVE; + + return true; + } + case TR_DEATH: + { + self.velocity = '0 0 0'; + +#ifdef EWHEEL_FANCYPATH + if (self.pathcurrent) + pathlib_deletepath(self.pathcurrent.owner); +#endif + self.pathcurrent = world; + + return true; + } + case TR_SETUP: + { + entity e; + + if(self.movetype == MOVETYPE_WALK) + { + self.velocity = '0 0 0'; + self.enemy = world; + + setorigin(self, self.pos1); + + if (self.target != "") + { + e = find(world, targetname, self.target); + if (!e) + { + LOG_TRACE("Initital waypoint for ewheel does NOT exsist, fix your map!\n"); + self.target = ""; + } + + if (e.classname != "turret_checkpoint") + LOG_TRACE("Warning: not a turrret path\n"); + else + { + +#ifdef EWHEEL_FANCYPATH + self.pathcurrent = WALKER_PATH(self.origin,e.origin); + self.pathgoal = e; +#else + self.pathcurrent = e; +#endif + } + } + } + + self.iscreature = true; + self.teleportable = TELEPORT_NORMAL; + self.damagedbycontents = true; + self.movetype = MOVETYPE_WALK; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + self.idle_aim = '0 0 0'; + self.pos1 = self.origin; + self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; + self.frame = self.tur_head.frame = 1; + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + + // Convert from dgr / sec to dgr / tic + self.tur_head.aim_speed = (autocvar_g_turrets_unit_ewheel_turnrate); + self.tur_head.aim_speed = self.tur_head.aim_speed / (1 / self.ticrate); + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC + +void ewheel_draw() +{SELFPARAM(); + float dt; + + dt = time - self.move_time; + self.move_time = time; + if(dt <= 0) + return; + + fixedmakevectors(self.angles); + setorigin(self, self.origin + self.velocity * dt); + self.tur_head.angles += dt * self.tur_head.move_avelocity; + self.angles_y = self.move_angles_y; + + if (self.health < 127) + if(random() < 0.05) + te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16); +} + +float t_ewheel(float req) +{SELFPARAM(); + switch(req) + { + case TR_SETUP: + { + self.gravity = 1; + self.movetype = MOVETYPE_BOUNCE; + self.move_movetype = MOVETYPE_BOUNCE; + self.move_origin = self.origin; + self.move_time = time; + self.draw = ewheel_draw; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/flac.qc b/qcsrc/common/turrets/turret/flac.qc new file mode 100644 index 000000000..aacefd164 --- /dev/null +++ b/qcsrc/common/turrets/turret/flac.qc @@ -0,0 +1,104 @@ +#ifndef TUR_FLAC_H +#define TUR_FLAC_H +REGISTER_TURRET( +/* TUR_##id */ FLAC, +/* function */ t_flac, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_MISSILE, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "flac.md3", +/* netname */ "flac", +/* fullname */ _("FLAC Cannon") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +void turret_flac_projectile_think_explode() +{SELFPARAM(); + if(self.enemy != world) + if(vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 3) + setorigin(self,self.enemy.origin + randomvec() * self.owner.shot_radius); + +#ifdef TURRET_DEBUG + float d; + d = RadiusDamage (self, self.owner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world); + self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; + self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg; +#else + RadiusDamage (self, self.realowner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world); +#endif + remove(self); +} + +void spawnfunc_turret_flac() { SELFPARAM(); if(!turret_initialize(TUR_FLAC.m_id)) remove(self); } + +float t_flac(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + entity proj; + + turret_tag_fire_update(); + + proj = turret_projectile(SND(HAGAR_FIRE), 5, 0, DEATH_TURRET_FLAC, PROJECTILE_HAGAR, TRUE, TRUE); + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + proj.think = turret_flac_projectile_think_explode; + proj.nextthink = time + self.tur_impacttime + (random() * 0.01 - random() * 0.01); + proj.missile_flags = MIF_SPLASH | MIF_PROXY; + + self.tur_head.frame = self.tur_head.frame + 1; + if (self.tur_head.frame >= 4) + self.tur_head.frame = 0; + + return true; + } + case TR_THINK: + { + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.target_select_flags |= TFL_TARGETSELECT_NOTURRETS | TFL_TARGETSELECT_MISSILESONLY; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_flac(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/fusionreactor.qc b/qcsrc/common/turrets/turret/fusionreactor.qc new file mode 100644 index 000000000..7d2f4f0b6 --- /dev/null +++ b/qcsrc/common/turrets/turret/fusionreactor.qc @@ -0,0 +1,117 @@ +#ifndef TUR_FUSIONREACTOR_H +#define TUR_FUSIONREACTOR_H +REGISTER_TURRET( +/* TUR_##id */ FUSIONREACTOR, +/* function */ t_fusionreactor, +/* spawnflags */ TUR_FLAG_SUPPORT | TUR_FLAG_AMMOSOURCE, +/* mins,maxs */ '-34 -34 0', '34 34 90', +/* model */ "base.md3", +/* head_model */ "reactor.md3", +/* netname */ "fusionreactor", +/* fullname */ _("Fusion Reactor") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +bool turret_fusionreactor_firecheck() +{SELFPARAM(); + if (self.attack_finished_single > time) + return false; + + if (self.enemy.deadflag != DEAD_NO) + return false; + + if (self.enemy == world) + return false; + + if (self.ammo < self.shot_dmg) + return false; + + if (self.enemy.ammo >= self.enemy.ammo_max) + return false; + + if (vlen(self.enemy.origin - self.origin) > self.target_range) + return false; + + if(self.team != self.enemy.team) + return false; + + if(!(self.enemy.ammo_flags & TFL_AMMO_ENERGY)) + return false; + + return true; +} + +void spawnfunc_turret_fusionreactor() { SELFPARAM(); if(!turret_initialize(TUR_FUSIONREACTOR.m_id)) remove(self); } + +float t_fusionreactor(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + vector fl_org; + + self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max); + fl_org = 0.5 * (self.enemy.absmin + self.enemy.absmax); + te_smallflash(fl_org); + + return true; + } + case TR_THINK: + { + self.tur_head.avelocity = '0 250 0' * (self.ammo / self.ammo_max); + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE; + self.target_select_flags = TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_OWNTEAM | TFL_TARGETSELECT_RANGELIMITS; + self.firecheck_flags = TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_AMMO_OTHER | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_DEAD; + self.shoot_flags = TFL_SHOOT_HITALLVALID; + self.aim_flags = TFL_AIM_NO; + self.track_flags = TFL_TRACK_NO; + + self.tur_head.scale = 0.75; + self.tur_head.avelocity = '0 50 0'; + + self.turret_firecheckfunc = turret_fusionreactor_firecheck; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_fusionreactor(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/hellion.qc b/qcsrc/common/turrets/turret/hellion.qc new file mode 100644 index 000000000..9efae2d96 --- /dev/null +++ b/qcsrc/common/turrets/turret/hellion.qc @@ -0,0 +1,161 @@ +#ifndef TUR_HELLION_H +#define TUR_HELLION_H +REGISTER_TURRET( +/* TUR_##id */ HELLION, +/* function */ t_hellion, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "hellion.md3", +/* netname */ "hellion", +/* fullname */ _("Hellion Missile Turret") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +float autocvar_g_turrets_unit_hellion_shot_speed_gain; +float autocvar_g_turrets_unit_hellion_shot_speed_max; + +void turret_hellion_missile_think() +{SELFPARAM(); + vector olddir,newdir; + vector pre_pos; + float itime; + + self.nextthink = time + 0.05; + + olddir = normalize(self.velocity); + + if(self.max_health < time) + turret_projectile_explode(); + + // Enemy dead? just keep on the current heading then. + if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO)) + { + + // Make sure we dont return to tracking a respawned player + self.enemy = world; + + // Turn model + self.angles = vectoangles(self.velocity); + + if ( (vlen(self.origin - self.owner.origin)) > (self.owner.shot_radius * 5) ) + turret_projectile_explode(); + + // Accelerate + self.velocity = olddir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max)); + + UpdateCSQCProjectile(self); + + return; + } + + // Enemy in range? + if (vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 0.2) + turret_projectile_explode(); + + // Predict enemy position + itime = vlen(self.enemy.origin - self.origin) / vlen(self.velocity); + pre_pos = self.enemy.origin + self.enemy.velocity * itime; + + pre_pos = (pre_pos + self.enemy.origin) * 0.5; + + // Find out the direction to that place + newdir = normalize(pre_pos - self.origin); + + // Turn + newdir = normalize(olddir + newdir * 0.35); + + // Turn model + self.angles = vectoangles(self.velocity); + + // Accelerate + self.velocity = newdir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max)); + + if (itime < 0.05) + self.think = turret_projectile_explode; + + UpdateCSQCProjectile(self); +} + +void spawnfunc_turret_hellion() { SELFPARAM(); if(!turret_initialize(TUR_HELLION.m_id)) remove(self); } + +float t_hellion(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + entity missile; + + if(self.tur_head.frame != 0) + self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire")); + else + self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire2")); + + missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_HELLION, PROJECTILE_ROCKET, FALSE, FALSE); + te_explosion (missile.origin); + missile.think = turret_hellion_missile_think; + missile.nextthink = time; + missile.flags = FL_PROJECTILE; + missile.max_health = time + 9; + missile.tur_aimpos = randomvec() * 128; + missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT; + self.tur_head.frame += 1; + + return true; + } + case TR_THINK: + { + if (self.tur_head.frame != 0) + self.tur_head.frame += 1; + + if (self.tur_head.frame >= 7) + self.tur_head.frame = 0; + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.aim_flags = TFL_AIM_SIMPLE; + self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK ; + self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF | TFL_FIRECHECK_AMMO_OWN; + self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_hellion(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/hk.qc b/qcsrc/common/turrets/turret/hk.qc new file mode 100644 index 000000000..8ec6f16bc --- /dev/null +++ b/qcsrc/common/turrets/turret/hk.qc @@ -0,0 +1,362 @@ +#ifndef TUR_HK_H +#define TUR_HK_H +REGISTER_TURRET( +/* TUR_##id */ HK, +/* function */ t_hk, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER | TUR_FLAG_RECIEVETARGETS, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "hk.md3", +/* netname */ "hk", +/* fullname */ _("Hunter-Killer Turret") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +float autocvar_g_turrets_unit_hk_shot_speed; +float autocvar_g_turrets_unit_hk_shot_speed_accel; +float autocvar_g_turrets_unit_hk_shot_speed_accel2; +float autocvar_g_turrets_unit_hk_shot_speed_decel; +float autocvar_g_turrets_unit_hk_shot_speed_max; +float autocvar_g_turrets_unit_hk_shot_speed_turnrate; + +//#define TURRET_DEBUG_HK + +#ifdef TURRET_DEBUG_HK +.float atime; +#endif + +float hk_is_valid_target(entity e_target) +{SELFPARAM(); + if (e_target == world) + return 0; + + // If only this was used more.. + if (e_target.flags & FL_NOTARGET) + return 0; + + // Cant touch this + if ((e_target.takedamage == DAMAGE_NO) || (e_target.health < 0)) + return 0; + + // player + if (IS_CLIENT(e_target)) + { + if (self.owner.target_select_playerbias < 0) + return 0; + + if (e_target.deadflag != DEAD_NO) + return 0; + } + + // Missile + if ((e_target.flags & FL_PROJECTILE) && (self.owner.target_select_missilebias < 0)) + return 0; + + // Team check + if ((e_target.team == self.owner.team) || (self.owner.team == e_target.owner.team)) + return 0; + + return 1; +} + +void turret_hk_missile_think() +{SELFPARAM(); + vector vu, vd, vf, vl, vr, ve; // Vector (direction) + float fu, fd, ff, fl, fr, fe; // Fraction to solid + vector olddir,wishdir,newdir; // Final direction + float lt_for; // Length of Trace FORwrad + float lt_seek; // Length of Trace SEEK (left, right, up down) + float pt_seek; // Pitch of Trace SEEK (How mutch to angele left, right up, down trace towards v_forward) + vector pre_pos; + float myspeed; + entity e; + float ad,edist; + + self.nextthink = time + self.ticrate; + + //if (self.cnt < time) + // turret_hk_missile_explode(); + + if (self.enemy.deadflag != DEAD_NO) + self.enemy = world; + + // Pick the closest valid target. + if (!self.enemy) + { + e = findradius(self.origin, 5000); + while (e) + { + if (hk_is_valid_target(e)) + { + if (!self.enemy) + self.enemy = e; + else + if (vlen(self.origin - e.origin) < vlen(self.origin - self.enemy.origin)) + self.enemy = e; + } + e = e.chain; + } + } + + self.angles = vectoangles(self.velocity); + self.angles_x = self.angles_x * -1; + makevectors(self.angles); + self.angles_x = self.angles_x * -1; + + if (self.enemy) + { + edist = vlen(self.origin - self.enemy.origin); + // Close enougth to do decent damage? + if ( edist <= (self.owner.shot_radius * 0.25) ) + { + turret_projectile_explode(); + return; + } + + // Get data on enemy position + pre_pos = self.enemy.origin + + self.enemy.velocity * + min((vlen(self.enemy.origin - self.origin) / vlen(self.velocity)),0.5); + + traceline(self.origin, pre_pos,true,self.enemy); + ve = normalize(pre_pos - self.origin); + fe = trace_fraction; + + } + else + { + edist = 0; + ve = '0 0 0'; + fe = 0; + } + + if ((fe != 1) || (self.enemy == world) || (edist > 1000)) + { + myspeed = vlen(self.velocity); + + lt_for = myspeed * 3; + lt_seek = myspeed * 2.95; + + // Trace forward + traceline(self.origin, self.origin + v_forward * lt_for,false,self); + vf = trace_endpos; + ff = trace_fraction; + + // Find angular offset + ad = vlen(vectoangles(normalize(self.enemy.origin - self.origin)) - self.angles); + + // To close to something, Slow down! + if ( ((ff < 0.7) || (ad > 4)) && (myspeed > (autocvar_g_turrets_unit_hk_shot_speed)) ) + myspeed = max(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_decel), (autocvar_g_turrets_unit_hk_shot_speed)); + + // Failry clear, accelerate. + if ( (ff > 0.7) && (myspeed < (autocvar_g_turrets_unit_hk_shot_speed_max)) ) + myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel), (autocvar_g_turrets_unit_hk_shot_speed_max)); + + // Setup trace pitch + pt_seek = 1 - ff; + pt_seek = bound(0.15,pt_seek,0.8); + if (ff < 0.5) pt_seek = 1; + + // Trace left + traceline(self.origin, self.origin + (-1 * (v_right * pt_seek) + (v_forward * ff)) * lt_seek,false,self); + vl = trace_endpos; + fl = trace_fraction; + + // Trace right + traceline(self.origin, self.origin + ((v_right * pt_seek) + (v_forward * ff)) * lt_seek ,false,self); + vr = trace_endpos; + fr = trace_fraction; + + // Trace up + traceline(self.origin, self.origin + ((v_up * pt_seek) + (v_forward * ff)) * lt_seek ,false,self); + vu = trace_endpos; + fu = trace_fraction; + + // Trace down + traceline(self.origin, self.origin + (-1 * (v_up * pt_seek) + (v_forward * ff)) * lt_seek ,false,self); + vd = trace_endpos; + fd = trace_fraction; + + vl = normalize(vl - self.origin); + vr = normalize(vr - self.origin); + vu = normalize(vu - self.origin); + vd = normalize(vd - self.origin); + + // Panic tresh passed, find a single direction and turn as hard as we can + if (pt_seek == 1) + { + wishdir = v_right; + if (fl > fr) wishdir = -1 * v_right; + if (fu > fl) wishdir = v_up; + if (fd > fu) wishdir = -1 * v_up; + } + else + { + // Normalize our trace vectors to make a smooth path + wishdir = normalize( (vl * fl) + (vr * fr) + (vu * fu) + (vd * fd) ); + } + + if (self.enemy) + { + if (fe < 0.1) fe = 0.1; // Make sure we always try to move sligtly towards our target + wishdir = (wishdir * (1 - fe)) + (ve * fe); + } + } + else + { + // Got a clear path to target, speed up fast (if not at full speed) and go straight for it. + myspeed = vlen(self.velocity); + if (myspeed < (autocvar_g_turrets_unit_hk_shot_speed_max)) + myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel2),(autocvar_g_turrets_unit_hk_shot_speed_max)); + + wishdir = ve; + } + + if ((myspeed > (autocvar_g_turrets_unit_hk_shot_speed)) && (self.cnt > time)) + myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel2),(autocvar_g_turrets_unit_hk_shot_speed_max)); + + // Ranoutagazfish? + if (self.cnt < time) + { + self.cnt = time + 0.25; + self.nextthink = 0; + self.movetype = MOVETYPE_BOUNCE; + return; + } + + // Calculate new heading + olddir = normalize(self.velocity); + newdir = normalize(olddir + wishdir * (autocvar_g_turrets_unit_hk_shot_speed_turnrate)); + + // Set heading & speed + self.velocity = newdir * myspeed; + + // Align model with new heading + self.angles = vectoangles(self.velocity); + + +#ifdef TURRET_DEBUG_HK + //if(self.atime < time) { + if ((fe <= 0.99)||(edist > 1000)) + { + te_lightning2(world,self.origin, self.origin + vr * lt_seek); + te_lightning2(world,self.origin, self.origin + vl * lt_seek); + te_lightning2(world,self.origin, self.origin + vu * lt_seek); + te_lightning2(world,self.origin, self.origin + vd * lt_seek); + te_lightning2(world,self.origin, vf); + } + else + { + te_lightning2(world,self.origin, self.enemy.origin); + } + bprint("Speed: ", ftos(rint(myspeed)), "\n"); + bprint("Trace to solid: ", ftos(rint(ff * 100)), "%\n"); + bprint("Trace to target:", ftos(rint(fe * 100)), "%\n"); + self.atime = time + 0.2; + //} +#endif + + UpdateCSQCProjectile(self); +} + +float turret_hk_addtarget(entity e_target,entity e_sender) +{SELFPARAM(); + if (e_target) + { + if (turret_validate_target(self,e_target,self.target_validate_flags) > 0) + { + self.enemy = e_target; + return 1; + } + } + + return 0; +} + +void spawnfunc_turret_hk() { SELFPARAM(); if(!turret_initialize(TUR_HK.m_id)) remove(self); } + +float t_hk(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + entity missile; + + missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_HK, PROJECTILE_ROCKET, FALSE, FALSE); + te_explosion (missile.origin); + + missile.think = turret_hk_missile_think; + missile.nextthink = time + 0.25; + missile.movetype = MOVETYPE_BOUNCEMISSILE; + missile.velocity = self.tur_shotdir_updated * (self.shot_speed * 0.75); + missile.angles = vectoangles(missile.velocity); + missile.cnt = time + 30; + missile.ticrate = max(autocvar_sys_ticrate, 0.05); + missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_AI; + + if (self.tur_head.frame == 0) + self.tur_head.frame = self.tur_head.frame + 1; + + return true; + } + case TR_THINK: + { + if (self.tur_head.frame != 0) + self.tur_head.frame = self.tur_head.frame + 1; + + if (self.tur_head.frame > 5) + self.tur_head.frame = 0; + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + self.aim_flags = TFL_AIM_SIMPLE; + self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF; + self.shoot_flags = TFL_SHOOT_CLEARTARGET; + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK; + + self.turret_addtarget = turret_hk_addtarget; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_hk(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/machinegun.qc b/qcsrc/common/turrets/turret/machinegun.qc new file mode 100644 index 000000000..48a200cd7 --- /dev/null +++ b/qcsrc/common/turrets/turret/machinegun.qc @@ -0,0 +1,81 @@ +#ifndef TUR_MACHINEGUN_H +#define TUR_MACHINEGUN_H +REGISTER_TURRET( +/* TUR_##id */ MACHINEGUN, +/* function */ t_machinegun, +/* spawnflags */ TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "machinegun.md3", +/* netname */ "machinegun", +/* fullname */ _("Machinegun Turret") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +void spawnfunc_turret_machinegun() { SELFPARAM(); if(!turret_initialize(TUR_MACHINEGUN.m_id)) remove(self); } + +void W_MachineGun_MuzzleFlash(void); + +float t_machinegun(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_MACHINEGUN, 0); + + W_MachineGun_MuzzleFlash(); + setattachment(self.muzzle_flash, self.tur_head, "tag_fire"); + + return true; + } + case TR_THINK: + { + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + self.turret_flags |= TUR_FLAG_HITSCAN; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_machinegun(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/mlrs.qc b/qcsrc/common/turrets/turret/mlrs.qc new file mode 100644 index 000000000..fe3775bd1 --- /dev/null +++ b/qcsrc/common/turrets/turret/mlrs.qc @@ -0,0 +1,91 @@ +#ifndef TUR_MLRS_H +#define TUR_MLRS_H +REGISTER_TURRET( +/* TUR_##id */ MLRS, +/* function */ t_mlrs, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "mlrs.md3", +/* netname */ "mlrs", +/* fullname */ _("MLRS Turret") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +void spawnfunc_turret_mlrs() { SELFPARAM(); if(!turret_initialize(TUR_MLRS.m_id)) remove(self); } + +float t_mlrs(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + entity missile; + + turret_tag_fire_update(); + missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_MLRS, PROJECTILE_ROCKET, TRUE, TRUE); + missile.nextthink = time + max(self.tur_impacttime,(self.shot_radius * 2) / self.shot_speed); + missile.missile_flags = MIF_SPLASH; + te_explosion (missile.origin); + + return true; + } + case TR_THINK: + { + // 0 = full, 6 = empty + self.tur_head.frame = bound(0, 6 - floor(0.1 + self.ammo / self.shot_dmg), 6); + if(self.tur_head.frame < 0) + { + LOG_TRACE("ammo:",ftos(self.ammo),"\n"); + LOG_TRACE("shot_dmg:",ftos(self.shot_dmg),"\n"); + } + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.shoot_flags |= TFL_SHOOT_VOLLYALWAYS; + self.volly_counter = self.shot_volly; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_mlrs(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/phaser.qc b/qcsrc/common/turrets/turret/phaser.qc new file mode 100644 index 000000000..9e162495b --- /dev/null +++ b/qcsrc/common/turrets/turret/phaser.qc @@ -0,0 +1,170 @@ +#ifndef TUR_PHASER_H +#define TUR_PHASER_H +REGISTER_TURRET( +/* TUR_##id */ PHASER, +/* function */ t_phaser, +/* spawnflags */ TUR_FLAG_SNIPER | TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "phaser.md3", +/* netname */ "phaser", +/* fullname */ _("Phaser Cannon") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +.float fireflag; + +float turret_phaser_firecheck() +{SELFPARAM(); + if (self.fireflag != 0) return 0; + return turret_firecheck(); +} + +void beam_think() +{SELFPARAM(); + if ((time > self.cnt) || (self.owner.deadflag != DEAD_NO)) + { + self.owner.attack_finished_single = time + self.owner.shot_refire; + self.owner.fireflag = 2; + self.owner.tur_head.frame = 10; + sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); + remove(self); + return; + } + + turret_do_updates(self.owner); + + if (time - self.shot_spread > 0) + { + self.shot_spread = time + 2; + sound (self, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM); + } + + + self.nextthink = time + self.ticrate; + + self.owner.attack_finished_single = time + frametime; + setself(self.owner); + FireImoBeam ( self.tur_shotorg, + self.tur_shotorg + self.tur_shotdir_updated * self.target_range, + '-1 -1 -1' * self.shot_radius, + '1 1 1' * self.shot_radius, + self.shot_force, + this.shot_dmg, + 0.75, + DEATH_TURRET_PHASER); + setself(this); + self.scale = vlen(self.owner.tur_shotorg - trace_endpos) / 256; + +} + +void spawnfunc_turret_phaser() { SELFPARAM(); if(!turret_initialize(TUR_PHASER.m_id)) remove(self); } + +float t_phaser(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + entity beam; + + beam = spawn(); + beam.ticrate = 0.1; //autocvar_sys_ticrate; + setmodel(beam, MDL_TUR_PHASER_BEAM); + beam.effects = EF_LOWPRECISION; + beam.solid = SOLID_NOT; + beam.think = beam_think; + beam.cnt = time + self.shot_speed; + beam.shot_spread = time + 2; + beam.nextthink = time; + beam.owner = self; + beam.shot_dmg = self.shot_dmg / (self.shot_speed / beam.ticrate); + beam.scale = self.target_range / 256; + beam.movetype = MOVETYPE_NONE; + beam.enemy = self.enemy; + beam.bot_dodge = true; + beam.bot_dodgerating = beam.shot_dmg; + sound (beam, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM); + self.fireflag = 1; + + beam.attack_finished_single = self.attack_finished_single; + self.attack_finished_single = time; // + autocvar_sys_ticrate; + + setattachment(beam,self.tur_head,"tag_fire"); + + soundat (self, trace_endpos, CH_SHOTS, SND(NEXIMPACT), VOL_BASE, ATTEN_NORM); + + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; + + return true; + } + case TR_THINK: + { + if (self.tur_head.frame != 0) + { + if (self.fireflag == 1) + { + if (self.tur_head.frame == 10) + self.tur_head.frame = 1; + else + self.tur_head.frame = self.tur_head.frame +1; + } + else if (self.fireflag == 2 ) + { + self.tur_head.frame = self.tur_head.frame +1; + if (self.tur_head.frame == 15) + { + self.tur_head.frame = 0; + self.fireflag = 0; + } + } + } + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.aim_flags = TFL_AIM_LEAD; + + self.turret_firecheckfunc = turret_phaser_firecheck; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_phaser(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/plasma.qc b/qcsrc/common/turrets/turret/plasma.qc new file mode 100644 index 000000000..0cfe13ca6 --- /dev/null +++ b/qcsrc/common/turrets/turret/plasma.qc @@ -0,0 +1,107 @@ +#ifndef TUR_PLASMA_H +#define TUR_PLASMA_H +REGISTER_TURRET( +/* TUR_##id */ PLASMA, +/* function */ t_plasma, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "plasma.md3", +/* netname */ "plasma", +/* fullname */ _("Plasma Cannon") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +void spawnfunc_turret_plasma() { SELFPARAM(); if(!turret_initialize(TUR_PLASMA.m_id)) remove(self); } + +float t_plasma(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + if(g_instagib) + { + float flying; + flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last + + FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); + + Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + // teamcolor / hit beam effect + vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum(EFFECT_VAPORIZER(self.team)), self.tur_shotorg, v); + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; + } + else + { + entity missile = turret_projectile(SND(HAGAR_FIRE), 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); + missile.missile_flags = MIF_SPLASH; + + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; + } + + return true; + } + case TR_THINK: + { + if (self.tur_head.frame != 0) + self.tur_head.frame = self.tur_head.frame + 1; + + if (self.tur_head.frame > 5) + self.tur_head.frame = 0; + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.firecheck_flags |= TFL_FIRECHECK_AFF; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; + + turret_do_updates(self); + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_plasma(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/plasma_dual.qc b/qcsrc/common/turrets/turret/plasma_dual.qc new file mode 100644 index 000000000..74713eaa9 --- /dev/null +++ b/qcsrc/common/turrets/turret/plasma_dual.qc @@ -0,0 +1,134 @@ +#ifndef TUR_PLASMA_DUAL_H +#define TUR_PLASMA_DUAL_H +REGISTER_TURRET( +/* TUR_##id */ PLASMA_DUAL, +/* function */ t_plasma_dual, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "plasmad.md3", +/* netname */ "plasma_dual", +/* fullname */ _("Dual Plasma Cannon") +); +#endif + +#ifdef IMPLEMENTATION + +#include "../../weapons/all.qh" + +CLASS(PlasmaDualAttack, PortoLaunch) +/* flags */ ATTRIB(PlasmaDualAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(PlasmaDualAttack, impulse, int, 5); +/* refname */ ATTRIB(PlasmaDualAttack, netname, string, "plasmadual"); +/* wepname */ ATTRIB(PlasmaDualAttack, message, string, _("Dual plasma")); +ENDCLASS(PlasmaDualAttack) +REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack)); + +#ifdef SVQC + +float t_plasma_dual(float req); +METHOD(PlasmaDualAttack, wr_think, bool(entity thiswep)) { + SELFPARAM(); + if (self.BUTTON_ATCK) + if (weapon_prepareattack(0, WEP_CVAR_PRI(electro, refire))) { + W_SetupShot_Dir(self, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0); + self.tur_shotdir_updated = w_shotdir; + self.tur_shotorg = w_shotorg; + self.tur_head = self; + self.shot_speed = max(1, ((!self.shot_speed) ? 2500 : self.shot_speed)); + self.shot_spread = bound(0.0001, ((!self.shot_spread) ? 0.0125 : self.shot_spread), 500); + t_plasma_dual(TR_ATTACK); + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + return true; +} + +void spawnfunc_turret_plasma_dual() { SELFPARAM(); if(!turret_initialize(TUR_PLASMA_DUAL.m_id)) remove(self); } + +float t_plasma_dual(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + if(g_instagib) + { + float flying; + flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last + + FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); + + + Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + // teamcolor / hit beam effect + vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum(EFFECT_VAPORIZER(self.team)), self.tur_shotorg, v); + self.tur_head.frame += 1; + } + else + { + entity missile = turret_projectile(SND(HAGAR_FIRE), 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); + missile.missile_flags = MIF_SPLASH; + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + self.tur_head.frame += 1; + } + + return true; + } + case TR_THINK: + { + if ((self.tur_head.frame != 0) && (self.tur_head.frame != 3)) + self.tur_head.frame = self.tur_head.frame + 1; + + if (self.tur_head.frame > 6) + self.tur_head.frame = 0; + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.firecheck_flags |= TFL_FIRECHECK_AFF; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; + + turret_do_updates(self); + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_plasma_dual(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/tesla.qc b/qcsrc/common/turrets/turret/tesla.qc new file mode 100644 index 000000000..66c675157 --- /dev/null +++ b/qcsrc/common/turrets/turret/tesla.qc @@ -0,0 +1,218 @@ +#ifndef TUR_TESLA_H +#define TUR_TESLA_H +REGISTER_TURRET( +/* TUR_##id */ TESLA, +/* function */ t_tesla, +/* spawnflags */ TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE, +/* mins,maxs */ '-60 -60 0', '60 60 128', +/* model */ "tesla_base.md3", +/* head_model */ "tesla_head.md3", +/* netname */ "tesla", +/* fullname */ _("Tesla Coil") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +entity toast(entity from, float range, float damage) +{SELFPARAM(); + entity e; + entity etarget = world; + float d,dd; + float r; + + dd = range + 1; + + e = findradius(from.origin,range); + while (e) + { + if ((e.railgunhit != 1) && (e != from)) + { + r = turret_validate_target(self,e,self.target_validate_flags); + if (r > 0) + { + traceline(from.origin,0.5 * (e.absmin + e.absmax),MOVE_WORLDONLY,from); + if (trace_fraction == 1.0) + { + d = vlen(e.origin - from.origin); + if (d < dd) + { + dd = d; + etarget = e; + } + } + } + } + e = e.chain; + } + + if (etarget) + { + te_csqc_lightningarc(from.origin,etarget.origin); + Damage(etarget, self, self, damage, DEATH_TURRET_TESLA, etarget.origin, '0 0 0'); + etarget.railgunhit = 1; + } + + return etarget; +} + +float turret_tesla_firecheck() +{SELFPARAM(); + // g_turrets_targetscan_maxdelay forces a target re-scan at least this often + float do_target_scan = 0; + + if((self.target_select_time + autocvar_g_turrets_targetscan_maxdelay) < time) + do_target_scan = 1; + + // Old target (if any) invalid? + if(self.target_validate_time < time) + if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0) + { + self.enemy = world; + self.target_validate_time = time + 0.5; + do_target_scan = 1; + } + + // But never more often then g_turrets_targetscan_mindelay! + if (self.target_select_time + autocvar_g_turrets_targetscan_mindelay > time) + do_target_scan = 0; + + if(do_target_scan) + { + self.enemy = turret_select_target(); + self.target_select_time = time; + } + + if(!turret_firecheck()) + return 0; + + if(self.enemy) + return 1; + + return 0; +} + +void spawnfunc_turret_tesla() { SELFPARAM(); if(!turret_initialize(TUR_TESLA.m_id)) remove(self); } + +float t_tesla(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + entity e, t; + float d, r, i; + + d = self.shot_dmg; + r = self.target_range; + e = spawn(); + setorigin(e,self.tur_shotorg); + + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + + t = toast(e,r,d); + remove(e); + + if (t == world) return true; + + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK; + + self.attack_finished_single = time + self.shot_refire; + for (i = 0; i < 10; ++i) + { + d *= 0.75; + r *= 0.85; + t = toast(t, r, d); + if (t == world) break; + + } + + e = findchainfloat(railgunhit, 1); + while (e) + { + e.railgunhit = 0; + e = e.chain; + } + + return true; + } + case TR_THINK: + { + if(!self.active) + { + self.tur_head.avelocity = '0 0 0'; + return true; + } + + if(self.ammo < self.shot_dmg) + { + self.tur_head.avelocity = '0 45 0' * (self.ammo / self.shot_dmg); + } + else + { + self.tur_head.avelocity = '0 180 0' * (self.ammo / self.shot_dmg); + + if(self.attack_finished_single > time) + return true; + + float f; + f = (self.ammo / self.ammo_max); + f = f * f; + if(f > random()) + if(random() < 0.1) + te_csqc_lightningarc(self.tur_shotorg,self.tur_shotorg + (randomvec() * 350)); + } + + return true; + } + case TR_DEATH: + { + return true; + } + case TR_SETUP: + { + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | + TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + + self.turret_firecheckfunc = turret_tesla_firecheck; + self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | + TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + + self.firecheck_flags = TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AMMO_OWN; + self.shoot_flags = TFL_SHOOT_CUSTOM; + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.aim_flags = TFL_AIM_NO; + self.track_flags = TFL_TRACK_NO; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float t_tesla(float req) +{ + switch(req) + { + case TR_SETUP: + { + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/turret/walker.qc b/qcsrc/common/turrets/turret/walker.qc new file mode 100644 index 000000000..82fb62238 --- /dev/null +++ b/qcsrc/common/turrets/turret/walker.qc @@ -0,0 +1,697 @@ +#ifndef TUR_WALKER_H +#define TUR_WALKER_H +REGISTER_TURRET( +/* TUR_##id */ WALKER, +/* function */ t_walker, +/* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE, +/* mins,maxs */ '-70 -70 0', '70 70 95', +/* model */ "walker_body.md3", +/* head_model */ "walker_head_minigun.md3", +/* netname */ "walker", +/* fullname */ _("Walker Turret") +); +#endif + +#ifdef IMPLEMENTATION +#ifdef SVQC +float autocvar_g_turrets_unit_walker_melee_damage; +float autocvar_g_turrets_unit_walker_melee_force; +float autocvar_g_turrets_unit_walker_melee_range; +float autocvar_g_turrets_unit_walker_rocket_damage; +float autocvar_g_turrets_unit_walker_rocket_radius; +float autocvar_g_turrets_unit_walker_rocket_force; +float autocvar_g_turrets_unit_walker_rocket_speed; +float autocvar_g_turrets_unit_walker_rocket_range; +float autocvar_g_turrets_unit_walker_rocket_range_min; +float autocvar_g_turrets_unit_walker_rocket_refire; +float autocvar_g_turrets_unit_walker_rocket_turnrate; +float autocvar_g_turrets_unit_walker_speed_stop; +float autocvar_g_turrets_unit_walker_speed_walk; +float autocvar_g_turrets_unit_walker_speed_run; +float autocvar_g_turrets_unit_walker_speed_jump; +float autocvar_g_turrets_unit_walker_speed_swim; +float autocvar_g_turrets_unit_walker_speed_roam; +float autocvar_g_turrets_unit_walker_turn; +float autocvar_g_turrets_unit_walker_turn_walk; +float autocvar_g_turrets_unit_walker_turn_strafe; +float autocvar_g_turrets_unit_walker_turn_swim; +float autocvar_g_turrets_unit_walker_turn_run; + +#define ANIM_NO 0 +#define ANIM_TURN 1 +#define ANIM_WALK 2 +#define ANIM_RUN 3 +#define ANIM_STRAFE_L 4 +#define ANIM_STRAFE_R 5 +#define ANIM_JUMP 6 +#define ANIM_LAND 7 +#define ANIM_PAIN 8 +#define ANIM_MELEE 9 +#define ANIM_SWIM 10 +#define ANIM_ROAM 11 + +.float animflag; +.float idletime; + +#define WALKER_PATH(s,e) pathlib_astar(s,e) + +float walker_firecheck() +{SELFPARAM(); + if (self.animflag == ANIM_MELEE) + return 0; + + return turret_firecheck(); +} + +void walker_melee_do_dmg() +{SELFPARAM(); + vector where; + entity e; + + makevectors(self.angles); + where = self.origin + v_forward * 128; + + e = findradius(where,32); + while (e) + { + if (turret_validate_target(self, e, self.target_validate_flags)) + if (e != self && e.owner != self) + Damage(e, self, self, (autocvar_g_turrets_unit_walker_melee_damage), DEATH_TURRET_WALK_MELEE, '0 0 0', v_forward * (autocvar_g_turrets_unit_walker_melee_force)); + + e = e.chain; + } +} + +void walker_setnoanim() +{SELFPARAM(); + turrets_setframe(ANIM_NO, false); + self.animflag = self.frame; +} +void walker_rocket_explode() +{SELFPARAM(); + RadiusDamage (self, self.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), self, world, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET, world); + remove (self); +} + +void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) +{SELFPARAM(); + self.health = self.health - damage; + self.velocity = self.velocity + vforce; + + if (self.health <= 0) + W_PrepareExplosionByDamage(self.owner, walker_rocket_explode); +} + +#define WALKER_ROCKET_MOVE movelib_move_simple(newdir, (autocvar_g_turrets_unit_walker_rocket_speed), (autocvar_g_turrets_unit_walker_rocket_turnrate)); UpdateCSQCProjectile(self) +void walker_rocket_loop(); +void walker_rocket_think() +{SELFPARAM(); + vector newdir; + float edist; + float itime; + float m_speed; + + self.nextthink = time; + + edist = vlen(self.enemy.origin - self.origin); + + // Simulate crude guidance + if (self.cnt < time) + { + if (edist < 1000) + self.tur_shotorg = randomvec() * min(edist, 64); + else + self.tur_shotorg = randomvec() * min(edist, 256); + + self.cnt = time + 0.5; + } + + if (edist < 128) + self.tur_shotorg = '0 0 0'; + + if (self.max_health < time) + { + self.think = walker_rocket_explode; + self.nextthink = time; + return; + } + + if (self.shot_dmg != 1337 && random() < 0.01) + { + walker_rocket_loop(); + return; + } + + m_speed = vlen(self.velocity); + + // Enemy dead? just keep on the current heading then. + if (self.enemy == world || self.enemy.deadflag != DEAD_NO) + self.enemy = world; + + if (self.enemy) + { + itime = max(edist / m_speed, 1); + newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg); + } + else + newdir = normalize(self.velocity); + + WALKER_ROCKET_MOVE; +} + +void walker_rocket_loop3() +{SELFPARAM(); + vector newdir; + self.nextthink = time; + + if (self.max_health < time) + { + self.think = walker_rocket_explode; + return; + } + + if (vlen(self.origin - self.tur_shotorg) < 100 ) + { + self.think = walker_rocket_think; + return; + } + + newdir = steerlib_pull(self.tur_shotorg); + WALKER_ROCKET_MOVE; + + self.angles = vectoangles(self.velocity); +} + +void walker_rocket_loop2() +{SELFPARAM(); + vector newdir; + + self.nextthink = time; + + if (self.max_health < time) + { + self.think = walker_rocket_explode; + return; + } + + if (vlen(self.origin - self.tur_shotorg) < 100 ) + { + self.tur_shotorg = self.origin - '0 0 200'; + self.think = walker_rocket_loop3; + return; + } + + newdir = steerlib_pull(self.tur_shotorg); + WALKER_ROCKET_MOVE; +} + +void walker_rocket_loop() +{SELFPARAM(); + self.nextthink = time; + self.tur_shotorg = self.origin + '0 0 300'; + self.think = walker_rocket_loop2; + self.shot_dmg = 1337; +} + +void walker_fire_rocket(vector org) +{SELFPARAM(); + entity rocket; + + fixedmakevectors(self.angles); + + te_explosion (org); + + rocket = spawn (); + setorigin(rocket, org); + + sound (self, CH_WEAPON_A, SND_HAGAR_FIRE, VOL_BASE, ATTEN_NORM); + setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot + + rocket.classname = "walker_rocket"; + rocket.owner = self; + rocket.bot_dodge = true; + rocket.bot_dodgerating = 50; + rocket.takedamage = DAMAGE_YES; + rocket.damageforcescale = 2; + rocket.health = 25; + rocket.tur_shotorg = randomvec() * 512; + rocket.cnt = time + 1; + rocket.enemy = self.enemy; + + if (random() < 0.01) + rocket.think = walker_rocket_loop; + else + rocket.think = walker_rocket_think; + + rocket.event_damage = walker_rocket_damage; + + rocket.nextthink = time; + rocket.movetype = MOVETYPE_FLY; + rocket.velocity = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * (autocvar_g_turrets_unit_walker_rocket_speed); + rocket.angles = vectoangles(rocket.velocity); + rocket.touch = walker_rocket_explode; + rocket.flags = FL_PROJECTILE; + rocket.solid = SOLID_BBOX; + rocket.max_health = time + 9; + rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT; + + CSQCProjectile(rocket, false, PROJECTILE_ROCKET, false); // no culling, has fly sound +} + +.vector enemy_last_loc; +.float enemy_last_time; +void walker_move_to(vector _target, float _dist) +{SELFPARAM(); + switch (self.waterlevel) + { + case WATERLEVEL_NONE: + if (_dist > 500) + self.animflag = ANIM_RUN; + else + self.animflag = ANIM_WALK; + case WATERLEVEL_WETFEET: + case WATERLEVEL_SWIMMING: + if (self.animflag != ANIM_SWIM) + self.animflag = ANIM_WALK; + else + self.animflag = ANIM_SWIM; + break; + case WATERLEVEL_SUBMERGED: + self.animflag = ANIM_SWIM; + } + + self.moveto = _target; + self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); + + if(self.enemy) + { + self.enemy_last_loc = _target; + self.enemy_last_time = time; + } +} + +//#define WALKER_FANCYPATHING + +void walker_move_path() +{SELFPARAM(); +#ifdef WALKER_FANCYPATHING + // Are we close enougth to a path node to switch to the next? + if (vlen(self.origin - self.pathcurrent.origin) < 64) + if (self.pathcurrent.path_next == world) + { + // Path endpoint reached + pathlib_deletepath(self.pathcurrent.owner); + self.pathcurrent = world; + + if (self.pathgoal) + { + if (self.pathgoal.use) + self.pathgoal.use(); + + if (self.pathgoal.enemy) + { + self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin); + self.pathgoal = self.pathgoal.enemy; + } + } + else + self.pathgoal = world; + } + else + self.pathcurrent = self.pathcurrent.path_next; + + self.moveto = self.pathcurrent.origin; + self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95); + walker_move_to(self.moveto, 0); + +#else + if (vlen(self.origin - self.pathcurrent.origin) < 64) + self.pathcurrent = self.pathcurrent.enemy; + + if(!self.pathcurrent) + return; + + self.moveto = self.pathcurrent.origin; + self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); + walker_move_to(self.moveto, 0); +#endif +} + +void spawnfunc_turret_walker() { SELFPARAM(); if(!turret_initialize(TUR_WALKER.m_id)) remove(self); } + +float t_walker(float req) +{SELFPARAM(); + switch(req) + { + case TR_ATTACK: + { + sound (self, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM); + fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_WALK_GUN, 0); + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + return true; + } + case TR_THINK: + { + fixedmakevectors(self.angles); + + if (self.spawnflags & TSF_NO_PATHBREAK && self.pathcurrent) + walker_move_path(); + else if (self.enemy == world) + { + if(self.pathcurrent) + walker_move_path(); + else + { + if(self.enemy_last_time != 0) + { + if(vlen(self.origin - self.enemy_last_loc) < 128 || time - self.enemy_last_time > 10) + self.enemy_last_time = 0; + else + walker_move_to(self.enemy_last_loc, 0); + } + else + { + if(self.animflag != ANIM_NO) + { + traceline(self.origin + '0 0 64', self.origin + '0 0 64' + v_forward * 128, MOVE_NORMAL, self); + + if(trace_fraction != 1.0) + self.tur_head.idletime = -1337; + else + { + traceline(trace_endpos, trace_endpos - '0 0 256', MOVE_NORMAL, self); + if(trace_fraction == 1.0) + self.tur_head.idletime = -1337; + } + + if(self.tur_head.idletime == -1337) + { + self.moveto = self.origin + randomvec() * 256; + self.tur_head.idletime = 0; + } + + self.moveto = self.moveto * 0.9 + ((self.origin + v_forward * 500) + randomvec() * 400) * 0.1; + self.moveto_z = self.origin_z + 64; + walker_move_to(self.moveto, 0); + } + + if(self.idletime < time) + { + if(random() < 0.5 || !(self.spawnflags & TSL_ROAM)) + { + self.idletime = time + 1 + random() * 5; + self.moveto = self.origin; + self.animflag = ANIM_NO; + } + else + { + self.animflag = ANIM_WALK; + self.idletime = time + 4 + random() * 2; + self.moveto = self.origin + randomvec() * 256; + self.tur_head.moveto = self.moveto; + self.tur_head.idletime = 0; + } + } + } + } + } + else + { + if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_melee_range) && self.animflag != ANIM_MELEE) + { + vector wish_angle; + + wish_angle = angleofs(self, self.enemy); + if (self.animflag != ANIM_SWIM) + if (fabs(wish_angle_y) < 15) + { + self.moveto = self.enemy.origin; + self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); + self.animflag = ANIM_MELEE; + } + } + else if (self.tur_head.attack_finished_single < time) + { + if(self.tur_head.shot_volly) + { + self.animflag = ANIM_NO; + + self.tur_head.shot_volly = self.tur_head.shot_volly -1; + if(self.tur_head.shot_volly == 0) + self.tur_head.attack_finished_single = time + (autocvar_g_turrets_unit_walker_rocket_refire); + else + self.tur_head.attack_finished_single = time + 0.2; + + if(self.tur_head.shot_volly > 1) + walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket01"))); + else + walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket02"))); + } + else + { + if (self.tur_dist_enemy > (autocvar_g_turrets_unit_walker_rocket_range_min)) + if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_rocket_range)) + self.tur_head.shot_volly = 4; + } + } + else + { + if (self.animflag != ANIM_MELEE) + walker_move_to(self.enemy.origin, self.tur_dist_enemy); + } + } + + { + vector real_angle; + float turny = 0, turnx = 0; + float vz; + + real_angle = vectoangles(self.steerto) - self.angles; + vz = self.velocity_z; + + switch (self.animflag) + { + case ANIM_NO: + movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop)); + break; + + case ANIM_TURN: + turny = (autocvar_g_turrets_unit_walker_turn); + movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop)); + break; + + case ANIM_WALK: + turny = (autocvar_g_turrets_unit_walker_turn_walk); + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_walk), 0.6); + break; + + case ANIM_RUN: + turny = (autocvar_g_turrets_unit_walker_turn_run); + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_run), 0.6); + break; + + case ANIM_STRAFE_L: + turny = (autocvar_g_turrets_unit_walker_turn_strafe); + movelib_move_simple(v_right * -1, (autocvar_g_turrets_unit_walker_speed_walk), 0.8); + break; + + case ANIM_STRAFE_R: + turny = (autocvar_g_turrets_unit_walker_turn_strafe); + movelib_move_simple(v_right, (autocvar_g_turrets_unit_walker_speed_walk), 0.8); + break; + + case ANIM_JUMP: + self.velocity += '0 0 1' * (autocvar_g_turrets_unit_walker_speed_jump); + break; + + case ANIM_LAND: + break; + + case ANIM_PAIN: + if(self.frame != ANIM_PAIN) + defer(0.25, walker_setnoanim); + + break; + + case ANIM_MELEE: + if(self.frame != ANIM_MELEE) + { + defer(0.41, walker_setnoanim); + defer(0.21, walker_melee_do_dmg); + } + + movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop)); + break; + + case ANIM_SWIM: + turny = (autocvar_g_turrets_unit_walker_turn_swim); + turnx = (autocvar_g_turrets_unit_walker_turn_swim); + + self.angles_x += bound(-10, shortangle_f(real_angle_x, self.angles_x), 10); + movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_swim), 0.3); + vz = self.velocity_z + sin(time * 4) * 8; + break; + + case ANIM_ROAM: + turny = (autocvar_g_turrets_unit_walker_turn_walk); + movelib_move_simple(v_forward ,(autocvar_g_turrets_unit_walker_speed_roam), 0.5); + break; + } + + if(turny) + { + turny = bound( turny * -1, shortangle_f(real_angle_y, self.angles_y), turny ); + self.angles_y += turny; + } + + if(turnx) + { + turnx = bound( turnx * -1, shortangle_f(real_angle_x, self.angles_x), turnx ); + self.angles_x += turnx; + } + + self.velocity_z = vz; + } + + + if(self.origin != self.oldorigin) + self.SendFlags |= TNSF_MOVE; + + self.oldorigin = self.origin; + turrets_setframe(self.animflag, false); + + return true; + } + case TR_DEATH: + { +#ifdef WALKER_FANCYPATHING + if (self.pathcurrent) + pathlib_deletepath(self.pathcurrent.owner); +#endif + self.pathcurrent = world; + + return true; + } + case TR_SETUP: + { + self.ticrate = 0.05; + + entity e; + + // Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn. + if(self.movetype == MOVETYPE_WALK) + { + if(self.pos1) + setorigin(self, self.pos1); + if(self.pos2) + self.angles = self.pos2; + } + + self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.aim_flags = TFL_AIM_LEAD; + self.turret_flags |= TUR_FLAG_HITSCAN; + + self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; + self.iscreature = true; + self.teleportable = TELEPORT_NORMAL; + self.damagedbycontents = true; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + if(self.movetype != MOVETYPE_WALK) + { + setorigin(self, self.origin); + tracebox(self.origin + '0 0 128', self.mins, self.maxs, self.origin - '0 0 10000', MOVE_NORMAL, self); + setorigin(self, trace_endpos + '0 0 4'); + self.pos1 = self.origin; + self.pos2 = self.angles; + } + self.movetype = MOVETYPE_WALK; + self.idle_aim = '0 0 0'; + self.turret_firecheckfunc = walker_firecheck; + + if (self.target != "") + { + e = find(world, targetname, self.target); + if (!e) + { + LOG_TRACE("Initital waypoint for walker does NOT exsist, fix your map!\n"); + self.target = ""; + } + + if (e.classname != "turret_checkpoint") + LOG_TRACE("Warning: not a turrret path\n"); + else + { +#ifdef WALKER_FANCYPATHING + self.pathcurrent = WALKER_PATH(self.origin, e.origin); + self.pathgoal = e; +#else + self.pathcurrent = e; +#endif + } + } + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC + +#include "../../../client/movelib.qh" + +void walker_draw() +{SELFPARAM(); + float dt; + + dt = time - self.move_time; + self.move_time = time; + if(dt <= 0) + return; + + fixedmakevectors(self.angles); + movelib_groundalign4point(300, 100, 0.25, 45); + setorigin(self, self.origin + self.velocity * dt); + self.tur_head.angles += dt * self.tur_head.move_avelocity; + self.angles_y = self.move_angles_y; + + if (self.health < 127) + if(random() < 0.15) + te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16); +} + +float t_walker(float req) +{SELFPARAM(); + switch(req) + { + case TR_SETUP: + { + self.gravity = 1; + self.movetype = MOVETYPE_BOUNCE; + self.move_movetype = MOVETYPE_BOUNCE; + self.move_origin = self.origin; + self.move_time = time; + self.draw = walker_draw; + + return true; + } + case TR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/ewheel.qc b/qcsrc/common/turrets/unit/ewheel.qc deleted file mode 100644 index cd111b258..000000000 --- a/qcsrc/common/turrets/unit/ewheel.qc +++ /dev/null @@ -1,309 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ EWHEEL, -/* function */ t_ewheel, -/* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM, -/* mins,maxs */ '-32 -32 0', '32 32 48', -/* model */ "ewheel-base2.md3", -/* head_model */ "ewheel-gun1.md3", -/* netname */ "ewheel", -/* fullname */ _("eWheel Turret") -); -#else -#ifdef SVQC -float autocvar_g_turrets_unit_ewheel_speed_fast; -float autocvar_g_turrets_unit_ewheel_speed_slow; -float autocvar_g_turrets_unit_ewheel_speed_slower; -float autocvar_g_turrets_unit_ewheel_speed_stop; -float autocvar_g_turrets_unit_ewheel_turnrate; - -const float ewheel_anim_stop = 0; -const float ewheel_anim_fwd_slow = 1; -const float ewheel_anim_fwd_fast = 2; -const float ewheel_anim_bck_slow = 3; -const float ewheel_anim_bck_fast = 4; - -//#define EWHEEL_FANCYPATH -void ewheel_move_path() -{SELFPARAM(); -#ifdef EWHEEL_FANCYPATH - // Are we close enougth to a path node to switch to the next? - if (vlen(self.origin - self.pathcurrent.origin) < 64) - if (self.pathcurrent.path_next == world) - { - // Path endpoint reached - pathlib_deletepath(self.pathcurrent.owner); - self.pathcurrent = world; - - if (self.pathgoal) - { - if (self.pathgoal.use) - self.pathgoal.use(); - - if (self.pathgoal.enemy) - { - self.pathcurrent = pathlib_astar(self.pathgoal.origin,self.pathgoal.enemy.origin); - self.pathgoal = self.pathgoal.enemy; - } - } - else - self.pathgoal = world; - } - else - self.pathcurrent = self.pathcurrent.path_next; - -#else - if (vlen(self.origin - self.pathcurrent.origin) < 64) - self.pathcurrent = self.pathcurrent.enemy; -#endif - - if (self.pathcurrent) - { - - self.moveto = self.pathcurrent.origin; - self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); - - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4); - } -} - -void ewheel_move_enemy() -{SELFPARAM(); - float newframe; - - self.steerto = steerlib_arrive(self.enemy.origin,self.target_range_optimal); - - self.moveto = self.origin + self.steerto * 128; - - if (self.tur_dist_enemy > self.target_range_optimal) - { - if ( self.tur_head.spawnshieldtime < 1 ) - { - newframe = ewheel_anim_fwd_fast; - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4); - } - else if (self.tur_head.spawnshieldtime < 2) - { - - newframe = ewheel_anim_fwd_slow; - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4); - } - else - { - newframe = ewheel_anim_fwd_slow; - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slower), 0.4); - } - } - else if (self.tur_dist_enemy < self.target_range_optimal * 0.5) - { - newframe = ewheel_anim_bck_slow; - movelib_move_simple(v_forward * -1, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4); - } - else - { - newframe = ewheel_anim_stop; - movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop)); - } - - turrets_setframe(newframe, false); -} - -void ewheel_move_idle() -{SELFPARAM(); - if(self.frame != 0) - { - self.SendFlags |= TNSF_ANIM; - self.anim_start_time = time; - } - - self.frame = 0; - if (vlen(self.velocity)) - movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop)); -} - -void spawnfunc_turret_ewheel() { SELFPARAM(); if(!turret_initialize(TUR_EWHEEL.m_id)) remove(self); } - -float t_ewheel(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - float i; - entity _mis; - - for (i = 0; i < 1; ++i) - { - turret_do_updates(self); - - _mis = turret_projectile(SND(LASERGUN_FIRE), 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_BLASTER, TRUE, TRUE); - _mis.missile_flags = MIF_SPLASH; - - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - - self.tur_head.frame += 2; - - if (self.tur_head.frame > 3) - self.tur_head.frame = 0; - } - - return true; - } - case TR_THINK: - { - float vz; - vector wish_angle, real_angle; - - vz = self.velocity_z; - - self.angles_x = anglemods(self.angles_x); - self.angles_y = anglemods(self.angles_y); - - fixedmakevectors(self.angles); - - wish_angle = normalize(self.steerto); - wish_angle = vectoangles(wish_angle); - real_angle = wish_angle - self.angles; - real_angle = shortangle_vxy(real_angle, self.tur_head.angles); - - self.tur_head.spawnshieldtime = fabs(real_angle_y); - real_angle_y = bound(-self.tur_head.aim_speed, real_angle_y, self.tur_head.aim_speed); - self.angles_y = (self.angles_y + real_angle_y); - - if(self.enemy) - ewheel_move_enemy(); - else if(self.pathcurrent) - ewheel_move_path(); - else - ewheel_move_idle(); - - self.velocity_z = vz; - - if(vlen(self.velocity)) - self.SendFlags |= TNSF_MOVE; - - return true; - } - case TR_DEATH: - { - self.velocity = '0 0 0'; - -#ifdef EWHEEL_FANCYPATH - if (self.pathcurrent) - pathlib_deletepath(self.pathcurrent.owner); -#endif - self.pathcurrent = world; - - return true; - } - case TR_SETUP: - { - entity e; - - if(self.movetype == MOVETYPE_WALK) - { - self.velocity = '0 0 0'; - self.enemy = world; - - setorigin(self, self.pos1); - - if (self.target != "") - { - e = find(world, targetname, self.target); - if (!e) - { - LOG_TRACE("Initital waypoint for ewheel does NOT exsist, fix your map!\n"); - self.target = ""; - } - - if (e.classname != "turret_checkpoint") - LOG_TRACE("Warning: not a turrret path\n"); - else - { - -#ifdef EWHEEL_FANCYPATH - self.pathcurrent = WALKER_PATH(self.origin,e.origin); - self.pathgoal = e; -#else - self.pathcurrent = e; -#endif - } - } - } - - self.iscreature = true; - self.teleportable = TELEPORT_NORMAL; - self.damagedbycontents = true; - self.movetype = MOVETYPE_WALK; - self.solid = SOLID_SLIDEBOX; - self.takedamage = DAMAGE_AIM; - self.idle_aim = '0 0 0'; - self.pos1 = self.origin; - self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; - self.frame = self.tur_head.frame = 1; - self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - - // Convert from dgr / sec to dgr / tic - self.tur_head.aim_speed = (autocvar_g_turrets_unit_ewheel_turnrate); - self.tur_head.aim_speed = self.tur_head.aim_speed / (1 / self.ticrate); - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC - -void ewheel_draw() -{SELFPARAM(); - float dt; - - dt = time - self.move_time; - self.move_time = time; - if(dt <= 0) - return; - - fixedmakevectors(self.angles); - setorigin(self, self.origin + self.velocity * dt); - self.tur_head.angles += dt * self.tur_head.move_avelocity; - self.angles_y = self.move_angles_y; - - if (self.health < 127) - if(random() < 0.05) - te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16); -} - -float t_ewheel(float req) -{SELFPARAM(); - switch(req) - { - case TR_SETUP: - { - self.gravity = 1; - self.movetype = MOVETYPE_BOUNCE; - self.move_movetype = MOVETYPE_BOUNCE; - self.move_origin = self.origin; - self.move_time = time; - self.draw = ewheel_draw; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/flac.qc b/qcsrc/common/turrets/unit/flac.qc deleted file mode 100644 index e19116067..000000000 --- a/qcsrc/common/turrets/unit/flac.qc +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ FLAC, -/* function */ t_flac, -/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_MISSILE, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "flac.md3", -/* netname */ "flac", -/* fullname */ _("FLAC Cannon") -); -#else -#ifdef SVQC -void turret_flac_projectile_think_explode() -{SELFPARAM(); - if(self.enemy != world) - if(vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 3) - setorigin(self,self.enemy.origin + randomvec() * self.owner.shot_radius); - -#ifdef TURRET_DEBUG - float d; - d = RadiusDamage (self, self.owner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world); - self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; - self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg; -#else - RadiusDamage (self, self.realowner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world); -#endif - remove(self); -} - -void spawnfunc_turret_flac() { SELFPARAM(); if(!turret_initialize(TUR_FLAC.m_id)) remove(self); } - -float t_flac(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - entity proj; - - turret_tag_fire_update(); - - proj = turret_projectile(SND(HAGAR_FIRE), 5, 0, DEATH_TURRET_FLAC, PROJECTILE_HAGAR, TRUE, TRUE); - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - proj.think = turret_flac_projectile_think_explode; - proj.nextthink = time + self.tur_impacttime + (random() * 0.01 - random() * 0.01); - proj.missile_flags = MIF_SPLASH | MIF_PROXY; - - self.tur_head.frame = self.tur_head.frame + 1; - if (self.tur_head.frame >= 4) - self.tur_head.frame = 0; - - return true; - } - case TR_THINK: - { - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; - self.damage_flags |= TFL_DMG_HEADSHAKE; - self.target_select_flags |= TFL_TARGETSELECT_NOTURRETS | TFL_TARGETSELECT_MISSILESONLY; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_flac(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/fusionreactor.qc b/qcsrc/common/turrets/unit/fusionreactor.qc deleted file mode 100644 index 5a8df2aad..000000000 --- a/qcsrc/common/turrets/unit/fusionreactor.qc +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ FUSIONREACTOR, -/* function */ t_fusionreactor, -/* spawnflags */ TUR_FLAG_SUPPORT | TUR_FLAG_AMMOSOURCE, -/* mins,maxs */ '-34 -34 0', '34 34 90', -/* model */ "base.md3", -/* head_model */ "reactor.md3", -/* netname */ "fusionreactor", -/* fullname */ _("Fusion Reactor") -); -#else -#ifdef SVQC -bool turret_fusionreactor_firecheck() -{SELFPARAM(); - if (self.attack_finished_single > time) - return false; - - if (self.enemy.deadflag != DEAD_NO) - return false; - - if (self.enemy == world) - return false; - - if (self.ammo < self.shot_dmg) - return false; - - if (self.enemy.ammo >= self.enemy.ammo_max) - return false; - - if (vlen(self.enemy.origin - self.origin) > self.target_range) - return false; - - if(self.team != self.enemy.team) - return false; - - if(!(self.enemy.ammo_flags & TFL_AMMO_ENERGY)) - return false; - - return true; -} - -void spawnfunc_turret_fusionreactor() { SELFPARAM(); if(!turret_initialize(TUR_FUSIONREACTOR.m_id)) remove(self); } - -float t_fusionreactor(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - vector fl_org; - - self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max); - fl_org = 0.5 * (self.enemy.absmin + self.enemy.absmax); - te_smallflash(fl_org); - - return true; - } - case TR_THINK: - { - self.tur_head.avelocity = '0 250 0' * (self.ammo / self.ammo_max); - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE; - self.target_select_flags = TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_OWNTEAM | TFL_TARGETSELECT_RANGELIMITS; - self.firecheck_flags = TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_AMMO_OTHER | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_DEAD; - self.shoot_flags = TFL_SHOOT_HITALLVALID; - self.aim_flags = TFL_AIM_NO; - self.track_flags = TFL_TRACK_NO; - - self.tur_head.scale = 0.75; - self.tur_head.avelocity = '0 50 0'; - - self.turret_firecheckfunc = turret_fusionreactor_firecheck; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_fusionreactor(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/hellion.qc b/qcsrc/common/turrets/unit/hellion.qc deleted file mode 100644 index 56f5da90a..000000000 --- a/qcsrc/common/turrets/unit/hellion.qc +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ HELLION, -/* function */ t_hellion, -/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "hellion.md3", -/* netname */ "hellion", -/* fullname */ _("Hellion Missile Turret") -); -#else -#ifdef SVQC -float autocvar_g_turrets_unit_hellion_shot_speed_gain; -float autocvar_g_turrets_unit_hellion_shot_speed_max; - -void turret_hellion_missile_think() -{SELFPARAM(); - vector olddir,newdir; - vector pre_pos; - float itime; - - self.nextthink = time + 0.05; - - olddir = normalize(self.velocity); - - if(self.max_health < time) - turret_projectile_explode(); - - // Enemy dead? just keep on the current heading then. - if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO)) - { - - // Make sure we dont return to tracking a respawned player - self.enemy = world; - - // Turn model - self.angles = vectoangles(self.velocity); - - if ( (vlen(self.origin - self.owner.origin)) > (self.owner.shot_radius * 5) ) - turret_projectile_explode(); - - // Accelerate - self.velocity = olddir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max)); - - UpdateCSQCProjectile(self); - - return; - } - - // Enemy in range? - if (vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 0.2) - turret_projectile_explode(); - - // Predict enemy position - itime = vlen(self.enemy.origin - self.origin) / vlen(self.velocity); - pre_pos = self.enemy.origin + self.enemy.velocity * itime; - - pre_pos = (pre_pos + self.enemy.origin) * 0.5; - - // Find out the direction to that place - newdir = normalize(pre_pos - self.origin); - - // Turn - newdir = normalize(olddir + newdir * 0.35); - - // Turn model - self.angles = vectoangles(self.velocity); - - // Accelerate - self.velocity = newdir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max)); - - if (itime < 0.05) - self.think = turret_projectile_explode; - - UpdateCSQCProjectile(self); -} - -void spawnfunc_turret_hellion() { SELFPARAM(); if(!turret_initialize(TUR_HELLION.m_id)) remove(self); } - -float t_hellion(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - entity missile; - - if(self.tur_head.frame != 0) - self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire")); - else - self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire2")); - - missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_HELLION, PROJECTILE_ROCKET, FALSE, FALSE); - te_explosion (missile.origin); - missile.think = turret_hellion_missile_think; - missile.nextthink = time; - missile.flags = FL_PROJECTILE; - missile.max_health = time + 9; - missile.tur_aimpos = randomvec() * 128; - missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT; - self.tur_head.frame += 1; - - return true; - } - case TR_THINK: - { - if (self.tur_head.frame != 0) - self.tur_head.frame += 1; - - if (self.tur_head.frame >= 7) - self.tur_head.frame = 0; - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.aim_flags = TFL_AIM_SIMPLE; - self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK ; - self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF | TFL_FIRECHECK_AMMO_OWN; - self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_hellion(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/hk.qc b/qcsrc/common/turrets/unit/hk.qc deleted file mode 100644 index 106c982ae..000000000 --- a/qcsrc/common/turrets/unit/hk.qc +++ /dev/null @@ -1,359 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ HK, -/* function */ t_hk, -/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER | TUR_FLAG_RECIEVETARGETS, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "hk.md3", -/* netname */ "hk", -/* fullname */ _("Hunter-Killer Turret") -); -#else -#ifdef SVQC -float autocvar_g_turrets_unit_hk_shot_speed; -float autocvar_g_turrets_unit_hk_shot_speed_accel; -float autocvar_g_turrets_unit_hk_shot_speed_accel2; -float autocvar_g_turrets_unit_hk_shot_speed_decel; -float autocvar_g_turrets_unit_hk_shot_speed_max; -float autocvar_g_turrets_unit_hk_shot_speed_turnrate; - -//#define TURRET_DEBUG_HK - -#ifdef TURRET_DEBUG_HK -.float atime; -#endif - -float hk_is_valid_target(entity e_target) -{SELFPARAM(); - if (e_target == world) - return 0; - - // If only this was used more.. - if (e_target.flags & FL_NOTARGET) - return 0; - - // Cant touch this - if ((e_target.takedamage == DAMAGE_NO) || (e_target.health < 0)) - return 0; - - // player - if (IS_CLIENT(e_target)) - { - if (self.owner.target_select_playerbias < 0) - return 0; - - if (e_target.deadflag != DEAD_NO) - return 0; - } - - // Missile - if ((e_target.flags & FL_PROJECTILE) && (self.owner.target_select_missilebias < 0)) - return 0; - - // Team check - if ((e_target.team == self.owner.team) || (self.owner.team == e_target.owner.team)) - return 0; - - return 1; -} - -void turret_hk_missile_think() -{SELFPARAM(); - vector vu, vd, vf, vl, vr, ve; // Vector (direction) - float fu, fd, ff, fl, fr, fe; // Fraction to solid - vector olddir,wishdir,newdir; // Final direction - float lt_for; // Length of Trace FORwrad - float lt_seek; // Length of Trace SEEK (left, right, up down) - float pt_seek; // Pitch of Trace SEEK (How mutch to angele left, right up, down trace towards v_forward) - vector pre_pos; - float myspeed; - entity e; - float ad,edist; - - self.nextthink = time + self.ticrate; - - //if (self.cnt < time) - // turret_hk_missile_explode(); - - if (self.enemy.deadflag != DEAD_NO) - self.enemy = world; - - // Pick the closest valid target. - if (!self.enemy) - { - e = findradius(self.origin, 5000); - while (e) - { - if (hk_is_valid_target(e)) - { - if (!self.enemy) - self.enemy = e; - else - if (vlen(self.origin - e.origin) < vlen(self.origin - self.enemy.origin)) - self.enemy = e; - } - e = e.chain; - } - } - - self.angles = vectoangles(self.velocity); - self.angles_x = self.angles_x * -1; - makevectors(self.angles); - self.angles_x = self.angles_x * -1; - - if (self.enemy) - { - edist = vlen(self.origin - self.enemy.origin); - // Close enougth to do decent damage? - if ( edist <= (self.owner.shot_radius * 0.25) ) - { - turret_projectile_explode(); - return; - } - - // Get data on enemy position - pre_pos = self.enemy.origin + - self.enemy.velocity * - min((vlen(self.enemy.origin - self.origin) / vlen(self.velocity)),0.5); - - traceline(self.origin, pre_pos,true,self.enemy); - ve = normalize(pre_pos - self.origin); - fe = trace_fraction; - - } - else - { - edist = 0; - ve = '0 0 0'; - fe = 0; - } - - if ((fe != 1) || (self.enemy == world) || (edist > 1000)) - { - myspeed = vlen(self.velocity); - - lt_for = myspeed * 3; - lt_seek = myspeed * 2.95; - - // Trace forward - traceline(self.origin, self.origin + v_forward * lt_for,false,self); - vf = trace_endpos; - ff = trace_fraction; - - // Find angular offset - ad = vlen(vectoangles(normalize(self.enemy.origin - self.origin)) - self.angles); - - // To close to something, Slow down! - if ( ((ff < 0.7) || (ad > 4)) && (myspeed > (autocvar_g_turrets_unit_hk_shot_speed)) ) - myspeed = max(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_decel), (autocvar_g_turrets_unit_hk_shot_speed)); - - // Failry clear, accelerate. - if ( (ff > 0.7) && (myspeed < (autocvar_g_turrets_unit_hk_shot_speed_max)) ) - myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel), (autocvar_g_turrets_unit_hk_shot_speed_max)); - - // Setup trace pitch - pt_seek = 1 - ff; - pt_seek = bound(0.15,pt_seek,0.8); - if (ff < 0.5) pt_seek = 1; - - // Trace left - traceline(self.origin, self.origin + (-1 * (v_right * pt_seek) + (v_forward * ff)) * lt_seek,false,self); - vl = trace_endpos; - fl = trace_fraction; - - // Trace right - traceline(self.origin, self.origin + ((v_right * pt_seek) + (v_forward * ff)) * lt_seek ,false,self); - vr = trace_endpos; - fr = trace_fraction; - - // Trace up - traceline(self.origin, self.origin + ((v_up * pt_seek) + (v_forward * ff)) * lt_seek ,false,self); - vu = trace_endpos; - fu = trace_fraction; - - // Trace down - traceline(self.origin, self.origin + (-1 * (v_up * pt_seek) + (v_forward * ff)) * lt_seek ,false,self); - vd = trace_endpos; - fd = trace_fraction; - - vl = normalize(vl - self.origin); - vr = normalize(vr - self.origin); - vu = normalize(vu - self.origin); - vd = normalize(vd - self.origin); - - // Panic tresh passed, find a single direction and turn as hard as we can - if (pt_seek == 1) - { - wishdir = v_right; - if (fl > fr) wishdir = -1 * v_right; - if (fu > fl) wishdir = v_up; - if (fd > fu) wishdir = -1 * v_up; - } - else - { - // Normalize our trace vectors to make a smooth path - wishdir = normalize( (vl * fl) + (vr * fr) + (vu * fu) + (vd * fd) ); - } - - if (self.enemy) - { - if (fe < 0.1) fe = 0.1; // Make sure we always try to move sligtly towards our target - wishdir = (wishdir * (1 - fe)) + (ve * fe); - } - } - else - { - // Got a clear path to target, speed up fast (if not at full speed) and go straight for it. - myspeed = vlen(self.velocity); - if (myspeed < (autocvar_g_turrets_unit_hk_shot_speed_max)) - myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel2),(autocvar_g_turrets_unit_hk_shot_speed_max)); - - wishdir = ve; - } - - if ((myspeed > (autocvar_g_turrets_unit_hk_shot_speed)) && (self.cnt > time)) - myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel2),(autocvar_g_turrets_unit_hk_shot_speed_max)); - - // Ranoutagazfish? - if (self.cnt < time) - { - self.cnt = time + 0.25; - self.nextthink = 0; - self.movetype = MOVETYPE_BOUNCE; - return; - } - - // Calculate new heading - olddir = normalize(self.velocity); - newdir = normalize(olddir + wishdir * (autocvar_g_turrets_unit_hk_shot_speed_turnrate)); - - // Set heading & speed - self.velocity = newdir * myspeed; - - // Align model with new heading - self.angles = vectoangles(self.velocity); - - -#ifdef TURRET_DEBUG_HK - //if(self.atime < time) { - if ((fe <= 0.99)||(edist > 1000)) - { - te_lightning2(world,self.origin, self.origin + vr * lt_seek); - te_lightning2(world,self.origin, self.origin + vl * lt_seek); - te_lightning2(world,self.origin, self.origin + vu * lt_seek); - te_lightning2(world,self.origin, self.origin + vd * lt_seek); - te_lightning2(world,self.origin, vf); - } - else - { - te_lightning2(world,self.origin, self.enemy.origin); - } - bprint("Speed: ", ftos(rint(myspeed)), "\n"); - bprint("Trace to solid: ", ftos(rint(ff * 100)), "%\n"); - bprint("Trace to target:", ftos(rint(fe * 100)), "%\n"); - self.atime = time + 0.2; - //} -#endif - - UpdateCSQCProjectile(self); -} - -float turret_hk_addtarget(entity e_target,entity e_sender) -{SELFPARAM(); - if (e_target) - { - if (turret_validate_target(self,e_target,self.target_validate_flags) > 0) - { - self.enemy = e_target; - return 1; - } - } - - return 0; -} - -void spawnfunc_turret_hk() { SELFPARAM(); if(!turret_initialize(TUR_HK.m_id)) remove(self); } - -float t_hk(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - entity missile; - - missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_HK, PROJECTILE_ROCKET, FALSE, FALSE); - te_explosion (missile.origin); - - missile.think = turret_hk_missile_think; - missile.nextthink = time + 0.25; - missile.movetype = MOVETYPE_BOUNCEMISSILE; - missile.velocity = self.tur_shotdir_updated * (self.shot_speed * 0.75); - missile.angles = vectoangles(missile.velocity); - missile.cnt = time + 30; - missile.ticrate = max(autocvar_sys_ticrate, 0.05); - missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_AI; - - if (self.tur_head.frame == 0) - self.tur_head.frame = self.tur_head.frame + 1; - - return true; - } - case TR_THINK: - { - if (self.tur_head.frame != 0) - self.tur_head.frame = self.tur_head.frame + 1; - - if (self.tur_head.frame > 5) - self.tur_head.frame = 0; - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - self.aim_flags = TFL_AIM_SIMPLE; - self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF; - self.shoot_flags = TFL_SHOOT_CLEARTARGET; - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK; - - self.turret_addtarget = turret_hk_addtarget; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_hk(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/machinegun.qc b/qcsrc/common/turrets/unit/machinegun.qc deleted file mode 100644 index 35f1921ed..000000000 --- a/qcsrc/common/turrets/unit/machinegun.qc +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ MACHINEGUN, -/* function */ t_machinegun, -/* spawnflags */ TUR_FLAG_PLAYER, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "machinegun.md3", -/* netname */ "machinegun", -/* fullname */ _("Machinegun Turret") -); -#else -#ifdef SVQC -void spawnfunc_turret_machinegun() { SELFPARAM(); if(!turret_initialize(TUR_MACHINEGUN.m_id)) remove(self); } - -void W_MachineGun_MuzzleFlash(void); - -float t_machinegun(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_MACHINEGUN, 0); - - W_MachineGun_MuzzleFlash(); - setattachment(self.muzzle_flash, self.tur_head, "tag_fire"); - - return true; - } - case TR_THINK: - { - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.damage_flags |= TFL_DMG_HEADSHAKE; - self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; - self.turret_flags |= TUR_FLAG_HITSCAN; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_machinegun(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/mlrs.qc b/qcsrc/common/turrets/unit/mlrs.qc deleted file mode 100644 index 21e0a435d..000000000 --- a/qcsrc/common/turrets/unit/mlrs.qc +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ MLRS, -/* function */ t_mlrs, -/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "mlrs.md3", -/* netname */ "mlrs", -/* fullname */ _("MLRS Turret") -); -#else -#ifdef SVQC -void spawnfunc_turret_mlrs() { SELFPARAM(); if(!turret_initialize(TUR_MLRS.m_id)) remove(self); } - -float t_mlrs(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - entity missile; - - turret_tag_fire_update(); - missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_MLRS, PROJECTILE_ROCKET, TRUE, TRUE); - missile.nextthink = time + max(self.tur_impacttime,(self.shot_radius * 2) / self.shot_speed); - missile.missile_flags = MIF_SPLASH; - te_explosion (missile.origin); - - return true; - } - case TR_THINK: - { - // 0 = full, 6 = empty - self.tur_head.frame = bound(0, 6 - floor(0.1 + self.ammo / self.shot_dmg), 6); - if(self.tur_head.frame < 0) - { - LOG_TRACE("ammo:",ftos(self.ammo),"\n"); - LOG_TRACE("shot_dmg:",ftos(self.shot_dmg),"\n"); - } - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; - - self.damage_flags |= TFL_DMG_HEADSHAKE; - self.shoot_flags |= TFL_SHOOT_VOLLYALWAYS; - self.volly_counter = self.shot_volly; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_mlrs(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/phaser.qc b/qcsrc/common/turrets/unit/phaser.qc deleted file mode 100644 index 04e226448..000000000 --- a/qcsrc/common/turrets/unit/phaser.qc +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ PHASER, -/* function */ t_phaser, -/* spawnflags */ TUR_FLAG_SNIPER | TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "phaser.md3", -/* netname */ "phaser", -/* fullname */ _("Phaser Cannon") -); -#else -#ifdef SVQC -.float fireflag; - -float turret_phaser_firecheck() -{SELFPARAM(); - if (self.fireflag != 0) return 0; - return turret_firecheck(); -} - -void beam_think() -{SELFPARAM(); - if ((time > self.cnt) || (self.owner.deadflag != DEAD_NO)) - { - self.owner.attack_finished_single = time + self.owner.shot_refire; - self.owner.fireflag = 2; - self.owner.tur_head.frame = 10; - sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); - remove(self); - return; - } - - turret_do_updates(self.owner); - - if (time - self.shot_spread > 0) - { - self.shot_spread = time + 2; - sound (self, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM); - } - - - self.nextthink = time + self.ticrate; - - self.owner.attack_finished_single = time + frametime; - setself(self.owner); - FireImoBeam ( self.tur_shotorg, - self.tur_shotorg + self.tur_shotdir_updated * self.target_range, - '-1 -1 -1' * self.shot_radius, - '1 1 1' * self.shot_radius, - self.shot_force, - this.shot_dmg, - 0.75, - DEATH_TURRET_PHASER); - setself(this); - self.scale = vlen(self.owner.tur_shotorg - trace_endpos) / 256; - -} - -void spawnfunc_turret_phaser() { SELFPARAM(); if(!turret_initialize(TUR_PHASER.m_id)) remove(self); } - -float t_phaser(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - entity beam; - - beam = spawn(); - beam.ticrate = 0.1; //autocvar_sys_ticrate; - setmodel(beam, MDL_TUR_PHASER_BEAM); - beam.effects = EF_LOWPRECISION; - beam.solid = SOLID_NOT; - beam.think = beam_think; - beam.cnt = time + self.shot_speed; - beam.shot_spread = time + 2; - beam.nextthink = time; - beam.owner = self; - beam.shot_dmg = self.shot_dmg / (self.shot_speed / beam.ticrate); - beam.scale = self.target_range / 256; - beam.movetype = MOVETYPE_NONE; - beam.enemy = self.enemy; - beam.bot_dodge = true; - beam.bot_dodgerating = beam.shot_dmg; - sound (beam, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM); - self.fireflag = 1; - - beam.attack_finished_single = self.attack_finished_single; - self.attack_finished_single = time; // + autocvar_sys_ticrate; - - setattachment(beam,self.tur_head,"tag_fire"); - - soundat (self, trace_endpos, CH_SHOTS, SND(NEXIMPACT), VOL_BASE, ATTEN_NORM); - - if (self.tur_head.frame == 0) - self.tur_head.frame = 1; - - return true; - } - case TR_THINK: - { - if (self.tur_head.frame != 0) - { - if (self.fireflag == 1) - { - if (self.tur_head.frame == 10) - self.tur_head.frame = 1; - else - self.tur_head.frame = self.tur_head.frame +1; - } - else if (self.fireflag == 2 ) - { - self.tur_head.frame = self.tur_head.frame +1; - if (self.tur_head.frame == 15) - { - self.tur_head.frame = 0; - self.fireflag = 0; - } - } - } - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - self.aim_flags = TFL_AIM_LEAD; - - self.turret_firecheckfunc = turret_phaser_firecheck; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_phaser(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/plasma.qc b/qcsrc/common/turrets/unit/plasma.qc deleted file mode 100644 index baafa51c6..000000000 --- a/qcsrc/common/turrets/unit/plasma.qc +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ PLASMA, -/* function */ t_plasma, -/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "plasma.md3", -/* netname */ "plasma", -/* fullname */ _("Plasma Cannon") -); -#else -#ifdef SVQC -void spawnfunc_turret_plasma() { SELFPARAM(); if(!turret_initialize(TUR_PLASMA.m_id)) remove(self); } - -float t_plasma(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - if(g_instagib) - { - float flying; - flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last - - FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, - 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); - - Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - - // teamcolor / hit beam effect - vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); - WarpZone_TrailParticles(world, particleeffectnum(EFFECT_VAPORIZER(self.team)), self.tur_shotorg, v); - if (self.tur_head.frame == 0) - self.tur_head.frame = 1; - } - else - { - entity missile = turret_projectile(SND(HAGAR_FIRE), 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); - missile.missile_flags = MIF_SPLASH; - - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - if (self.tur_head.frame == 0) - self.tur_head.frame = 1; - } - - return true; - } - case TR_THINK: - { - if (self.tur_head.frame != 0) - self.tur_head.frame = self.tur_head.frame + 1; - - if (self.tur_head.frame > 5) - self.tur_head.frame = 0; - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - self.damage_flags |= TFL_DMG_HEADSHAKE; - self.firecheck_flags |= TFL_FIRECHECK_AFF; - self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; - - turret_do_updates(self); - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_plasma(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/plasma_dual.qc b/qcsrc/common/turrets/unit/plasma_dual.qc deleted file mode 100644 index 8b2bc252e..000000000 --- a/qcsrc/common/turrets/unit/plasma_dual.qc +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ PLASMA_DUAL, -/* function */ t_plasma_dual, -/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, -/* mins,maxs */ '-32 -32 0', '32 32 64', -/* model */ "base.md3", -/* head_model */ "plasmad.md3", -/* netname */ "plasma_dual", -/* fullname */ _("Dual Plasma Cannon") -); -#else - -#include "../../weapons/all.qh" - -CLASS(PlasmaDualAttack, PortoLaunch) -/* flags */ ATTRIB(PlasmaDualAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(PlasmaDualAttack, impulse, int, 5); -/* refname */ ATTRIB(PlasmaDualAttack, netname, string, "plasmadual"); -/* wepname */ ATTRIB(PlasmaDualAttack, message, string, _("Dual plasma")); -ENDCLASS(PlasmaDualAttack) -REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack)); - -#ifdef SVQC - -float t_plasma_dual(float req); -METHOD(PlasmaDualAttack, wr_think, bool(entity thiswep)) { - SELFPARAM(); - if (self.BUTTON_ATCK) - if (weapon_prepareattack(0, WEP_CVAR_PRI(electro, refire))) { - W_SetupShot_Dir(self, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0); - self.tur_shotdir_updated = w_shotdir; - self.tur_shotorg = w_shotorg; - self.tur_head = self; - self.shot_speed = max(1, ((!self.shot_speed) ? 2500 : self.shot_speed)); - self.shot_spread = bound(0.0001, ((!self.shot_spread) ? 0.0125 : self.shot_spread), 500); - t_plasma_dual(TR_ATTACK); - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - return true; -} - -void spawnfunc_turret_plasma_dual() { SELFPARAM(); if(!turret_initialize(TUR_PLASMA_DUAL.m_id)) remove(self); } - -float t_plasma_dual(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - if(g_instagib) - { - float flying; - flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last - - FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, - 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); - - - Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - - // teamcolor / hit beam effect - vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); - WarpZone_TrailParticles(world, particleeffectnum(EFFECT_VAPORIZER(self.team)), self.tur_shotorg, v); - self.tur_head.frame += 1; - } - else - { - entity missile = turret_projectile(SND(HAGAR_FIRE), 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); - missile.missile_flags = MIF_SPLASH; - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - self.tur_head.frame += 1; - } - - return true; - } - case TR_THINK: - { - if ((self.tur_head.frame != 0) && (self.tur_head.frame != 3)) - self.tur_head.frame = self.tur_head.frame + 1; - - if (self.tur_head.frame > 6) - self.tur_head.frame = 0; - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - self.damage_flags |= TFL_DMG_HEADSHAKE; - self.firecheck_flags |= TFL_FIRECHECK_AFF; - self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; - - turret_do_updates(self); - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_plasma_dual(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/tesla.qc b/qcsrc/common/turrets/unit/tesla.qc deleted file mode 100644 index d3c894b96..000000000 --- a/qcsrc/common/turrets/unit/tesla.qc +++ /dev/null @@ -1,215 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ TESLA, -/* function */ t_tesla, -/* spawnflags */ TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE, -/* mins,maxs */ '-60 -60 0', '60 60 128', -/* model */ "tesla_base.md3", -/* head_model */ "tesla_head.md3", -/* netname */ "tesla", -/* fullname */ _("Tesla Coil") -); -#else -#ifdef SVQC -entity toast(entity from, float range, float damage) -{SELFPARAM(); - entity e; - entity etarget = world; - float d,dd; - float r; - - dd = range + 1; - - e = findradius(from.origin,range); - while (e) - { - if ((e.railgunhit != 1) && (e != from)) - { - r = turret_validate_target(self,e,self.target_validate_flags); - if (r > 0) - { - traceline(from.origin,0.5 * (e.absmin + e.absmax),MOVE_WORLDONLY,from); - if (trace_fraction == 1.0) - { - d = vlen(e.origin - from.origin); - if (d < dd) - { - dd = d; - etarget = e; - } - } - } - } - e = e.chain; - } - - if (etarget) - { - te_csqc_lightningarc(from.origin,etarget.origin); - Damage(etarget, self, self, damage, DEATH_TURRET_TESLA, etarget.origin, '0 0 0'); - etarget.railgunhit = 1; - } - - return etarget; -} - -float turret_tesla_firecheck() -{SELFPARAM(); - // g_turrets_targetscan_maxdelay forces a target re-scan at least this often - float do_target_scan = 0; - - if((self.target_select_time + autocvar_g_turrets_targetscan_maxdelay) < time) - do_target_scan = 1; - - // Old target (if any) invalid? - if(self.target_validate_time < time) - if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0) - { - self.enemy = world; - self.target_validate_time = time + 0.5; - do_target_scan = 1; - } - - // But never more often then g_turrets_targetscan_mindelay! - if (self.target_select_time + autocvar_g_turrets_targetscan_mindelay > time) - do_target_scan = 0; - - if(do_target_scan) - { - self.enemy = turret_select_target(); - self.target_select_time = time; - } - - if(!turret_firecheck()) - return 0; - - if(self.enemy) - return 1; - - return 0; -} - -void spawnfunc_turret_tesla() { SELFPARAM(); if(!turret_initialize(TUR_TESLA.m_id)) remove(self); } - -float t_tesla(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - entity e, t; - float d, r, i; - - d = self.shot_dmg; - r = self.target_range; - e = spawn(); - setorigin(e,self.tur_shotorg); - - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - - t = toast(e,r,d); - remove(e); - - if (t == world) return true; - - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK; - - self.attack_finished_single = time + self.shot_refire; - for (i = 0; i < 10; ++i) - { - d *= 0.75; - r *= 0.85; - t = toast(t, r, d); - if (t == world) break; - - } - - e = findchainfloat(railgunhit, 1); - while (e) - { - e.railgunhit = 0; - e = e.chain; - } - - return true; - } - case TR_THINK: - { - if(!self.active) - { - self.tur_head.avelocity = '0 0 0'; - return true; - } - - if(self.ammo < self.shot_dmg) - { - self.tur_head.avelocity = '0 45 0' * (self.ammo / self.shot_dmg); - } - else - { - self.tur_head.avelocity = '0 180 0' * (self.ammo / self.shot_dmg); - - if(self.attack_finished_single > time) - return true; - - float f; - f = (self.ammo / self.ammo_max); - f = f * f; - if(f > random()) - if(random() < 0.1) - te_csqc_lightningarc(self.tur_shotorg,self.tur_shotorg + (randomvec() * 350)); - } - - return true; - } - case TR_DEATH: - { - return true; - } - case TR_SETUP: - { - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | - TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - - self.turret_firecheckfunc = turret_tesla_firecheck; - self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | - TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - - self.firecheck_flags = TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AMMO_OWN; - self.shoot_flags = TFL_SHOOT_CUSTOM; - self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - self.aim_flags = TFL_AIM_NO; - self.track_flags = TFL_TRACK_NO; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC -float t_tesla(float req) -{ - switch(req) - { - case TR_SETUP: - { - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/common/turrets/unit/walker.qc b/qcsrc/common/turrets/unit/walker.qc deleted file mode 100644 index 792e7a338..000000000 --- a/qcsrc/common/turrets/unit/walker.qc +++ /dev/null @@ -1,694 +0,0 @@ -#ifndef IMPLEMENTATION -REGISTER_TURRET( -/* TUR_##id */ WALKER, -/* function */ t_walker, -/* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE, -/* mins,maxs */ '-70 -70 0', '70 70 95', -/* model */ "walker_body.md3", -/* head_model */ "walker_head_minigun.md3", -/* netname */ "walker", -/* fullname */ _("Walker Turret") -); -#else -#ifdef SVQC -float autocvar_g_turrets_unit_walker_melee_damage; -float autocvar_g_turrets_unit_walker_melee_force; -float autocvar_g_turrets_unit_walker_melee_range; -float autocvar_g_turrets_unit_walker_rocket_damage; -float autocvar_g_turrets_unit_walker_rocket_radius; -float autocvar_g_turrets_unit_walker_rocket_force; -float autocvar_g_turrets_unit_walker_rocket_speed; -float autocvar_g_turrets_unit_walker_rocket_range; -float autocvar_g_turrets_unit_walker_rocket_range_min; -float autocvar_g_turrets_unit_walker_rocket_refire; -float autocvar_g_turrets_unit_walker_rocket_turnrate; -float autocvar_g_turrets_unit_walker_speed_stop; -float autocvar_g_turrets_unit_walker_speed_walk; -float autocvar_g_turrets_unit_walker_speed_run; -float autocvar_g_turrets_unit_walker_speed_jump; -float autocvar_g_turrets_unit_walker_speed_swim; -float autocvar_g_turrets_unit_walker_speed_roam; -float autocvar_g_turrets_unit_walker_turn; -float autocvar_g_turrets_unit_walker_turn_walk; -float autocvar_g_turrets_unit_walker_turn_strafe; -float autocvar_g_turrets_unit_walker_turn_swim; -float autocvar_g_turrets_unit_walker_turn_run; - -#define ANIM_NO 0 -#define ANIM_TURN 1 -#define ANIM_WALK 2 -#define ANIM_RUN 3 -#define ANIM_STRAFE_L 4 -#define ANIM_STRAFE_R 5 -#define ANIM_JUMP 6 -#define ANIM_LAND 7 -#define ANIM_PAIN 8 -#define ANIM_MELEE 9 -#define ANIM_SWIM 10 -#define ANIM_ROAM 11 - -.float animflag; -.float idletime; - -#define WALKER_PATH(s,e) pathlib_astar(s,e) - -float walker_firecheck() -{SELFPARAM(); - if (self.animflag == ANIM_MELEE) - return 0; - - return turret_firecheck(); -} - -void walker_melee_do_dmg() -{SELFPARAM(); - vector where; - entity e; - - makevectors(self.angles); - where = self.origin + v_forward * 128; - - e = findradius(where,32); - while (e) - { - if (turret_validate_target(self, e, self.target_validate_flags)) - if (e != self && e.owner != self) - Damage(e, self, self, (autocvar_g_turrets_unit_walker_melee_damage), DEATH_TURRET_WALK_MELEE, '0 0 0', v_forward * (autocvar_g_turrets_unit_walker_melee_force)); - - e = e.chain; - } -} - -void walker_setnoanim() -{SELFPARAM(); - turrets_setframe(ANIM_NO, false); - self.animflag = self.frame; -} -void walker_rocket_explode() -{SELFPARAM(); - RadiusDamage (self, self.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), self, world, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET, world); - remove (self); -} - -void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) -{SELFPARAM(); - self.health = self.health - damage; - self.velocity = self.velocity + vforce; - - if (self.health <= 0) - W_PrepareExplosionByDamage(self.owner, walker_rocket_explode); -} - -#define WALKER_ROCKET_MOVE movelib_move_simple(newdir, (autocvar_g_turrets_unit_walker_rocket_speed), (autocvar_g_turrets_unit_walker_rocket_turnrate)); UpdateCSQCProjectile(self) -void walker_rocket_loop(); -void walker_rocket_think() -{SELFPARAM(); - vector newdir; - float edist; - float itime; - float m_speed; - - self.nextthink = time; - - edist = vlen(self.enemy.origin - self.origin); - - // Simulate crude guidance - if (self.cnt < time) - { - if (edist < 1000) - self.tur_shotorg = randomvec() * min(edist, 64); - else - self.tur_shotorg = randomvec() * min(edist, 256); - - self.cnt = time + 0.5; - } - - if (edist < 128) - self.tur_shotorg = '0 0 0'; - - if (self.max_health < time) - { - self.think = walker_rocket_explode; - self.nextthink = time; - return; - } - - if (self.shot_dmg != 1337 && random() < 0.01) - { - walker_rocket_loop(); - return; - } - - m_speed = vlen(self.velocity); - - // Enemy dead? just keep on the current heading then. - if (self.enemy == world || self.enemy.deadflag != DEAD_NO) - self.enemy = world; - - if (self.enemy) - { - itime = max(edist / m_speed, 1); - newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg); - } - else - newdir = normalize(self.velocity); - - WALKER_ROCKET_MOVE; -} - -void walker_rocket_loop3() -{SELFPARAM(); - vector newdir; - self.nextthink = time; - - if (self.max_health < time) - { - self.think = walker_rocket_explode; - return; - } - - if (vlen(self.origin - self.tur_shotorg) < 100 ) - { - self.think = walker_rocket_think; - return; - } - - newdir = steerlib_pull(self.tur_shotorg); - WALKER_ROCKET_MOVE; - - self.angles = vectoangles(self.velocity); -} - -void walker_rocket_loop2() -{SELFPARAM(); - vector newdir; - - self.nextthink = time; - - if (self.max_health < time) - { - self.think = walker_rocket_explode; - return; - } - - if (vlen(self.origin - self.tur_shotorg) < 100 ) - { - self.tur_shotorg = self.origin - '0 0 200'; - self.think = walker_rocket_loop3; - return; - } - - newdir = steerlib_pull(self.tur_shotorg); - WALKER_ROCKET_MOVE; -} - -void walker_rocket_loop() -{SELFPARAM(); - self.nextthink = time; - self.tur_shotorg = self.origin + '0 0 300'; - self.think = walker_rocket_loop2; - self.shot_dmg = 1337; -} - -void walker_fire_rocket(vector org) -{SELFPARAM(); - entity rocket; - - fixedmakevectors(self.angles); - - te_explosion (org); - - rocket = spawn (); - setorigin(rocket, org); - - sound (self, CH_WEAPON_A, SND_HAGAR_FIRE, VOL_BASE, ATTEN_NORM); - setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot - - rocket.classname = "walker_rocket"; - rocket.owner = self; - rocket.bot_dodge = true; - rocket.bot_dodgerating = 50; - rocket.takedamage = DAMAGE_YES; - rocket.damageforcescale = 2; - rocket.health = 25; - rocket.tur_shotorg = randomvec() * 512; - rocket.cnt = time + 1; - rocket.enemy = self.enemy; - - if (random() < 0.01) - rocket.think = walker_rocket_loop; - else - rocket.think = walker_rocket_think; - - rocket.event_damage = walker_rocket_damage; - - rocket.nextthink = time; - rocket.movetype = MOVETYPE_FLY; - rocket.velocity = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * (autocvar_g_turrets_unit_walker_rocket_speed); - rocket.angles = vectoangles(rocket.velocity); - rocket.touch = walker_rocket_explode; - rocket.flags = FL_PROJECTILE; - rocket.solid = SOLID_BBOX; - rocket.max_health = time + 9; - rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT; - - CSQCProjectile(rocket, false, PROJECTILE_ROCKET, false); // no culling, has fly sound -} - -.vector enemy_last_loc; -.float enemy_last_time; -void walker_move_to(vector _target, float _dist) -{SELFPARAM(); - switch (self.waterlevel) - { - case WATERLEVEL_NONE: - if (_dist > 500) - self.animflag = ANIM_RUN; - else - self.animflag = ANIM_WALK; - case WATERLEVEL_WETFEET: - case WATERLEVEL_SWIMMING: - if (self.animflag != ANIM_SWIM) - self.animflag = ANIM_WALK; - else - self.animflag = ANIM_SWIM; - break; - case WATERLEVEL_SUBMERGED: - self.animflag = ANIM_SWIM; - } - - self.moveto = _target; - self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); - - if(self.enemy) - { - self.enemy_last_loc = _target; - self.enemy_last_time = time; - } -} - -//#define WALKER_FANCYPATHING - -void walker_move_path() -{SELFPARAM(); -#ifdef WALKER_FANCYPATHING - // Are we close enougth to a path node to switch to the next? - if (vlen(self.origin - self.pathcurrent.origin) < 64) - if (self.pathcurrent.path_next == world) - { - // Path endpoint reached - pathlib_deletepath(self.pathcurrent.owner); - self.pathcurrent = world; - - if (self.pathgoal) - { - if (self.pathgoal.use) - self.pathgoal.use(); - - if (self.pathgoal.enemy) - { - self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin); - self.pathgoal = self.pathgoal.enemy; - } - } - else - self.pathgoal = world; - } - else - self.pathcurrent = self.pathcurrent.path_next; - - self.moveto = self.pathcurrent.origin; - self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95); - walker_move_to(self.moveto, 0); - -#else - if (vlen(self.origin - self.pathcurrent.origin) < 64) - self.pathcurrent = self.pathcurrent.enemy; - - if(!self.pathcurrent) - return; - - self.moveto = self.pathcurrent.origin; - self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); - walker_move_to(self.moveto, 0); -#endif -} - -void spawnfunc_turret_walker() { SELFPARAM(); if(!turret_initialize(TUR_WALKER.m_id)) remove(self); } - -float t_walker(float req) -{SELFPARAM(); - switch(req) - { - case TR_ATTACK: - { - sound (self, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM); - fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_WALK_GUN, 0); - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - - return true; - } - case TR_THINK: - { - fixedmakevectors(self.angles); - - if (self.spawnflags & TSF_NO_PATHBREAK && self.pathcurrent) - walker_move_path(); - else if (self.enemy == world) - { - if(self.pathcurrent) - walker_move_path(); - else - { - if(self.enemy_last_time != 0) - { - if(vlen(self.origin - self.enemy_last_loc) < 128 || time - self.enemy_last_time > 10) - self.enemy_last_time = 0; - else - walker_move_to(self.enemy_last_loc, 0); - } - else - { - if(self.animflag != ANIM_NO) - { - traceline(self.origin + '0 0 64', self.origin + '0 0 64' + v_forward * 128, MOVE_NORMAL, self); - - if(trace_fraction != 1.0) - self.tur_head.idletime = -1337; - else - { - traceline(trace_endpos, trace_endpos - '0 0 256', MOVE_NORMAL, self); - if(trace_fraction == 1.0) - self.tur_head.idletime = -1337; - } - - if(self.tur_head.idletime == -1337) - { - self.moveto = self.origin + randomvec() * 256; - self.tur_head.idletime = 0; - } - - self.moveto = self.moveto * 0.9 + ((self.origin + v_forward * 500) + randomvec() * 400) * 0.1; - self.moveto_z = self.origin_z + 64; - walker_move_to(self.moveto, 0); - } - - if(self.idletime < time) - { - if(random() < 0.5 || !(self.spawnflags & TSL_ROAM)) - { - self.idletime = time + 1 + random() * 5; - self.moveto = self.origin; - self.animflag = ANIM_NO; - } - else - { - self.animflag = ANIM_WALK; - self.idletime = time + 4 + random() * 2; - self.moveto = self.origin + randomvec() * 256; - self.tur_head.moveto = self.moveto; - self.tur_head.idletime = 0; - } - } - } - } - } - else - { - if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_melee_range) && self.animflag != ANIM_MELEE) - { - vector wish_angle; - - wish_angle = angleofs(self, self.enemy); - if (self.animflag != ANIM_SWIM) - if (fabs(wish_angle_y) < 15) - { - self.moveto = self.enemy.origin; - self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95); - self.animflag = ANIM_MELEE; - } - } - else if (self.tur_head.attack_finished_single < time) - { - if(self.tur_head.shot_volly) - { - self.animflag = ANIM_NO; - - self.tur_head.shot_volly = self.tur_head.shot_volly -1; - if(self.tur_head.shot_volly == 0) - self.tur_head.attack_finished_single = time + (autocvar_g_turrets_unit_walker_rocket_refire); - else - self.tur_head.attack_finished_single = time + 0.2; - - if(self.tur_head.shot_volly > 1) - walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket01"))); - else - walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket02"))); - } - else - { - if (self.tur_dist_enemy > (autocvar_g_turrets_unit_walker_rocket_range_min)) - if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_rocket_range)) - self.tur_head.shot_volly = 4; - } - } - else - { - if (self.animflag != ANIM_MELEE) - walker_move_to(self.enemy.origin, self.tur_dist_enemy); - } - } - - { - vector real_angle; - float turny = 0, turnx = 0; - float vz; - - real_angle = vectoangles(self.steerto) - self.angles; - vz = self.velocity_z; - - switch (self.animflag) - { - case ANIM_NO: - movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop)); - break; - - case ANIM_TURN: - turny = (autocvar_g_turrets_unit_walker_turn); - movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop)); - break; - - case ANIM_WALK: - turny = (autocvar_g_turrets_unit_walker_turn_walk); - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_walk), 0.6); - break; - - case ANIM_RUN: - turny = (autocvar_g_turrets_unit_walker_turn_run); - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_run), 0.6); - break; - - case ANIM_STRAFE_L: - turny = (autocvar_g_turrets_unit_walker_turn_strafe); - movelib_move_simple(v_right * -1, (autocvar_g_turrets_unit_walker_speed_walk), 0.8); - break; - - case ANIM_STRAFE_R: - turny = (autocvar_g_turrets_unit_walker_turn_strafe); - movelib_move_simple(v_right, (autocvar_g_turrets_unit_walker_speed_walk), 0.8); - break; - - case ANIM_JUMP: - self.velocity += '0 0 1' * (autocvar_g_turrets_unit_walker_speed_jump); - break; - - case ANIM_LAND: - break; - - case ANIM_PAIN: - if(self.frame != ANIM_PAIN) - defer(0.25, walker_setnoanim); - - break; - - case ANIM_MELEE: - if(self.frame != ANIM_MELEE) - { - defer(0.41, walker_setnoanim); - defer(0.21, walker_melee_do_dmg); - } - - movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop)); - break; - - case ANIM_SWIM: - turny = (autocvar_g_turrets_unit_walker_turn_swim); - turnx = (autocvar_g_turrets_unit_walker_turn_swim); - - self.angles_x += bound(-10, shortangle_f(real_angle_x, self.angles_x), 10); - movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_swim), 0.3); - vz = self.velocity_z + sin(time * 4) * 8; - break; - - case ANIM_ROAM: - turny = (autocvar_g_turrets_unit_walker_turn_walk); - movelib_move_simple(v_forward ,(autocvar_g_turrets_unit_walker_speed_roam), 0.5); - break; - } - - if(turny) - { - turny = bound( turny * -1, shortangle_f(real_angle_y, self.angles_y), turny ); - self.angles_y += turny; - } - - if(turnx) - { - turnx = bound( turnx * -1, shortangle_f(real_angle_x, self.angles_x), turnx ); - self.angles_x += turnx; - } - - self.velocity_z = vz; - } - - - if(self.origin != self.oldorigin) - self.SendFlags |= TNSF_MOVE; - - self.oldorigin = self.origin; - turrets_setframe(self.animflag, false); - - return true; - } - case TR_DEATH: - { -#ifdef WALKER_FANCYPATHING - if (self.pathcurrent) - pathlib_deletepath(self.pathcurrent.owner); -#endif - self.pathcurrent = world; - - return true; - } - case TR_SETUP: - { - self.ticrate = 0.05; - - entity e; - - // Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn. - if(self.movetype == MOVETYPE_WALK) - { - if(self.pos1) - setorigin(self, self.pos1); - if(self.pos2) - self.angles = self.pos2; - } - - self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - self.aim_flags = TFL_AIM_LEAD; - self.turret_flags |= TUR_FLAG_HITSCAN; - - self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; - self.iscreature = true; - self.teleportable = TELEPORT_NORMAL; - self.damagedbycontents = true; - self.solid = SOLID_SLIDEBOX; - self.takedamage = DAMAGE_AIM; - if(self.movetype != MOVETYPE_WALK) - { - setorigin(self, self.origin); - tracebox(self.origin + '0 0 128', self.mins, self.maxs, self.origin - '0 0 10000', MOVE_NORMAL, self); - setorigin(self, trace_endpos + '0 0 4'); - self.pos1 = self.origin; - self.pos2 = self.angles; - } - self.movetype = MOVETYPE_WALK; - self.idle_aim = '0 0 0'; - self.turret_firecheckfunc = walker_firecheck; - - if (self.target != "") - { - e = find(world, targetname, self.target); - if (!e) - { - LOG_TRACE("Initital waypoint for walker does NOT exsist, fix your map!\n"); - self.target = ""; - } - - if (e.classname != "turret_checkpoint") - LOG_TRACE("Warning: not a turrret path\n"); - else - { -#ifdef WALKER_FANCYPATHING - self.pathcurrent = WALKER_PATH(self.origin, e.origin); - self.pathgoal = e; -#else - self.pathcurrent = e; -#endif - } - } - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // SVQC -#ifdef CSQC - -#include "../../../client/movelib.qh" - -void walker_draw() -{SELFPARAM(); - float dt; - - dt = time - self.move_time; - self.move_time = time; - if(dt <= 0) - return; - - fixedmakevectors(self.angles); - movelib_groundalign4point(300, 100, 0.25, 45); - setorigin(self, self.origin + self.velocity * dt); - self.tur_head.angles += dt * self.tur_head.move_avelocity; - self.angles_y = self.move_angles_y; - - if (self.health < 127) - if(random() < 0.15) - te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16); -} - -float t_walker(float req) -{SELFPARAM(); - switch(req) - { - case TR_SETUP: - { - self.gravity = 1; - self.movetype = MOVETYPE_BOUNCE; - self.move_movetype = MOVETYPE_BOUNCE; - self.move_origin = self.origin; - self.move_time = time; - self.draw = walker_draw; - - return true; - } - case TR_PRECACHE: - { - return true; - } - } - - return true; -} - -#endif // CSQC -#endif // REGISTER_TURRET diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index e17e7adbc..2c889c09e 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -557,7 +557,6 @@ void spawnfunc___init_dedicated_server(void) // needs to be done so early because of the constants they create static_init(); - CALL_ACCUMULATED_FUNCTION(RegisterTurrets); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); @@ -604,7 +603,6 @@ void spawnfunc_worldspawn (void) // needs to be done so early because of the constants they create static_init(); - CALL_ACCUMULATED_FUNCTION(RegisterTurrets); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); diff --git a/qcsrc/server/progs.inc b/qcsrc/server/progs.inc index 4eceb36b9..86ede6350 100644 --- a/qcsrc/server/progs.inc +++ b/qcsrc/server/progs.inc @@ -101,13 +101,13 @@ #include "../common/items/all.qc" #include "../common/monsters/all.qc" #include "../common/mutators/all.qc" +#include "../common/turrets/all.qc" #include "../common/vehicles/all.qc" -#include "../common/weapons/all.qc" // TODO +#include "../common/weapons/all.qc" #include "../common/turrets/sv_turrets.qc" #include "../common/turrets/config.qc" #include "../common/turrets/util.qc" -#include "../common/turrets/all.qc" #include "../common/turrets/checkpoint.qc" #include "../common/turrets/targettrigger.qc" #include "../common/weapons/config.qc"