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"
}
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");
}
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:
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")));
--- /dev/null
+// 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
+++ /dev/null
-// 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
#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"
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);
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);
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;
// 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;