From: Mario Date: Mon, 29 Apr 2013 17:33:00 +0000 (+1000) Subject: Rename grunt to marine X-Git-Tag: xonotic-v0.8.0~241^2^2~262 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=14254f91ef460927f5a590703c90e550b33b02ee;p=xonotic%2Fxonotic-data.pk3dir.git Rename grunt to marine --- diff --git a/models/monsters/marine.zym b/models/monsters/marine.zym new file mode 100644 index 000000000..1615af482 Binary files /dev/null and b/models/monsters/marine.zym differ diff --git a/models/monsters/soldier.zym b/models/monsters/soldier.zym deleted file mode 100644 index 1615af482..000000000 Binary files a/models/monsters/soldier.zym and /dev/null differ diff --git a/monsters.cfg b/monsters.cfg index d14a8bb14..967581040 100644 --- a/monsters.cfg +++ b/monsters.cfg @@ -75,38 +75,38 @@ set g_monster_bruiser_melee_side_damage 10 "Bruiser melee attack side damage" set g_monster_bruiser_speed_walk 40 "Bruiser walk speed" set g_monster_bruiser_speed_run 70 "Bruiser run speed" -// Grunt -set g_monster_soldier 1 "Enable Grunts" -set g_monster_soldier_health 100 "Grunt Health" -set g_monster_soldier_drop ammo "Grunt drops this item on death" -set g_monster_soldier_drop_size shells "Size of the item Grunts drop. Possible values are: small, medium, large" -set g_monster_soldier_melee_damage 20 "Grunt melee attack damage" -set g_monster_soldier_speed_walk 75 "Grunt walk speed" -set g_monster_soldier_speed_run 100 "Grunt run speed" -set g_monster_soldier_ammo 5 "Grunt weapon ammo" -set g_monster_soldier_weapon_laser_chance 6 "Chance of Grunt weapon being laser" -set g_monster_soldier_weapon_shotgun_chance 8 "Chance of Grunt weapon being shotgun" -set g_monster_soldier_weapon_machinegun_chance 4 "Chance of Grunt weapon being machine gun" -set g_monster_soldier_weapon_rocketlauncher_chance 2 "Chance of Grunt weapon being rocket launcher" -set g_monster_soldier_attack_uzi_bullets 3 "Number of machine gun bullets Grunt fires" -set g_monster_soldier_attack_uzi_damage 10 "Grunt machine gun damage per bullet" -set g_monster_soldier_attack_uzi_force 5 "Grunt machine gun knockback" -set g_monster_soldier_attack_shotgun_damage 4 "Grunt shotgun per bullet damage" -set g_monster_soldier_attack_shotgun_spread 0.2 "Grunt shotgun bullet spread" -set g_monster_soldier_attack_shotgun_bullets 12 "Grunt shotgun bullets per shot" -set g_monster_soldier_attack_shotgun_force 5 "Grunt shotgun knockback" -set g_monster_soldier_attack_rocket_damage 50 "Grunt rocket direct hit damage" -set g_monster_soldier_attack_rocket_edgedamage 25 "Grunt rocket indirect hit damage" -set g_monster_soldier_attack_rocket_radius 110 "Grunt rocket explosion radius" -set g_monster_soldier_attack_rocket_force 25 "Grunt rocket knockback" -set g_monster_soldier_attack_rocket_lifetime 5 "Grunt rocket lifetime" -set g_monster_soldier_attack_rocket_speed 2000 "Grunt rocket fly speed" -set g_monster_soldier_attack_laser_damage 15 "Grunt laser damage" -set g_monster_soldier_attack_laser_edgedamage 7 "Grunt laser indirect hit damage" -set g_monster_soldier_attack_laser_radius 50 "Grunt laser damage radius" -set g_monster_soldier_attack_laser_force 300 "Grunt laser knockback" -set g_monster_soldier_attack_laser_speed 2000 "Grunt laser projectile speed" -set g_monster_soldier_attack_laser_spread 0 "Grunt laser projectile spread" +// Marine +set g_monster_marine 1 "Enable Marines" +set g_monster_marine_health 100 "Marine Health" +set g_monster_marine_drop ammo "Marine drops this item on death" +set g_monster_marine_drop_size shells "Size of the item Marines drop. Possible values are: small, medium, large" +set g_monster_marine_melee_damage 20 "Marine melee attack damage" +set g_monster_marine_speed_walk 75 "Marine walk speed" +set g_monster_marine_speed_run 100 "Marine run speed" +set g_monster_marine_ammo 5 "Marine weapon ammo" +set g_monster_marine_weapon_laser_chance 6 "Chance of Marine weapon being laser" +set g_monster_marine_weapon_shotgun_chance 8 "Chance of Marine weapon being shotgun" +set g_monster_marine_weapon_machinegun_chance 4 "Chance of Marine weapon being machine gun" +set g_monster_marine_weapon_rocketlauncher_chance 2 "Chance of Marine weapon being rocket launcher" +set g_monster_marine_attack_uzi_bullets 3 "Number of machine gun bullets Marine fires" +set g_monster_marine_attack_uzi_damage 10 "Marine machine gun damage per bullet" +set g_monster_marine_attack_uzi_force 5 "Marine machine gun knockback" +set g_monster_marine_attack_shotgun_damage 4 "Marine shotgun per bullet damage" +set g_monster_marine_attack_shotgun_spread 0.2 "Marine shotgun bullet spread" +set g_monster_marine_attack_shotgun_bullets 12 "Marine shotgun bullets per shot" +set g_monster_marine_attack_shotgun_force 5 "Marine shotgun knockback" +set g_monster_marine_attack_rocket_damage 50 "Marine rocket direct hit damage" +set g_monster_marine_attack_rocket_edgedamage 25 "Marine rocket indirect hit damage" +set g_monster_marine_attack_rocket_radius 110 "Marine rocket explosion radius" +set g_monster_marine_attack_rocket_force 25 "Marine rocket knockback" +set g_monster_marine_attack_rocket_lifetime 5 "Marine rocket lifetime" +set g_monster_marine_attack_rocket_speed 2000 "Marine rocket fly speed" +set g_monster_marine_attack_laser_damage 15 "Marine laser damage" +set g_monster_marine_attack_laser_edgedamage 7 "Marine laser indirect hit damage" +set g_monster_marine_attack_laser_radius 50 "Marine laser damage radius" +set g_monster_marine_attack_laser_force 300 "Marine laser knockback" +set g_monster_marine_attack_laser_speed 2000 "Marine laser projectile speed" +set g_monster_marine_attack_laser_spread 0 "Marine laser projectile spread" // Wyvern set g_monster_wyvern 1 "Enable Wyverns" diff --git a/qcsrc/client/monsters.qc b/qcsrc/client/monsters.qc index e88116a4e..725c2f057 100644 --- a/qcsrc/client/monsters.qc +++ b/qcsrc/client/monsters.qc @@ -41,7 +41,7 @@ void monster_precache(float _mid) } case MONSTER_MARINE: { - precache_model(SOLDIER_MODEL); + precache_model(MARINE_MODEL); precache_sound("weapons/shotgun_fire.wav"); precache_sound("weapons/uzi_fire.wav"); precache_sound("weapons/laser_fire.wav"); @@ -146,10 +146,10 @@ void monster_mid2info(float _mid) } case MONSTER_MARINE: { - mid2info_model = SOLDIER_MODEL; + mid2info_model = MARINE_MODEL; mid2info_name = "Marine"; - mid2info_min = SOLDIER_MIN; - mid2info_max = SOLDIER_MAX; + mid2info_min = MARINE_MIN; + mid2info_max = MARINE_MAX; break; } case MONSTER_WYVERN: diff --git a/qcsrc/menu/xonotic/dialog_monstertools.c b/qcsrc/menu/xonotic/dialog_monstertools.c index 4fa0227ff..7d5228a1b 100644 --- a/qcsrc/menu/xonotic/dialog_monstertools.c +++ b/qcsrc/menu/xonotic/dialog_monstertools.c @@ -25,7 +25,7 @@ void XonoticMonsterToolsDialog_fill(entity me) me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "bruiser", _("Bruiser"))); me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "knight", _("Knight"))); me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "shambler", _("Shambler"))); - me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "soldier", _("Marine"))); + me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "marine", _("Marine"))); me.TR(me); me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "cerberus", _("Cerberus"))); me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "slime", _("Slime"))); diff --git a/qcsrc/server/monsters/monster/marine.qc b/qcsrc/server/monsters/monster/marine.qc new file mode 100644 index 000000000..6560ae8e4 --- /dev/null +++ b/qcsrc/server/monsters/monster/marine.qc @@ -0,0 +1,387 @@ +// size +const vector MARINE_MIN = '-16 -16 -30'; +const vector MARINE_MAX = '16 16 32'; + +// model +string MARINE_MODEL = "models/monsters/marine.zym"; + +#ifdef SVQC +// cvars +float autocvar_g_monster_marine; +float autocvar_g_monster_marine_health; +float autocvar_g_monster_marine_melee_damage; +float autocvar_g_monster_marine_speed_walk; +float autocvar_g_monster_marine_speed_run; +float autocvar_g_monster_marine_ammo; +float autocvar_g_monster_marine_weapon_laser_chance; +float autocvar_g_monster_marine_weapon_shotgun_chance; +float autocvar_g_monster_marine_weapon_machinegun_chance; +float autocvar_g_monster_marine_weapon_rocketlauncher_chance; +float autocvar_g_monster_marine_attack_uzi_bullets; +float autocvar_g_monster_marine_attack_uzi_damage; +float autocvar_g_monster_marine_attack_uzi_force; +float autocvar_g_monster_marine_attack_shotgun_damage; +float autocvar_g_monster_marine_attack_shotgun_force; +float autocvar_g_monster_marine_attack_shotgun_spread; +float autocvar_g_monster_marine_attack_shotgun_bullets; +float autocvar_g_monster_marine_attack_rocket_damage; +float autocvar_g_monster_marine_attack_rocket_edgedamage; +float autocvar_g_monster_marine_attack_rocket_radius; +float autocvar_g_monster_marine_attack_rocket_force; +float autocvar_g_monster_marine_attack_rocket_lifetime; +float autocvar_g_monster_marine_attack_rocket_speed; +float autocvar_g_monster_marine_attack_laser_damage; +float autocvar_g_monster_marine_attack_laser_edgedamage; +float autocvar_g_monster_marine_attack_laser_radius; +float autocvar_g_monster_marine_attack_laser_force; + +// animations +const float marine_anim_die1 = 0; +const float marine_anim_die2 = 1; +const float marine_anim_draw = 2; +const float marine_anim_duck = 3; +const float marine_anim_duckwalk = 4; +const float marine_anim_duckjump = 5; +const float marine_anim_duckidle = 6; +const float marine_anim_idle = 7; +const float marine_anim_jump = 8; +const float marine_anim_pain1 = 9; +const float marine_anim_pain2 = 10; +const float marine_anim_shoot = 11; +const float marine_anim_taunt = 12; +const float marine_anim_run = 13; +const float marine_anim_runbackwards = 14; +const float marine_anim_strafeleft = 15; +const float marine_anim_straferight = 16; +const float marine_anim_dead1 = 17; +const float marine_anim_dead2 = 18; +const float marine_anim_forwardright = 19; +const float marine_anim_forwardleft = 20; +const float marine_anim_backright = 21; +const float marine_anim_backleft = 22; + +.float marine_cycles; + +void marine_think() +{ + self.think = marine_think; + self.nextthink = time + self.ticrate; + + if(time < self.attack_finished_single) + monster_move(0, 0, 0, marine_anim_shoot, marine_anim_shoot, marine_anim_shoot); + else + monster_move(autocvar_g_monster_marine_speed_run, autocvar_g_monster_marine_speed_walk, 50, marine_anim_run, marine_anim_run, marine_anim_idle); +} + +void marine_reload() +{ + self.monster_delayedattack = func_null; // out of ammo, don't keep attacking + self.delay = -1; + monsters_setframe(marine_anim_draw); + self.attack_finished_single = time + 2; + self.currentammo = autocvar_g_monster_marine_ammo; + sound (self, CH_SHOTS, "weapons/reload.wav", VOL_BASE, ATTN_LARGE); +} + +void marine_uzi() +{ + self.currentammo -= 1; + if(self.currentammo <= 0) + { + marine_reload(); + return; + } + + self.marine_cycles += 1; + + if(self.marine_cycles > autocvar_g_monster_marine_attack_uzi_bullets) + { + self.monster_delayedattack = func_null; + self.delay = -1; + return; + } + + monster_makevectors(self.enemy); + + W_SetupShot(self, autocvar_g_antilag_bullets && 18000 >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, autocvar_g_monster_marine_attack_uzi_damage); + fireBallisticBullet(w_shotorg, w_shotdir, 0.02, 18000, 5, autocvar_g_monster_marine_attack_uzi_damage, autocvar_g_monster_marine_attack_uzi_force, DEATH_MONSTER_MARINE, 0, 1, 115); + endFireBallisticBullet(); + + self.delay = time + 0.1; + self.monster_delayedattack = marine_uzi; +} + +void marine_rocket_explode() +{ + self.event_damage = func_null; + self.takedamage = DAMAGE_NO; + + pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1); + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); + + RadiusDamage(self, self.realowner, autocvar_g_monster_marine_attack_rocket_damage, autocvar_g_monster_marine_attack_rocket_edgedamage, autocvar_g_monster_marine_attack_rocket_radius, world, autocvar_g_monster_marine_attack_rocket_force, self.projectiledeathtype, other); + + remove(self); +} + +void marine_rocket_touch() +{ + PROJECTILE_TOUCH; + + marine_rocket_explode(); +} + +void marine_rocket_think() +{ + self.nextthink = time; + if(time >= self.cnt) + { + marine_rocket_explode(); + return; + } +} + +void marine_rocket_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + if(self.health <= 0) + return; + + if(!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions + return; // g_projectiles_damage says to halt + + self.health -= damage; + self.angles = vectoangles(self.velocity); + + if(self.health <= 0) + W_PrepareExplosionByDamage(attacker, marine_rocket_explode); +} + +void marine_rocket() +{ + entity missile; + + W_SetupShot_ProjectileSize(self, '-3 -3 -3', '3 3 3', FALSE, 5, "weapons/rocket_fire.wav", CH_WEAPON_A, autocvar_g_monster_marine_attack_rocket_damage); + + missile = spawn(); + missile.owner = missile.realowner = self; + missile.classname = "rocket"; + missile.bot_dodge = TRUE; + missile.bot_dodgerating = autocvar_g_monster_marine_attack_rocket_damage * 2; // * 2 because it can be detonated inflight which makes it even more dangerous + + missile.takedamage = DAMAGE_YES; + missile.health = 50; + missile.event_damage = marine_rocket_damage; + missile.damagedbycontents = TRUE; + + missile.movetype = MOVETYPE_FLY; + PROJECTILE_MAKETRIGGER(missile); + missile.projectiledeathtype = DEATH_MONSTER_MARINE; + setsize(missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot + + setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point + W_SetupProjectileVelocity(missile, autocvar_g_monster_marine_attack_rocket_speed, 0); + missile.angles = vectoangles(missile.velocity); + + missile.touch = marine_rocket_touch; + missile.think = marine_rocket_think; + missile.nextthink = time; + missile.cnt = time + autocvar_g_monster_marine_attack_rocket_lifetime; + missile.flags = FL_PROJECTILE; + missile.missile_flags = MIF_SPLASH; + + CSQCProjectile(missile, TRUE, PROJECTILE_ROCKET, FALSE); +} + +void marine_shotgun() +{ + float sc; + W_SetupShot(self, autocvar_g_antilag_bullets && 18000 >= autocvar_g_antilag_bullets, 5, "weapons/shotgun_fire.wav", CH_WEAPON_A, autocvar_g_monster_marine_attack_shotgun_damage * autocvar_g_monster_marine_attack_shotgun_bullets); + for(sc = 0;sc < autocvar_g_monster_marine_attack_shotgun_bullets;sc = sc + 1) + fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_monster_marine_attack_shotgun_spread, 18000, 5, autocvar_g_monster_marine_attack_shotgun_damage, autocvar_g_monster_marine_attack_shotgun_force, DEATH_MONSTER_MARINE, 0, 1, 115); + endFireBallisticBullet(); +} + +void marine_laser_touch() +{ + PROJECTILE_TOUCH; + + self.event_damage = func_null; + RadiusDamage(self, self.realowner, autocvar_g_monster_marine_attack_laser_damage, autocvar_g_monster_marine_attack_laser_edgedamage, autocvar_g_monster_marine_attack_laser_radius, world, autocvar_g_monster_marine_attack_laser_force, self.projectiledeathtype, other); + + remove(self); +} + +void marine_laser() +{ + entity missile; + + W_SetupShot_Dir(self, v_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_monster_marine_attack_laser_damage); + + missile = spawn(); + missile.owner = missile.realowner = self; + missile.classname = "laserbolt"; + PROJECTILE_MAKETRIGGER(missile); + missile.projectiledeathtype = DEATH_MONSTER_MARINE; + + setorigin(missile, w_shotorg); + setsize(missile, '0 0 0', '0 0 0'); + + W_SETUPPROJECTILEVELOCITY(missile, g_monster_marine_attack_laser); + missile.angles = vectoangles(missile.velocity); + missile.touch = marine_laser_touch; + + missile.flags = FL_PROJECTILE; + missile.missile_flags = MIF_SPLASH; + missile.movetype = MOVETYPE_FLY; + + missile.think = SUB_Remove; + missile.nextthink = time + 5; + + CSQCProjectile(missile, TRUE, PROJECTILE_LASER, TRUE); +} + +float marine_attack(float attack_type) +{ + switch(attack_type) + { + case MONSTER_ATTACK_MELEE: + { + monsters_setframe(marine_anim_shoot); + self.attack_finished_single = time + 0.8; + monster_melee(self.enemy, autocvar_g_monster_marine_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE); + + return TRUE; + } + case MONSTER_ATTACK_RANGED: + { + if(self.currentammo <= 0) + { + marine_reload(); + + return FALSE; + } + + monsters_setframe(marine_anim_shoot); + monster_makevectors(self.enemy); + self.marine_cycles = 0; + + switch(self.weapon) + { + case WEP_ROCKET_LAUNCHER: + { + self.currentammo -= 1; + self.attack_finished_single = time + 0.8; + marine_rocket(); + + return TRUE; + } + case WEP_SHOTGUN: + { + self.currentammo -= 1; + self.attack_finished_single = time + 0.8; + marine_shotgun(); + + return TRUE; + } + case WEP_UZI: + { + self.attack_finished_single = time + 0.8; + self.delay = time + 0.1; + self.monster_delayedattack = marine_uzi; + + return TRUE; + } + case WEP_LASER: + { + self.attack_finished_single = time + 0.8; + marine_laser(); + + return TRUE; + } + } + + return FALSE; + } + } + + return FALSE; +} + +void marine_die() +{ + Monster_CheckDropCvars ("marine"); + + self.think = monster_dead_think; + self.nextthink = time + self.ticrate; + self.ltime = time + 5; + monsters_setframe((random() > 0.5) ? marine_anim_die1 : marine_anim_die2); + + monster_hook_death(); // for post-death mods +} + +void marine_spawn() +{ + if not(self.health) + self.health = autocvar_g_monster_marine_health; + + self.damageforcescale = 0.003; + self.classname = "monster_marine"; + self.monster_attackfunc = marine_attack; + self.nextthink = time + random() * 0.5 + 0.1; + self.think = marine_think; + self.currentammo = 3; + self.items = (IT_SHELLS | IT_ROCKETS | IT_NAILS); + + monsters_setframe(marine_anim_draw); + + monster_setupsounds("marine"); + + setmodel(self, MARINE_MODEL); + + RandomSelection_Init(); + RandomSelection_Add(world, WEP_LASER, string_null, autocvar_g_monster_marine_weapon_laser_chance, 1); + RandomSelection_Add(world, WEP_SHOTGUN, string_null, autocvar_g_monster_marine_weapon_shotgun_chance, 1); + RandomSelection_Add(world, WEP_UZI, string_null, autocvar_g_monster_marine_weapon_machinegun_chance, 1); + RandomSelection_Add(world, WEP_ROCKET_LAUNCHER, string_null, autocvar_g_monster_marine_weapon_rocketlauncher_chance, 1); + + self.weaponentity = spawn(); + self.weaponentity.movetype = MOVETYPE_NOCLIP; + self.weaponentity.team = self.team; + self.weaponentity.solid = SOLID_NOT; + self.weaponentity.owner = self.weaponentity.realowner = self; + setmodel(self.weaponentity, "models/weapons/v_seeker.md3"); + setattachment(self.weaponentity, self, "bip01 r hand"); + + self.armorvalue = bound(0.5, random(), 1); + self.weapon = RandomSelection_chosen_float; + + monster_hook_spawn(); // for post-spawn mods +} + +void spawnfunc_monster_marine() +{ + if not(autocvar_g_monster_marine) { remove(self); return; } + + self.monster_spawnfunc = spawnfunc_monster_marine; + + if(Monster_CheckAppearFlags(self)) + return; + + precache_model("models/weapons/v_seeker.md3"); + precache_model(MARINE_MODEL); + + if not (monster_initialize( + "Marine", MONSTER_MARINE, + MARINE_MIN, MARINE_MAX, + FALSE, + marine_die, marine_spawn)) + { + remove(self); + return; + } +} + +// compatibility with old spawns +void spawnfunc_monster_army() { spawnfunc_monster_marine(); } + +#endif // SVQC diff --git a/qcsrc/server/monsters/monster/soldier.qc b/qcsrc/server/monsters/monster/soldier.qc deleted file mode 100644 index dfe7de825..000000000 --- a/qcsrc/server/monsters/monster/soldier.qc +++ /dev/null @@ -1,384 +0,0 @@ -// size -const vector SOLDIER_MIN = '-16 -16 -30'; -const vector SOLDIER_MAX = '16 16 32'; - -// model -string SOLDIER_MODEL = "models/monsters/soldier.zym"; - -#ifdef SVQC -// cvars -float autocvar_g_monster_soldier; -float autocvar_g_monster_soldier_health; -float autocvar_g_monster_soldier_melee_damage; -float autocvar_g_monster_soldier_speed_walk; -float autocvar_g_monster_soldier_speed_run; -float autocvar_g_monster_soldier_ammo; -float autocvar_g_monster_soldier_weapon_laser_chance; -float autocvar_g_monster_soldier_weapon_shotgun_chance; -float autocvar_g_monster_soldier_weapon_machinegun_chance; -float autocvar_g_monster_soldier_weapon_rocketlauncher_chance; -float autocvar_g_monster_soldier_attack_uzi_bullets; -float autocvar_g_monster_soldier_attack_uzi_damage; -float autocvar_g_monster_soldier_attack_uzi_force; -float autocvar_g_monster_soldier_attack_shotgun_damage; -float autocvar_g_monster_soldier_attack_shotgun_force; -float autocvar_g_monster_soldier_attack_shotgun_spread; -float autocvar_g_monster_soldier_attack_shotgun_bullets; -float autocvar_g_monster_soldier_attack_rocket_damage; -float autocvar_g_monster_soldier_attack_rocket_edgedamage; -float autocvar_g_monster_soldier_attack_rocket_radius; -float autocvar_g_monster_soldier_attack_rocket_force; -float autocvar_g_monster_soldier_attack_rocket_lifetime; -float autocvar_g_monster_soldier_attack_rocket_speed; -float autocvar_g_monster_soldier_attack_laser_damage; -float autocvar_g_monster_soldier_attack_laser_edgedamage; -float autocvar_g_monster_soldier_attack_laser_radius; -float autocvar_g_monster_soldier_attack_laser_force; - -// animations -const float soldier_anim_die1 = 0; -const float soldier_anim_die2 = 1; -const float soldier_anim_draw = 2; -const float soldier_anim_duck = 3; -const float soldier_anim_duckwalk = 4; -const float soldier_anim_duckjump = 5; -const float soldier_anim_duckidle = 6; -const float soldier_anim_idle = 7; -const float soldier_anim_jump = 8; -const float soldier_anim_pain1 = 9; -const float soldier_anim_pain2 = 10; -const float soldier_anim_shoot = 11; -const float soldier_anim_taunt = 12; -const float soldier_anim_run = 13; -const float soldier_anim_runbackwards = 14; -const float soldier_anim_strafeleft = 15; -const float soldier_anim_straferight = 16; -const float soldier_anim_dead1 = 17; -const float soldier_anim_dead2 = 18; -const float soldier_anim_forwardright = 19; -const float soldier_anim_forwardleft = 20; -const float soldier_anim_backright = 21; -const float soldier_anim_backleft = 22; - -void soldier_think () -{ - self.think = soldier_think; - self.nextthink = time + self.ticrate; - - if(time < self.attack_finished_single) - monster_move(0, 0, 0, soldier_anim_shoot, soldier_anim_shoot, soldier_anim_shoot); - else - monster_move(autocvar_g_monster_soldier_speed_run, autocvar_g_monster_soldier_speed_walk, 50, soldier_anim_run, soldier_anim_run, soldier_anim_idle); -} - -void soldier_reload () -{ - self.monster_delayedattack = func_null; // out of ammo, don't keep attacking - self.delay = -1; - monsters_setframe(soldier_anim_draw); - self.attack_finished_single = time + 2; - self.currentammo = autocvar_g_monster_soldier_ammo; - sound (self, CH_SHOTS, "weapons/reload.wav", VOL_BASE, ATTN_LARGE); -} - -.float grunt_cycles; -void soldier_uzi_fire () -{ - self.currentammo -= 1; - if(self.currentammo <= 0) - { - soldier_reload(); - return; - } - - self.grunt_cycles += 1; - - if(self.grunt_cycles > autocvar_g_monster_soldier_attack_uzi_bullets) - { - self.monster_delayedattack = func_null; - self.delay = -1; - return; - } - - W_SetupShot (self, autocvar_g_antilag_bullets && 18000 >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, autocvar_g_monster_soldier_attack_uzi_damage); - fireBallisticBullet(w_shotorg, w_shotdir, 0.02, 18000, 5, autocvar_g_monster_soldier_attack_uzi_damage, autocvar_g_monster_soldier_attack_uzi_force, DEATH_MONSTER_MARINE, 0, 1, 115); - endFireBallisticBullet(); - - self.delay = time + 0.1; - self.monster_delayedattack = soldier_uzi_fire; -} - -void soldier_rocket_explode() -{ - self.event_damage = func_null; - self.takedamage = DAMAGE_NO; - - pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1); - sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); - - RadiusDamage (self, self.realowner, autocvar_g_monster_soldier_attack_rocket_damage, autocvar_g_monster_soldier_attack_rocket_edgedamage, autocvar_g_monster_soldier_attack_rocket_radius, world, autocvar_g_monster_soldier_attack_rocket_force, self.projectiledeathtype, other); - - remove (self); -} - -void soldier_rocket_touch() -{ - PROJECTILE_TOUCH; - - soldier_rocket_explode(); -} - -void soldier_rocket_think() -{ - self.nextthink = time; - if (time > self.cnt) - { - soldier_rocket_explode(); - return; - } -} - -void soldier_rocket_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - if (self.health <= 0) - return; - - if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions - return; // g_projectiles_damage says to halt - - self.health -= damage; - self.angles = vectoangles(self.velocity); - - if (self.health <= 0) - W_PrepareExplosionByDamage(attacker, soldier_rocket_explode); -} - -void soldier_rocket_fire() -{ - entity missile; - - W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 5, "weapons/rocket_fire.wav", CH_WEAPON_A, autocvar_g_monster_soldier_attack_rocket_damage); - - missile = spawn(); - missile.owner = missile.realowner = self; - missile.classname = "rocket"; - missile.bot_dodge = TRUE; - missile.bot_dodgerating = autocvar_g_monster_soldier_attack_rocket_damage * 2; // * 2 because it can be detonated inflight which makes it even more dangerous - - missile.takedamage = DAMAGE_YES; - missile.health = 50; - missile.event_damage = soldier_rocket_damage; - missile.damagedbycontents = TRUE; - - missile.movetype = MOVETYPE_FLY; - PROJECTILE_MAKETRIGGER(missile); - missile.projectiledeathtype = DEATH_MONSTER_MARINE; - setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot - - setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point - W_SetupProjectileVelocity(missile, autocvar_g_monster_soldier_attack_rocket_speed, 0); - missile.angles = vectoangles (missile.velocity); - - missile.touch = soldier_rocket_touch; - missile.think = soldier_rocket_think; - missile.nextthink = time; - missile.cnt = time + autocvar_g_monster_soldier_attack_rocket_lifetime; - missile.flags = FL_PROJECTILE; - missile.missile_flags = MIF_SPLASH; - - CSQCProjectile(missile, TRUE, PROJECTILE_ROCKET, FALSE); -} - -void soldier_shotgun_fire() -{ - float sc; - W_SetupShot (self, autocvar_g_antilag_bullets && 18000 >= autocvar_g_antilag_bullets, 5, "weapons/shotgun_fire.wav", CH_WEAPON_A, autocvar_g_monster_soldier_attack_shotgun_damage * autocvar_g_monster_soldier_attack_shotgun_bullets); - for (sc = 0;sc < autocvar_g_monster_soldier_attack_shotgun_bullets;sc = sc + 1) - fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_monster_soldier_attack_shotgun_spread, 18000, 5, autocvar_g_monster_soldier_attack_shotgun_damage, autocvar_g_monster_soldier_attack_shotgun_force, DEATH_MONSTER_MARINE, 0, 1, 115); - endFireBallisticBullet(); -} - -void soldier_laser_touch() -{ - PROJECTILE_TOUCH; - - self.event_damage = func_null; - RadiusDamage (self, self.realowner, autocvar_g_monster_soldier_attack_laser_damage, autocvar_g_monster_soldier_attack_laser_edgedamage, autocvar_g_monster_soldier_attack_laser_radius, world, autocvar_g_monster_soldier_attack_laser_force, self.projectiledeathtype, other); - - remove (self); -} - -void soldier_laser_fire() -{ - entity missile; - - W_SetupShot_Dir(self, v_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_monster_soldier_attack_laser_damage); - - missile = spawn (); - missile.owner = missile.realowner = self; - missile.classname = "laserbolt"; - PROJECTILE_MAKETRIGGER(missile); - missile.projectiledeathtype = DEATH_MONSTER_MARINE; - - setorigin (missile, w_shotorg); - setsize(missile, '0 0 0', '0 0 0'); - - W_SETUPPROJECTILEVELOCITY(missile, g_monster_soldier_attack_laser); - missile.angles = vectoangles(missile.velocity); - missile.touch = soldier_laser_touch; - - missile.flags = FL_PROJECTILE; - missile.missile_flags = MIF_SPLASH; - missile.movetype = MOVETYPE_FLY; - - missile.think = SUB_Remove; - missile.nextthink = time + 5; - - CSQCProjectile(missile, TRUE, PROJECTILE_LASER, TRUE); -} - -float marine_attack(float attack_type) -{ - switch(attack_type) - { - case MONSTER_ATTACK_MELEE: - { - monsters_setframe(soldier_anim_shoot); - self.attack_finished_single = time + 0.8; - monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE); - - return TRUE; - } - case MONSTER_ATTACK_RANGED: - { - if(self.currentammo <= 0) - { - soldier_reload(); - - return FALSE; - } - - monsters_setframe(soldier_anim_shoot); - monster_makevectors(self.enemy); - self.grunt_cycles = 0; - - switch(self.weapon) - { - case WEP_ROCKET_LAUNCHER: - { - self.currentammo -= 1; - self.attack_finished_single = time + 0.8; - soldier_rocket_fire(); - - return TRUE; - } - case WEP_SHOTGUN: - { - self.currentammo -= 1; - self.attack_finished_single = time + 0.8; - soldier_shotgun_fire(); - - return TRUE; - } - case WEP_UZI: - { - self.attack_finished_single = time + 0.8; - self.delay = time + 0.1; - self.monster_delayedattack = soldier_uzi_fire; - - return TRUE; - } - case WEP_LASER: - { - self.attack_finished_single = time + 0.8; - soldier_laser_fire(); - - return TRUE; - } - } - - return FALSE; - } - } - - return FALSE; -} - -void soldier_die() -{ - Monster_CheckDropCvars ("soldier"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe((random() > 0.5) ? soldier_anim_die1 : soldier_anim_die2); - - monster_hook_death(); // for post-death mods -} - -void soldier_spawn () -{ - if not(self.health) - self.health = autocvar_g_monster_soldier_health; - - self.damageforcescale = 0.003; - self.classname = "monster_soldier"; - self.monster_attackfunc = marine_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = soldier_think; - self.currentammo = 3; - self.items = (IT_SHELLS | IT_ROCKETS | IT_NAILS); - - monsters_setframe(soldier_anim_draw); - - monster_setupsounds("soldier"); - - setmodel(self, SOLDIER_MODEL); - - RandomSelection_Init(); - RandomSelection_Add(world, WEP_LASER, string_null, autocvar_g_monster_soldier_weapon_laser_chance, 1); - RandomSelection_Add(world, WEP_SHOTGUN, string_null, autocvar_g_monster_soldier_weapon_shotgun_chance, 1); - RandomSelection_Add(world, WEP_UZI, string_null, autocvar_g_monster_soldier_weapon_machinegun_chance, 1); - RandomSelection_Add(world, WEP_ROCKET_LAUNCHER, string_null, autocvar_g_monster_soldier_weapon_rocketlauncher_chance, 1); - - self.weaponentity = spawn(); - self.weaponentity.movetype = MOVETYPE_NOCLIP; - self.weaponentity.team = self.team; - self.weaponentity.solid = SOLID_NOT; - self.weaponentity.owner = self.weaponentity.realowner = self; - setmodel(self.weaponentity, "models/weapons/v_seeker.md3"); - setattachment(self.weaponentity, self, "bip01 r hand"); - - self.armorvalue = bound(0.5, random(), 1); - self.weapon = RandomSelection_chosen_float; - - monster_hook_spawn(); // for post-spawn mods -} - -void spawnfunc_monster_marine() -{ - if not(autocvar_g_monster_soldier) { remove(self); return; } - - self.monster_spawnfunc = spawnfunc_monster_marine; - - if(Monster_CheckAppearFlags(self)) - return; - - precache_model("models/weapons/v_seeker.md3"); - precache_model(SOLDIER_MODEL); - - if not (monster_initialize( - "Marine", MONSTER_MARINE, - SOLDIER_MIN, SOLDIER_MAX, - FALSE, - soldier_die, soldier_spawn)) - { - remove(self); - return; - } -} - -// compatibility with old spawns -void spawnfunc_monster_army() { spawnfunc_monster_marine(); } - -#endif // SVQC diff --git a/qcsrc/server/monsters/monsters.qh b/qcsrc/server/monsters/monsters.qh index d633c2c9d..aa46643b5 100644 --- a/qcsrc/server/monsters/monsters.qh +++ b/qcsrc/server/monsters/monsters.qh @@ -10,7 +10,7 @@ #include "monster/animus.qc" #include "monster/shambler.qc" #include "monster/bruiser.qc" -#include "monster/soldier.qc" +#include "monster/marine.qc" #include "monster/wyvern.qc" #include "monster/cerberus.qc" #include "monster/slime.qc" diff --git a/qcsrc/server/mutators/gamemode_towerdefense.qc b/qcsrc/server/mutators/gamemode_towerdefense.qc index 79f1c7a3f..d0204ae6e 100644 --- a/qcsrc/server/mutators/gamemode_towerdefense.qc +++ b/qcsrc/server/mutators/gamemode_towerdefense.qc @@ -449,7 +449,7 @@ float RandomMonster() if(n_animuses) RandomSelection_Add(world, MONSTER_ANIMUS, "", 1, 1); if(n_mages) RandomSelection_Add(world, MONSTER_MAGE, "", 1, 1); - if(n_soldiers) RandomSelection_Add(world, MONSTER_MARINE, "", 1, 1); + if(n_marines) RandomSelection_Add(world, MONSTER_MARINE, "", 1, 1); if(n_knights) RandomSelection_Add(world, MONSTER_KNIGHT, "", 1, 1); if(n_zombies) RandomSelection_Add(world, MONSTER_ZOMBIE, "", 1, 1); if(n_spiders) RandomSelection_Add(world, MONSTER_SPIDER, "", 1, 1); @@ -507,7 +507,7 @@ void queue_monsters(float maxmonsters) n_cerberuses = DistributeEvenly_Get(1); n_bruisers = DistributeEvenly_Get(1); n_mages = DistributeEvenly_Get(1); - n_soldiers = DistributeEvenly_Get(1); + n_marines = DistributeEvenly_Get(1); n_knights = DistributeEvenly_Get(1); n_zombies = DistributeEvenly_Get(1); n_spiders = DistributeEvenly_Get(1); @@ -843,7 +843,7 @@ MUTATOR_HOOKFUNCTION(td_MonsterSpawn) case MONSTER_ANIMUS: n_animuses -= 1; break; case MONSTER_SHAMBLER: n_shamblers -= 1; break; case MONSTER_BRUISER: n_bruisers -= 1; break; - case MONSTER_MARINE: n_soldiers -= 1; break; + case MONSTER_MARINE: n_marines -= 1; break; case MONSTER_WYVERN: n_wyverns -= 1; break; case MONSTER_CERBERUS: n_cerberuses -= 1; break; case MONSTER_SLIME: n_slimes -= 1; break; diff --git a/qcsrc/server/mutators/gamemode_towerdefense.qh b/qcsrc/server/mutators/gamemode_towerdefense.qh index 67049fc4c..2086ee60e 100644 --- a/qcsrc/server/mutators/gamemode_towerdefense.qh +++ b/qcsrc/server/mutators/gamemode_towerdefense.qh @@ -1,6 +1,6 @@ // Counters float monster_count, totalmonsters; -float n_bruisers, n_cerberuses, n_ogres, n_shamblers, n_wyverns, n_mages, n_soldiers, n_knights, n_animuses, n_zombies, n_slimes, n_fish, n_spiders; +float n_bruisers, n_cerberuses, n_ogres, n_shamblers, n_wyverns, n_mages, n_marines, n_knights, n_animuses, n_zombies, n_slimes, n_fish, n_spiders; float current_monsters; float waterspawns_count, flyspawns_count; float wave_count, max_waves;