From: TimePath Date: Wed, 30 Sep 2015 23:10:37 +0000 (+1000) Subject: Turrets: factor out attacks X-Git-Tag: xonotic-v0.8.2~1874^2~27 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=93f6c1c41d7a17718dfbf7b464c319a9716643f4;ds=sidebyside Turrets: factor out attacks --- diff --git a/qcsrc/common/turrets/turret/ewheel.qc b/qcsrc/common/turrets/turret/ewheel.qc index b725c029f8..6dab617275 100644 --- a/qcsrc/common/turrets/turret/ewheel.qc +++ b/qcsrc/common/turrets/turret/ewheel.qc @@ -1,16 +1,10 @@ -#ifndef TUR_EWHEEL_H -#define TUR_EWHEEL_H - -CLASS(EWheelAttack, PortoLaunch) -/* flags */ ATTRIB(EWheelAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(EWheelAttack, impulse, int, 5); -/* refname */ ATTRIB(EWheelAttack, netname, string, "turret_ewheel"); -/* wepname */ ATTRIB(EWheelAttack, message, string, _("eWheel")); -ENDCLASS(EWheelAttack) -REGISTER_WEAPON(EWHEEL, NEW(EWheelAttack)); +#ifndef TURRET_EWHEEL_H +#define TURRET_EWHEEL_H //#define EWHEEL_FANCYPATH +#include "ewheel_weapon.qc" + CLASS(EWheel, Turret) /* spawnflags */ ATTRIB(EWheel, spawnflags, int, TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM); /* mins */ ATTRIB(EWheel, mins, vector, '-32 -32 0'); @@ -27,38 +21,10 @@ REGISTER_TURRET(EWHEEL, NEW(EWheel)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -void turret_initparams(entity); -METHOD(EWheelAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - - turret_do_updates(self); - entity missile = turret_projectile(SND(LASERGUN_FIRE), 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_BLASTER, true, true); - missile.missile_flags = MIF_SPLASH; +#include "ewheel_weapon.qc" - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); - - if (!isPlayer) { - self.tur_head.frame += 2; - - if (self.tur_head.frame > 3) - self.tur_head.frame = 0; - } - } - return true; -} +#ifdef SVQC float autocvar_g_turrets_unit_ewheel_speed_fast; float autocvar_g_turrets_unit_ewheel_speed_slow; diff --git a/qcsrc/common/turrets/turret/ewheel_weapon.qc b/qcsrc/common/turrets/turret/ewheel_weapon.qc new file mode 100644 index 0000000000..64b7357715 --- /dev/null +++ b/qcsrc/common/turrets/turret/ewheel_weapon.qc @@ -0,0 +1,52 @@ +#ifndef TURRET_EWHEEL_WEAPON_H +#define TURRET_EWHEEL_WEAPON_H + +CLASS(EWheelAttack, PortoLaunch) +/* flags */ ATTRIB(EWheelAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(EWheelAttack, impulse, int, 5); +/* refname */ ATTRIB(EWheelAttack, netname, string, "turret_ewheel"); +/* wepname */ ATTRIB(EWheelAttack, message, string, _("eWheel")); +ENDCLASS(EWheelAttack) +REGISTER_WEAPON(EWHEEL, NEW(EWheelAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +void turret_initparams(entity); +METHOD(EWheelAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + + turret_do_updates(self); + + entity missile = turret_projectile(SND(LASERGUN_FIRE), 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_BLASTER, true, true); + missile.missile_flags = MIF_SPLASH; + + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + if (!isPlayer) { + self.tur_head.frame += 2; + + if (self.tur_head.frame > 3) + self.tur_head.frame = 0; + } + } + return true; +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/flac.qc b/qcsrc/common/turrets/turret/flac.qc index c600c4fa92..a2de5cac4b 100644 --- a/qcsrc/common/turrets/turret/flac.qc +++ b/qcsrc/common/turrets/turret/flac.qc @@ -1,13 +1,7 @@ -#ifndef TUR_FLAC_H -#define TUR_FLAC_H +#ifndef TURRET_FLAC_H +#define TURRET_FLAC_H -CLASS(FlacAttack, PortoLaunch) -/* flags */ ATTRIB(FlacAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(FlacAttack, impulse, int, 5); -/* refname */ ATTRIB(FlacAttack, netname, string, "turret_flac"); -/* wepname */ ATTRIB(FlacAttack, message, string, _("FLAC")); -ENDCLASS(FlacAttack) -REGISTER_WEAPON(FLAC, NEW(FlacAttack)); +#include "flac_weapon.qc" CLASS(Flac, Turret) /* spawnflags */ ATTRIB(Flac, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_MISSILE); @@ -25,66 +19,21 @@ REGISTER_TURRET(FLAC, NEW(Flac)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -void turret_flac_projectile_think_explode(); -METHOD(FlacAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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.tur_impacttime = 10; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - - turret_tag_fire_update(); - entity proj = turret_projectile(SND(HAGAR_FIRE), 5, 0, DEATH_TURRET_FLAC, PROJECTILE_HAGAR, true, true); - proj.missile_flags = MIF_SPLASH | MIF_PROXY; - proj.think = turret_flac_projectile_think_explode; - proj.nextthink = time + self.tur_impacttime + (random() * 0.01 - random() * 0.01); - Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); +#include "flac_weapon.qc" - if (!isPlayer) { - self.tur_head.frame = self.tur_head.frame + 1; - if (self.tur_head.frame >= 4) - self.tur_head.frame = 0; - } - } - return true; -} +#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); +void spawnfunc_turret_flac() { SELFPARAM(); if (!turret_initialize(TUR_FLAC)) remove(self); } -#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); +METHOD(Flac, tr_setup, void(Flac this, entity it)) +{ + it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + it.damage_flags |= TFL_DMG_HEADSHAKE; + it.target_select_flags |= TFL_TARGETSELECT_NOTURRETS | TFL_TARGETSELECT_MISSILESONLY; } -void spawnfunc_turret_flac() { SELFPARAM(); if(!turret_initialize(TUR_FLAC)) remove(self); } - - METHOD(Flac, tr_setup, void(Flac this, entity it)) - { - it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; - it.damage_flags |= TFL_DMG_HEADSHAKE; - it.target_select_flags |= TFL_TARGETSELECT_NOTURRETS | TFL_TARGETSELECT_MISSILESONLY; - } +#endif -#endif // SVQC #endif diff --git a/qcsrc/common/turrets/turret/flac_weapon.qc b/qcsrc/common/turrets/turret/flac_weapon.qc new file mode 100644 index 0000000000..d0de05730d --- /dev/null +++ b/qcsrc/common/turrets/turret/flac_weapon.qc @@ -0,0 +1,70 @@ +#ifndef TURRET_FLAC_WEAPON_H +#define TURRET_FLAC_WEAPON_H + +CLASS(FlacAttack, PortoLaunch) +/* flags */ ATTRIB(FlacAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(FlacAttack, impulse, int, 5); +/* refname */ ATTRIB(FlacAttack, netname, string, "turret_flac"); +/* wepname */ ATTRIB(FlacAttack, message, string, _("FLAC")); +ENDCLASS(FlacAttack) +REGISTER_WEAPON(FLAC, NEW(FlacAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +void turret_flac_projectile_think_explode(); +METHOD(FlacAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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.tur_impacttime = 10; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + + turret_tag_fire_update(); + + entity proj = turret_projectile(SND(HAGAR_FIRE), 5, 0, DEATH_TURRET_FLAC, PROJECTILE_HAGAR, true, true); + proj.missile_flags = MIF_SPLASH | MIF_PROXY; + proj.think = turret_flac_projectile_think_explode; + proj.nextthink = time + self.tur_impacttime + (random() * 0.01 - random() * 0.01); + Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + if (!isPlayer) { + self.tur_head.frame = self.tur_head.frame + 1; + if (self.tur_head.frame >= 4) + self.tur_head.frame = 0; + } + } + return true; +} + +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 = 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); +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/fusionreactor.qc b/qcsrc/common/turrets/turret/fusionreactor.qc index 671d9a6729..fcd6113779 100644 --- a/qcsrc/common/turrets/turret/fusionreactor.qc +++ b/qcsrc/common/turrets/turret/fusionreactor.qc @@ -1,5 +1,5 @@ -#ifndef TUR_FUSIONREACTOR_H -#define TUR_FUSIONREACTOR_H +#ifndef TURRET_FUSIONREACTOR_H +#define TURRET_FUSIONREACTOR_H CLASS(FusionReactor, Turret) /* spawnflags */ ATTRIB(FusionReactor, spawnflags, int, TUR_FLAG_SUPPORT | TUR_FLAG_AMMOSOURCE); @@ -46,32 +46,32 @@ bool turret_fusionreactor_firecheck() return true; } -void spawnfunc_turret_fusionreactor() { SELFPARAM(); if(!turret_initialize(TUR_FUSIONREACTOR)) remove(self); } - - METHOD(FusionReactor, tr_attack, void(FusionReactor this)) - { - self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max); - vector fl_org = 0.5 * (self.enemy.absmin + self.enemy.absmax); - te_smallflash(fl_org); - } - METHOD(FusionReactor, tr_think, void(FusionReactor thistur)) - { - self.tur_head.avelocity = '0 250 0' * (self.ammo / self.ammo_max); - } - METHOD(FusionReactor, tr_setup, void(FusionReactor this, entity it)) - { - it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE; - it.target_select_flags = TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_OWNTEAM | TFL_TARGETSELECT_RANGELIMITS; - it.firecheck_flags = TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_AMMO_OTHER | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_DEAD; - it.shoot_flags = TFL_SHOOT_HITALLVALID; - it.aim_flags = TFL_AIM_NO; - it.track_flags = TFL_TRACK_NO; - - it.tur_head.scale = 0.75; - it.tur_head.avelocity = '0 50 0'; - - it.turret_firecheckfunc = turret_fusionreactor_firecheck; - } - -#endif // SVQC +void spawnfunc_turret_fusionreactor() { SELFPARAM(); if (!turret_initialize(TUR_FUSIONREACTOR)) remove(self); } + +METHOD(FusionReactor, tr_attack, void(FusionReactor this)) +{ + self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max); + vector fl_org = 0.5 * (self.enemy.absmin + self.enemy.absmax); + te_smallflash(fl_org); +} +METHOD(FusionReactor, tr_think, void(FusionReactor thistur)) +{ + self.tur_head.avelocity = '0 250 0' * (self.ammo / self.ammo_max); +} +METHOD(FusionReactor, tr_setup, void(FusionReactor this, entity it)) +{ + it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE; + it.target_select_flags = TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_OWNTEAM | TFL_TARGETSELECT_RANGELIMITS; + it.firecheck_flags = TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_AMMO_OTHER | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_DEAD; + it.shoot_flags = TFL_SHOOT_HITALLVALID; + it.aim_flags = TFL_AIM_NO; + it.track_flags = TFL_TRACK_NO; + + it.tur_head.scale = 0.75; + it.tur_head.avelocity = '0 50 0'; + + it.turret_firecheckfunc = turret_fusionreactor_firecheck; +} + +#endif #endif diff --git a/qcsrc/common/turrets/turret/hellion.qc b/qcsrc/common/turrets/turret/hellion.qc index e2661442cf..f2c6f7fc91 100644 --- a/qcsrc/common/turrets/turret/hellion.qc +++ b/qcsrc/common/turrets/turret/hellion.qc @@ -1,13 +1,7 @@ -#ifndef TUR_HELLION_H -#define TUR_HELLION_H +#ifndef TURRET_HELLION_H +#define TURRET_HELLION_H -CLASS(HellionAttack, PortoLaunch) -/* flags */ ATTRIB(HellionAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(HellionAttack, impulse, int, 9); -/* refname */ ATTRIB(HellionAttack, netname, string, "turret_hellion"); -/* wepname */ ATTRIB(HellionAttack, message, string, _("Hellion")); -ENDCLASS(HellionAttack) -REGISTER_WEAPON(HELLION, NEW(HellionAttack)); +#include "hellion_weapon.qc" CLASS(Hellion, Turret) /* spawnflags */ ATTRIB(Hellion, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE); @@ -25,124 +19,28 @@ REGISTER_TURRET(HELLION, NEW(Hellion)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -void turret_hellion_missile_think(); -METHOD(HellionAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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_radius = 500; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - if (!isPlayer) { - 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")); - } - - entity 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; - if (!isPlayer) self.tur_head.frame += 1; - } - return true; -} - -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); +#include "hellion_weapon.qc" - 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); +#ifdef SVQC - // Accelerate - self.velocity = newdir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max)); +void spawnfunc_turret_hellion() { SELFPARAM(); if (!turret_initialize(TUR_HELLION)) remove(self); } - if (itime < 0.05) - self.think = turret_projectile_explode; +METHOD(Hellion, tr_think, void(Hellion thistur)) +{ + if (self.tur_head.frame != 0) + self.tur_head.frame += 1; - UpdateCSQCProjectile(self); + if (self.tur_head.frame >= 7) + self.tur_head.frame = 0; +} +METHOD(Hellion, tr_setup, void(Hellion this, entity it)) +{ + it.aim_flags = TFL_AIM_SIMPLE; + it.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK ; + it.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF | TFL_FIRECHECK_AMMO_OWN; + it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; } -void spawnfunc_turret_hellion() { SELFPARAM(); if(!turret_initialize(TUR_HELLION)) remove(self); } - - METHOD(Hellion, tr_think, void(Hellion thistur)) - { - if (self.tur_head.frame != 0) - self.tur_head.frame += 1; - - if (self.tur_head.frame >= 7) - self.tur_head.frame = 0; - } - METHOD(Hellion, tr_setup, void(Hellion this, entity it)) - { - it.aim_flags = TFL_AIM_SIMPLE; - it.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK ; - it.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF | TFL_FIRECHECK_AMMO_OWN; - it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - } - -#endif // SVQC +#endif #endif diff --git a/qcsrc/common/turrets/turret/hellion_weapon.qc b/qcsrc/common/turrets/turret/hellion_weapon.qc new file mode 100644 index 0000000000..c3fe8bc019 --- /dev/null +++ b/qcsrc/common/turrets/turret/hellion_weapon.qc @@ -0,0 +1,120 @@ +#ifndef TURRET_HELLION_WEAPON_H +#define TURRET_HELLION_WEAPON_H + +CLASS(HellionAttack, PortoLaunch) +/* flags */ ATTRIB(HellionAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(HellionAttack, impulse, int, 9); +/* refname */ ATTRIB(HellionAttack, netname, string, "turret_hellion"); +/* wepname */ ATTRIB(HellionAttack, message, string, _("Hellion")); +ENDCLASS(HellionAttack) +REGISTER_WEAPON(HELLION, NEW(HellionAttack)); + +#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(); +METHOD(HellionAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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_radius = 500; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + if (!isPlayer) { + 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")); + } + + entity 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; + if (!isPlayer) self.tur_head.frame += 1; + } + return true; +} + +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); +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/hk.qc b/qcsrc/common/turrets/turret/hk.qc index f659b5e212..0d7dc6dd0a 100644 --- a/qcsrc/common/turrets/turret/hk.qc +++ b/qcsrc/common/turrets/turret/hk.qc @@ -1,13 +1,9 @@ -#ifndef TUR_HK_H -#define TUR_HK_H +#ifndef TURRET_HK_H +#define TURRET_HK_H -CLASS(HunterKillerAttack, PortoLaunch) -/* flags */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(HunterKillerAttack, impulse, int, 9); -/* refname */ ATTRIB(HunterKillerAttack, netname, string, "turret_hk"); -/* wepname */ ATTRIB(HunterKillerAttack, message, string, _("Hunter-Killer")); -ENDCLASS(HunterKillerAttack) -REGISTER_WEAPON(HK, NEW(HunterKillerAttack)); +//#define TURRET_DEBUG_HK + +#include "hk_weapon.qc" CLASS(HunterKiller, Turret) /* spawnflags */ ATTRIB(HunterKiller, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER | TUR_FLAG_RECIEVETARGETS); @@ -25,286 +21,37 @@ REGISTER_TURRET(HK, NEW(HunterKiller)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -void turret_hk_missile_think(); -METHOD(HunterKillerAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - entity 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 (!isPlayer) - if (self.tur_head.frame == 0) - self.tur_head.frame = self.tur_head.frame + 1; - } - return true; -} +#include "hk_weapon.qc" -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 SVQC #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; +void spawnfunc_turret_hk() { SELFPARAM(); if(!turret_initialize(TUR_HK)) remove(self); } - // Team check - if ((e_target.team == self.owner.team) || (self.owner.team == e_target.owner.team)) - return 0; +METHOD(HunterKiller, tr_think, void(HunterKiller thistur)) +{ + if (self.tur_head.frame != 0) + self.tur_head.frame = self.tur_head.frame + 1; - return 1; + if (self.tur_head.frame > 5) + self.tur_head.frame = 0; } -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); +METHOD(HunterKiller, tr_setup, void(HunterKiller this, entity it)) +{ + it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + it.aim_flags = TFL_AIM_SIMPLE; + it.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + it.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF; + it.shoot_flags = TFL_SHOOT_CLEARTARGET; + it.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK; + + it.turret_addtarget = turret_hk_addtarget; } float turret_hk_addtarget(entity e_target,entity e_sender) @@ -321,27 +68,5 @@ float turret_hk_addtarget(entity e_target,entity e_sender) return 0; } -void spawnfunc_turret_hk() { SELFPARAM(); if(!turret_initialize(TUR_HK)) remove(self); } - - METHOD(HunterKiller, tr_think, void(HunterKiller thistur)) - { - 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; - } - METHOD(HunterKiller, tr_setup, void(HunterKiller this, entity it)) - { - it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - it.aim_flags = TFL_AIM_SIMPLE; - it.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - it.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF; - it.shoot_flags = TFL_SHOOT_CLEARTARGET; - it.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK; - - it.turret_addtarget = turret_hk_addtarget; - } - #endif // SVQC #endif diff --git a/qcsrc/common/turrets/turret/hk_weapon.qc b/qcsrc/common/turrets/turret/hk_weapon.qc new file mode 100644 index 0000000000..e3f838f33e --- /dev/null +++ b/qcsrc/common/turrets/turret/hk_weapon.qc @@ -0,0 +1,297 @@ +#ifndef TURRET_HK_WEAPON_H +#define TURRET_HK_WEAPON_H + +CLASS(HunterKillerAttack, PortoLaunch) +/* flags */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(HunterKillerAttack, impulse, int, 9); +/* refname */ ATTRIB(HunterKillerAttack, netname, string, "turret_hk"); +/* wepname */ ATTRIB(HunterKillerAttack, message, string, _("Hunter-Killer")); +ENDCLASS(HunterKillerAttack) +REGISTER_WEAPON(HK, NEW(HunterKillerAttack)); + +#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; + +void turret_hk_missile_think(); +METHOD(HunterKillerAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) +{ + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + entity 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 (!isPlayer) + if (self.tur_head.frame == 0) + self.tur_head.frame = self.tur_head.frame + 1; + } + return true; +} + +bool hk_is_valid_target(entity e_target); +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); +} + +bool 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; +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/machinegun.qc b/qcsrc/common/turrets/turret/machinegun.qc index 336a0f7c8c..8fc1f4251c 100644 --- a/qcsrc/common/turrets/turret/machinegun.qc +++ b/qcsrc/common/turrets/turret/machinegun.qc @@ -1,13 +1,7 @@ -#ifndef TUR_MACHINEGUN_H -#define TUR_MACHINEGUN_H +#ifndef TURRET_MACHINEGUN_H +#define TURRET_MACHINEGUN_H -CLASS(MachineGunTurretAttack, PortoLaunch) -/* flags */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(MachineGunTurretAttack, impulse, int, 9); -/* refname */ ATTRIB(MachineGunTurretAttack, netname, string, "turret_machinegun"); -/* wepname */ ATTRIB(MachineGunTurretAttack, message, string, _("Machinegun")); -ENDCLASS(MachineGunTurretAttack) -REGISTER_WEAPON(TUR_MACHINEGUN, NEW(MachineGunTurretAttack)); +#include "machinegun_weapon.qc" CLASS(MachineGunTurret, Turret) /* spawnflags */ ATTRIB(MachineGunTurret, spawnflags, int, TUR_FLAG_PLAYER); @@ -25,39 +19,21 @@ REGISTER_TURRET(MACHINEGUN, NEW(MachineGunTurret)); #endif #ifdef IMPLEMENTATION + +#include "machinegun_weapon.qc" + #ifdef SVQC -void W_MachineGun_MuzzleFlash(); - -METHOD(MachineGunTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR(machinegun, sustained_refire))) { - if (isPlayer) { - turret_initparams(self); - 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; - weapon_thinkf(WFRAME_FIRE1, 0, w_ready); - } - 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; -} -void spawnfunc_turret_machinegun() { SELFPARAM(); if(!turret_initialize(TUR_MACHINEGUN)) remove(self); } +void spawnfunc_turret_machinegun() { SELFPARAM(); if (!turret_initialize(TUR_MACHINEGUN)) remove(self); } - METHOD(MachineGunTurret, tr_setup, void(MachineGunTurret this, entity it)) - { - it.damage_flags |= TFL_DMG_HEADSHAKE; - it.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - it.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; - it.turret_flags |= TUR_FLAG_HITSCAN; - } +METHOD(MachineGunTurret, tr_setup, void(MachineGunTurret this, entity it)) +{ + it.damage_flags |= TFL_DMG_HEADSHAKE; + it.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + it.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + it.turret_flags |= TUR_FLAG_HITSCAN; +} #endif // SVQC #endif diff --git a/qcsrc/common/turrets/turret/machinegun_weapon.qc b/qcsrc/common/turrets/turret/machinegun_weapon.qc new file mode 100644 index 0000000000..6612ecb804 --- /dev/null +++ b/qcsrc/common/turrets/turret/machinegun_weapon.qc @@ -0,0 +1,43 @@ +#ifndef TURRET_MACHINEGUN_WEAPON_H +#define TURRET_MACHINEGUN_WEAPON_H + +CLASS(MachineGunTurretAttack, PortoLaunch) +/* flags */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(MachineGunTurretAttack, impulse, int, 9); +/* refname */ ATTRIB(MachineGunTurretAttack, netname, string, "turret_machinegun"); +/* wepname */ ATTRIB(MachineGunTurretAttack, message, string, _("Machinegun")); +ENDCLASS(MachineGunTurretAttack) +REGISTER_WEAPON(TUR_MACHINEGUN, NEW(MachineGunTurretAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +void W_MachineGun_MuzzleFlash(); + +METHOD(MachineGunTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) +{ + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR(machinegun, sustained_refire))) { + if (isPlayer) { + turret_initparams(self); + 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; + weapon_thinkf(WFRAME_FIRE1, 0, w_ready); + } + 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; +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/mlrs.qc b/qcsrc/common/turrets/turret/mlrs.qc index 93fd49e1a5..7920c1a02d 100644 --- a/qcsrc/common/turrets/turret/mlrs.qc +++ b/qcsrc/common/turrets/turret/mlrs.qc @@ -1,13 +1,7 @@ -#ifndef TUR_MLRS_H -#define TUR_MLRS_H +#ifndef TURRET_MLRS_H +#define TURRET_MLRS_H -CLASS(MLRSTurretAttack, PortoLaunch) -/* flags */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(MLRSTurretAttack, impulse, int, 9); -/* refname */ ATTRIB(MLRSTurretAttack, netname, string, "turret_mlrs"); -/* wepname */ ATTRIB(MLRSTurretAttack, message, string, _("MLRS")); -ENDCLASS(MLRSTurretAttack) -REGISTER_WEAPON(TUR_MLRS, NEW(MLRSTurretAttack)); +#include "mlrs_weapon.qc" CLASS(MLRSTurret, Turret) /* spawnflags */ ATTRIB(MLRSTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER); @@ -25,51 +19,32 @@ REGISTER_TURRET(MLRS, NEW(MLRSTurret)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -METHOD(MLRSTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR(machinegun, sustained_refire))) { - if (isPlayer) { - turret_initparams(self); - 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_radius = 500; - weapon_thinkf(WFRAME_FIRE1, 0, w_ready); - } - turret_tag_fire_update(); - entity 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; -} -void spawnfunc_turret_mlrs() { SELFPARAM(); if(!turret_initialize(TUR_MLRS)) remove(self); } +#include "mlrs_weapon.qc" - METHOD(MLRSTurret, tr_think, void(MLRSTurret thistur)) - { - // 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"); - } - } - METHOD(MLRSTurret, tr_setup, void(MLRSTurret this, entity it)) - { - it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; - it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; +#ifdef SVQC - it.damage_flags |= TFL_DMG_HEADSHAKE; - it.shoot_flags |= TFL_SHOOT_VOLLYALWAYS; - it.volly_counter = it.shot_volly; - } +void spawnfunc_turret_mlrs() { SELFPARAM(); if (!turret_initialize(TUR_MLRS)) remove(self); } + +METHOD(MLRSTurret, tr_think, void(MLRSTurret thistur)) +{ + // 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"); + } +} +METHOD(MLRSTurret, tr_setup, void(MLRSTurret this, entity it)) +{ + it.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE; + it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + + it.damage_flags |= TFL_DMG_HEADSHAKE; + it.shoot_flags |= TFL_SHOOT_VOLLYALWAYS; + it.volly_counter = it.shot_volly; +} #endif // SVQC #endif diff --git a/qcsrc/common/turrets/turret/mlrs_weapon.qc b/qcsrc/common/turrets/turret/mlrs_weapon.qc new file mode 100644 index 0000000000..70d7f8da75 --- /dev/null +++ b/qcsrc/common/turrets/turret/mlrs_weapon.qc @@ -0,0 +1,44 @@ +#ifndef TURRET_MLRS_WEAPON_H +#define TURRET_MLRS_WEAPON_H + +CLASS(MLRSTurretAttack, PortoLaunch) +/* flags */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(MLRSTurretAttack, impulse, int, 9); +/* refname */ ATTRIB(MLRSTurretAttack, netname, string, "turret_mlrs"); +/* wepname */ ATTRIB(MLRSTurretAttack, message, string, _("MLRS")); +ENDCLASS(MLRSTurretAttack) +REGISTER_WEAPON(TUR_MLRS, NEW(MLRSTurretAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +METHOD(MLRSTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) +{ + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR(machinegun, sustained_refire))) { + if (isPlayer) { + turret_initparams(self); + 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_radius = 500; + weapon_thinkf(WFRAME_FIRE1, 0, w_ready); + } + turret_tag_fire_update(); + entity 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; +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/phaser.qc b/qcsrc/common/turrets/turret/phaser.qc index c7b11cba96..7fcb0131f6 100644 --- a/qcsrc/common/turrets/turret/phaser.qc +++ b/qcsrc/common/turrets/turret/phaser.qc @@ -1,13 +1,7 @@ -#ifndef TUR_PHASER_H -#define TUR_PHASER_H +#ifndef TURRET_PHASER_H +#define TURRET_PHASER_H -CLASS(PhaserTurretAttack, PortoLaunch) -/* flags */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(PhaserTurretAttack, impulse, int, 9); -/* refname */ ATTRIB(PhaserTurretAttack, netname, string, "turret_phaser"); -/* wepname */ ATTRIB(PhaserTurretAttack, message, string, _("Phaser")); -ENDCLASS(PhaserTurretAttack) -REGISTER_WEAPON(PHASER, NEW(PhaserTurretAttack)); +#include "phaser_weapon.qc" CLASS(PhaserTurret, Turret) /* spawnflags */ ATTRIB(PhaserTurret, spawnflags, int, TUR_FLAG_SNIPER | TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER); @@ -25,130 +19,49 @@ REGISTER_TURRET(PHASER, NEW(PhaserTurret)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -void beam_think(); -.int fireflag; -METHOD(PhaserTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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 = 1; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - entity 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 (!isPlayer) - if (self.tur_head.frame == 0) - self.tur_head.frame = 1; - } - return true; -} - -float turret_phaser_firecheck() -{SELFPARAM(); - if (self.fireflag != 0) return 0; - return turret_firecheck(); -} +#include "phaser_weapon.qc" -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; - } +#ifdef SVQC - turret_do_updates(self.owner); +void spawnfunc_turret_phaser() { SELFPARAM(); if (!turret_initialize(TUR_PHASER)) remove(self); } - if (time - self.shot_spread > 0) +METHOD(PhaserTurret, tr_think, void(PhaserTurret thistur)) +{ + if (self.tur_head.frame != 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)) remove(self); } - - METHOD(PhaserTurret, tr_think, void(PhaserTurret thistur)) + if (self.fireflag == 1) { - if (self.tur_head.frame != 0) + 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) { - 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; - } - } + self.tur_head.frame = 0; + self.fireflag = 0; } } - METHOD(PhaserTurret, tr_setup, void(PhaserTurret this, entity it)) - { - it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - it.aim_flags = TFL_AIM_LEAD; + } +} +float turret_phaser_firecheck(); +METHOD(PhaserTurret, tr_setup, void(PhaserTurret this, entity it)) +{ + it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + it.aim_flags = TFL_AIM_LEAD; - it.turret_firecheckfunc = turret_phaser_firecheck; - } + it.turret_firecheckfunc = turret_phaser_firecheck; +} +float turret_phaser_firecheck() +{ + SELFPARAM(); + if (self.fireflag != 0) return 0; + return turret_firecheck(); +} -#endif // SVQC +#endif #endif diff --git a/qcsrc/common/turrets/turret/phaser_weapon.qc b/qcsrc/common/turrets/turret/phaser_weapon.qc new file mode 100644 index 0000000000..ac817703e8 --- /dev/null +++ b/qcsrc/common/turrets/turret/phaser_weapon.qc @@ -0,0 +1,108 @@ +#ifndef TURRET_PHASER_WEAPON_H +#define TURRET_PHASER_WEAPON_H + +CLASS(PhaserTurretAttack, PortoLaunch) +/* flags */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(PhaserTurretAttack, impulse, int, 9); +/* refname */ ATTRIB(PhaserTurretAttack, netname, string, "turret_phaser"); +/* wepname */ ATTRIB(PhaserTurretAttack, message, string, _("Phaser")); +ENDCLASS(PhaserTurretAttack) +REGISTER_WEAPON(PHASER, NEW(PhaserTurretAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC +void beam_think(); + +.int fireflag; + +METHOD(PhaserTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) +{ + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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 = 1; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + entity 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 (!isPlayer) + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; + } + return true; +} + +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; + +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/plasma.qc b/qcsrc/common/turrets/turret/plasma.qc index 1adb456230..04f81cbc0d 100644 --- a/qcsrc/common/turrets/turret/plasma.qc +++ b/qcsrc/common/turrets/turret/plasma.qc @@ -1,13 +1,7 @@ -#ifndef TUR_PLASMA_H -#define TUR_PLASMA_H +#ifndef TURRET_PLASMA_H +#define TURRET_PLASMA_H -CLASS(PlasmaAttack, PortoLaunch) -/* flags */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(PlasmaAttack, impulse, int, 5); -/* refname */ ATTRIB(PlasmaAttack, netname, string, "turret_plasma"); -/* wepname */ ATTRIB(PlasmaAttack, message, string, _("Plasma")); -ENDCLASS(PlasmaAttack) -REGISTER_WEAPON(PLASMA, NEW(PlasmaAttack)); +#include "plasma_weapon.qc" CLASS(PlasmaTurret, Turret) /* spawnflags */ ATTRIB(PlasmaTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER); @@ -25,67 +19,50 @@ REGISTER_TURRET(PLASMA, NEW(PlasmaTurret)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -METHOD(PlasmaAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - 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); - } - return true; -} +#include "plasma_weapon.qc" + +#ifdef SVQC -void spawnfunc_turret_plasma() { SELFPARAM(); if(!turret_initialize(TUR_PLASMA)) remove(self); } +void spawnfunc_turret_plasma() { SELFPARAM(); if (!turret_initialize(TUR_PLASMA)) remove(self); } - METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this)) - { - if(g_instagib) - { - FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, - 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); +METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this)) +{ + if(g_instagib) + { + 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); + 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); - } - else - { - super.tr_attack(this); - } - if (self.tur_head.frame == 0) - self.tur_head.frame = 1; - } - METHOD(PlasmaTurret, tr_think, void(PlasmaTurret thistur)) - { - if (self.tur_head.frame != 0) - self.tur_head.frame = self.tur_head.frame + 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); + } + else + { + super.tr_attack(this); + } + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; +} +METHOD(PlasmaTurret, tr_think, void(PlasmaTurret thistur)) +{ + 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; - } - METHOD(PlasmaTurret, tr_setup, void(PlasmaTurret this, entity it)) - { - it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - it.damage_flags |= TFL_DMG_HEADSHAKE; - it.firecheck_flags |= TFL_FIRECHECK_AFF; - it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; + if (self.tur_head.frame > 5) + self.tur_head.frame = 0; +} +METHOD(PlasmaTurret, tr_setup, void(PlasmaTurret this, entity it)) +{ + it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + it.damage_flags |= TFL_DMG_HEADSHAKE; + it.firecheck_flags |= TFL_FIRECHECK_AFF; + it.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; - turret_do_updates(it); - } + turret_do_updates(it); +} -#endif // SVQC +#endif #endif diff --git a/qcsrc/common/turrets/turret/plasma_dual.qc b/qcsrc/common/turrets/turret/plasma_dual.qc index 98f6243ee0..faac00d26d 100644 --- a/qcsrc/common/turrets/turret/plasma_dual.qc +++ b/qcsrc/common/turrets/turret/plasma_dual.qc @@ -1,5 +1,5 @@ -#ifndef TUR_PLASMA_DUAL_H -#define TUR_PLASMA_DUAL_H +#ifndef TURRET_PLASMA_DUAL_H +#define TURRET_PLASMA_DUAL_H CLASS(PlasmaDualAttack, PlasmaAttack) /* refname */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual"); @@ -26,33 +26,33 @@ REGISTER_TURRET(PLASMA_DUAL, NEW(DualPlasmaTurret)); #ifdef SVQC -void spawnfunc_turret_plasma_dual() { SELFPARAM(); if(!turret_initialize(TUR_PLASMA_DUAL)) remove(self); } +void spawnfunc_turret_plasma_dual() { SELFPARAM(); if (!turret_initialize(TUR_PLASMA_DUAL)) remove(self); } - METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret this)) - { - if (g_instagib) { - FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, - 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); +METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret this)) +{ + if (g_instagib) { + 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); + 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); - } else { - super.vtblbase.tr_attack(this); - } - self.tur_head.frame += 1; - } - METHOD(DualPlasmaTurret, tr_think, void(DualPlasmaTurret thistur)) - { - if ((self.tur_head.frame != 0) && (self.tur_head.frame != 3)) - self.tur_head.frame = self.tur_head.frame + 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); + } else { + super.vtblbase.tr_attack(this); + } + self.tur_head.frame += 1; +} +METHOD(DualPlasmaTurret, tr_think, void(DualPlasmaTurret thistur)) +{ + 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; - } + if (self.tur_head.frame > 6) + self.tur_head.frame = 0; +} -#endif // SVQC +#endif #endif diff --git a/qcsrc/common/turrets/turret/plasma_weapon.qc b/qcsrc/common/turrets/turret/plasma_weapon.qc new file mode 100644 index 0000000000..4fa085173d --- /dev/null +++ b/qcsrc/common/turrets/turret/plasma_weapon.qc @@ -0,0 +1,40 @@ +#ifndef TURRET_PLASMA_WEAPON_H +#define TURRET_PLASMA_WEAPON_H + +CLASS(PlasmaAttack, PortoLaunch) +/* flags */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(PlasmaAttack, impulse, int, 5); +/* refname */ ATTRIB(PlasmaAttack, netname, string, "turret_plasma"); +/* wepname */ ATTRIB(PlasmaAttack, message, string, _("Plasma")); +ENDCLASS(PlasmaAttack) +REGISTER_WEAPON(PLASMA, NEW(PlasmaAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +METHOD(PlasmaAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + 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); + } + return true; +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/tesla.qc b/qcsrc/common/turrets/turret/tesla.qc index 02fcd1f4cc..65733a8cbe 100644 --- a/qcsrc/common/turrets/turret/tesla.qc +++ b/qcsrc/common/turrets/turret/tesla.qc @@ -1,13 +1,7 @@ -#ifndef TUR_TESLA_H -#define TUR_TESLA_H +#ifndef TURRET_TESLA_H +#define TURRET_TESLA_H -CLASS(TeslaCoilTurretAttack, PortoLaunch) -/* flags */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(TeslaCoilTurretAttack, impulse, int, 9); -/* refname */ ATTRIB(TeslaCoilTurretAttack, netname, string, "turret_tesla"); -/* wepname */ ATTRIB(TeslaCoilTurretAttack, message, string, _("Tesla Coil")); -ENDCLASS(TeslaCoilTurretAttack) -REGISTER_WEAPON(TESLA, NEW(TeslaCoilTurretAttack)); +#include "tesla_weapon.qc" CLASS(TeslaCoil, Turret) /* spawnflags */ ATTRIB(TeslaCoil, spawnflags, int, TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE); @@ -25,95 +19,56 @@ REGISTER_TURRET(TESLA, NEW(TeslaCoil)); #endif #ifdef IMPLEMENTATION -#ifdef SVQC -entity toast(entity from, float range, float damage); -METHOD(TeslaCoilTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - - float d = self.shot_dmg; - float r = self.target_range; - entity e = spawn(); - setorigin(e,self.tur_shotorg); - - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - - entity t = toast(e,r,d); - remove(e); - - if (t == NULL) return true; - - self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK; - - self.attack_finished_single = time + self.shot_refire; - for (int 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; -} +#include "tesla_weapon.qc" -entity toast(entity from, float range, float damage) -{SELFPARAM(); - entity e; - entity etarget = world; - float d,dd; - float r; +#ifdef SVQC - dd = range + 1; +void spawnfunc_turret_tesla() { SELFPARAM(); if (!turret_initialize(TUR_TESLA)) remove(self); } - e = findradius(from.origin,range); - while (e) +METHOD(TeslaCoil, tr_think, void(TeslaCoil thistur)) +{ + if(!self.active) { - 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; + self.tur_head.avelocity = '0 0 0'; + return; } - if (etarget) + if(self.ammo < self.shot_dmg) { - te_csqc_lightningarc(from.origin,etarget.origin); - Damage(etarget, self, self, damage, DEATH_TURRET_TESLA, etarget.origin, '0 0 0'); - etarget.railgunhit = 1; + 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); - return etarget; + if(self.attack_finished_single > time) + return; + + 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)); + } +} + +float turret_tesla_firecheck(); +METHOD(TeslaCoil, tr_setup, void(TeslaCoil this, entity it)) +{ + it.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | + TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + + it.turret_firecheckfunc = turret_tesla_firecheck; + it.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | + TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + + it.firecheck_flags = TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AMMO_OWN; + it.shoot_flags = TFL_SHOOT_CUSTOM; + it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + it.aim_flags = TFL_AIM_NO; + it.track_flags = TFL_TRACK_NO; } float turret_tesla_firecheck() @@ -152,50 +107,5 @@ float turret_tesla_firecheck() return 0; } -void spawnfunc_turret_tesla() { SELFPARAM(); if(!turret_initialize(TUR_TESLA)) remove(self); } - - METHOD(TeslaCoil, tr_think, void(TeslaCoil thistur)) - { - if(!self.active) - { - self.tur_head.avelocity = '0 0 0'; - return; - } - - 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; - - 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)); - } - } - METHOD(TeslaCoil, tr_setup, void(TeslaCoil this, entity it)) - { - it.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | - TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - - it.turret_firecheckfunc = turret_tesla_firecheck; - it.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | - TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; - - it.firecheck_flags = TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AMMO_OWN; - it.shoot_flags = TFL_SHOOT_CUSTOM; - it.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; - it.aim_flags = TFL_AIM_NO; - it.track_flags = TFL_TRACK_NO; - } - -#endif // SVQC +#endif #endif diff --git a/qcsrc/common/turrets/turret/tesla_weapon.qc b/qcsrc/common/turrets/turret/tesla_weapon.qc new file mode 100644 index 0000000000..d8f69df8b8 --- /dev/null +++ b/qcsrc/common/turrets/turret/tesla_weapon.qc @@ -0,0 +1,110 @@ +#ifndef TURRET_TESLA_WEAPON_H +#define TURRET_TESLA_WEAPON_H + +CLASS(TeslaCoilTurretAttack, PortoLaunch) +/* flags */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(TeslaCoilTurretAttack, impulse, int, 9); +/* refname */ ATTRIB(TeslaCoilTurretAttack, netname, string, "turret_tesla"); +/* wepname */ ATTRIB(TeslaCoilTurretAttack, message, string, _("Tesla Coil")); +ENDCLASS(TeslaCoilTurretAttack) +REGISTER_WEAPON(TESLA, NEW(TeslaCoilTurretAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +entity toast(entity from, float range, float damage); +METHOD(TeslaCoilTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + + float d = self.shot_dmg; + float r = self.target_range; + entity e = spawn(); + setorigin(e,self.tur_shotorg); + + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK; + + entity t = toast(e,r,d); + remove(e); + + if (t == NULL) return true; + + self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK; + + self.attack_finished_single = time + self.shot_refire; + for (int 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; +} + +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; +} + +#endif + +#endif diff --git a/qcsrc/common/turrets/turret/walker.qc b/qcsrc/common/turrets/turret/walker.qc index 37781fa673..49e93c09d0 100644 --- a/qcsrc/common/turrets/turret/walker.qc +++ b/qcsrc/common/turrets/turret/walker.qc @@ -1,16 +1,10 @@ -#ifndef TUR_WALKER_H -#define TUR_WALKER_H - -CLASS(WalkerTurretAttack, PortoLaunch) -/* flags */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_TYPE_OTHER); -/* impulse */ ATTRIB(WalkerTurretAttack, impulse, int, 5); -/* refname */ ATTRIB(WalkerTurretAttack, netname, string, "turret_walker"); -/* wepname */ ATTRIB(WalkerTurretAttack, message, string, _("Walker")); -ENDCLASS(WalkerTurretAttack) -REGISTER_WEAPON(WALKER, NEW(WalkerTurretAttack)); +#ifndef TURRET_WALKER_H +#define TURRET_WALKER_H //#define WALKER_FANCYPATHING +#include "walker_weapon.qc" + CLASS(WalkerTurret, Turret) /* spawnflags */ ATTRIB(WalkerTurret, spawnflags, int, TUR_FLAG_PLAYER | TUR_FLAG_MOVE); /* mins */ ATTRIB(WalkerTurret, mins, vector, '-70 -70 0'); @@ -27,26 +21,10 @@ REGISTER_TURRET(WALKER, NEW(WalkerTurret)); #endif #ifdef IMPLEMENTATION + +#include "walker_weapon.qc" + #ifdef SVQC -METHOD(WalkerTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { - SELFPARAM(); - bool isPlayer = IS_PLAYER(self); - if (fire1) - if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { - if (isPlayer) { - turret_initparams(self); - 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; - weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); - } - 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; -} float autocvar_g_turrets_unit_walker_melee_damage; float autocvar_g_turrets_unit_walker_melee_force; diff --git a/qcsrc/common/turrets/turret/walker_weapon.qc b/qcsrc/common/turrets/turret/walker_weapon.qc new file mode 100644 index 0000000000..eea7a37384 --- /dev/null +++ b/qcsrc/common/turrets/turret/walker_weapon.qc @@ -0,0 +1,40 @@ +#ifndef TURRET_WALKER_WEAPON_H +#define TURRET_WALKER_WEAPON_H + +CLASS(WalkerTurretAttack, PortoLaunch) +/* flags */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_TYPE_OTHER); +/* impulse */ ATTRIB(WalkerTurretAttack, impulse, int, 5); +/* refname */ ATTRIB(WalkerTurretAttack, netname, string, "turret_walker"); +/* wepname */ ATTRIB(WalkerTurretAttack, message, string, _("Walker")); +ENDCLASS(WalkerTurretAttack) +REGISTER_WEAPON(WALKER, NEW(WalkerTurretAttack)); + +#endif + +#ifdef IMPLEMENTATION + +#ifdef SVQC + +METHOD(WalkerTurretAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) { + SELFPARAM(); + bool isPlayer = IS_PLAYER(self); + if (fire1) + if (!isPlayer || weapon_prepareattack(false, WEP_CVAR_PRI(electro, refire))) { + if (isPlayer) { + turret_initparams(self); + 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; + weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + } + 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; +} + +#endif + +#endif