2 const vector MARINE_MIN = '-16 -16 -30';
3 const vector MARINE_MAX = '16 16 32';
6 string MARINE_MODEL = "models/monsters/marine.zym";
10 float autocvar_g_monster_marine;
11 float autocvar_g_monster_marine_health;
12 float autocvar_g_monster_marine_melee_damage;
13 float autocvar_g_monster_marine_speed_walk;
14 float autocvar_g_monster_marine_speed_run;
15 float autocvar_g_monster_marine_ammo;
16 float autocvar_g_monster_marine_weapon_laser_chance;
17 float autocvar_g_monster_marine_weapon_shotgun_chance;
18 float autocvar_g_monster_marine_weapon_machinegun_chance;
19 float autocvar_g_monster_marine_weapon_rocketlauncher_chance;
20 float autocvar_g_monster_marine_attack_uzi_bullets;
21 float autocvar_g_monster_marine_attack_uzi_damage;
22 float autocvar_g_monster_marine_attack_uzi_force;
23 float autocvar_g_monster_marine_attack_shotgun_damage;
24 float autocvar_g_monster_marine_attack_shotgun_force;
25 float autocvar_g_monster_marine_attack_shotgun_spread;
26 float autocvar_g_monster_marine_attack_shotgun_bullets;
27 float autocvar_g_monster_marine_attack_rocket_damage;
28 float autocvar_g_monster_marine_attack_rocket_edgedamage;
29 float autocvar_g_monster_marine_attack_rocket_radius;
30 float autocvar_g_monster_marine_attack_rocket_force;
31 float autocvar_g_monster_marine_attack_rocket_lifetime;
32 float autocvar_g_monster_marine_attack_rocket_speed;
33 float autocvar_g_monster_marine_attack_laser_damage;
34 float autocvar_g_monster_marine_attack_laser_edgedamage;
35 float autocvar_g_monster_marine_attack_laser_radius;
36 float autocvar_g_monster_marine_attack_laser_force;
39 const float marine_anim_die1 = 0;
40 const float marine_anim_die2 = 1;
41 const float marine_anim_draw = 2;
42 const float marine_anim_duck = 3;
43 const float marine_anim_duckwalk = 4;
44 const float marine_anim_duckjump = 5;
45 const float marine_anim_duckidle = 6;
46 const float marine_anim_idle = 7;
47 const float marine_anim_jump = 8;
48 const float marine_anim_pain1 = 9;
49 const float marine_anim_pain2 = 10;
50 const float marine_anim_shoot = 11;
51 const float marine_anim_taunt = 12;
52 const float marine_anim_run = 13;
53 const float marine_anim_runbackwards = 14;
54 const float marine_anim_strafeleft = 15;
55 const float marine_anim_straferight = 16;
56 const float marine_anim_dead1 = 17;
57 const float marine_anim_dead2 = 18;
58 const float marine_anim_forwardright = 19;
59 const float marine_anim_forwardleft = 20;
60 const float marine_anim_backright = 21;
61 const float marine_anim_backleft = 22;
67 self.think = marine_think;
68 self.nextthink = time + self.ticrate;
70 if(time < self.attack_finished_single)
71 monster_move(0, 0, 0, marine_anim_shoot, marine_anim_shoot, marine_anim_shoot);
73 monster_move(autocvar_g_monster_marine_speed_run, autocvar_g_monster_marine_speed_walk, 50, marine_anim_run, marine_anim_run, marine_anim_idle);
78 self.monster_delayedattack = func_null; // out of ammo, don't keep attacking
80 monsters_setframe(marine_anim_draw);
81 self.attack_finished_single = time + 2;
82 self.currentammo = autocvar_g_monster_marine_ammo;
83 sound (self, CH_SHOTS, "weapons/reload.wav", VOL_BASE, ATTN_LARGE);
88 self.currentammo -= 1;
89 if(self.currentammo <= 0)
95 self.marine_cycles += 1;
97 if(self.marine_cycles > autocvar_g_monster_marine_attack_uzi_bullets)
99 self.monster_delayedattack = func_null;
104 monster_makevectors(self.enemy);
106 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);
107 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);
108 endFireBallisticBullet();
110 self.delay = time + 0.1;
111 self.monster_delayedattack = marine_uzi;
114 void marine_rocket_explode()
116 self.event_damage = func_null;
117 self.takedamage = DAMAGE_NO;
119 pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
120 sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
122 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);
127 void marine_rocket_touch()
131 marine_rocket_explode();
134 void marine_rocket_think()
136 self.nextthink = time;
139 marine_rocket_explode();
144 void marine_rocket_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
149 if(!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
150 return; // g_projectiles_damage says to halt
152 self.health -= damage;
153 self.angles = vectoangles(self.velocity);
156 W_PrepareExplosionByDamage(attacker, marine_rocket_explode);
163 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);
166 missile.owner = missile.realowner = self;
167 missile.classname = "rocket";
168 missile.bot_dodge = TRUE;
169 missile.bot_dodgerating = autocvar_g_monster_marine_attack_rocket_damage * 2; // * 2 because it can be detonated inflight which makes it even more dangerous
171 missile.takedamage = DAMAGE_YES;
173 missile.event_damage = marine_rocket_damage;
174 missile.damagedbycontents = TRUE;
176 missile.movetype = MOVETYPE_FLY;
177 PROJECTILE_MAKETRIGGER(missile);
178 missile.projectiledeathtype = DEATH_MONSTER_MARINE;
179 setsize(missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
181 setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
182 W_SetupProjectileVelocity(missile, autocvar_g_monster_marine_attack_rocket_speed, 0);
183 missile.angles = vectoangles(missile.velocity);
185 missile.touch = marine_rocket_touch;
186 missile.think = marine_rocket_think;
187 missile.nextthink = time;
188 missile.cnt = time + autocvar_g_monster_marine_attack_rocket_lifetime;
189 missile.flags = FL_PROJECTILE;
190 missile.missile_flags = MIF_SPLASH;
192 CSQCProjectile(missile, TRUE, PROJECTILE_ROCKET, FALSE);
195 void marine_shotgun()
198 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);
199 for(sc = 0;sc < autocvar_g_monster_marine_attack_shotgun_bullets;sc = sc + 1)
200 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);
201 endFireBallisticBullet();
204 void marine_laser_touch()
208 self.event_damage = func_null;
209 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);
218 W_SetupShot_Dir(self, v_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_monster_marine_attack_laser_damage);
221 missile.owner = missile.realowner = self;
222 missile.classname = "laserbolt";
223 PROJECTILE_MAKETRIGGER(missile);
224 missile.projectiledeathtype = DEATH_MONSTER_MARINE;
226 setorigin(missile, w_shotorg);
227 setsize(missile, '0 0 0', '0 0 0');
229 W_SETUPPROJECTILEVELOCITY(missile, g_monster_marine_attack_laser);
230 missile.angles = vectoangles(missile.velocity);
231 missile.touch = marine_laser_touch;
233 missile.flags = FL_PROJECTILE;
234 missile.missile_flags = MIF_SPLASH;
235 missile.movetype = MOVETYPE_FLY;
237 missile.think = SUB_Remove;
238 missile.nextthink = time + 5;
240 CSQCProjectile(missile, TRUE, PROJECTILE_LASER, TRUE);
243 float marine_attack(float attack_type)
247 case MONSTER_ATTACK_MELEE:
249 monsters_setframe(marine_anim_shoot);
250 self.attack_finished_single = time + 0.8;
251 monster_melee(self.enemy, autocvar_g_monster_marine_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE);
255 case MONSTER_ATTACK_RANGED:
257 if(self.currentammo <= 0)
264 monsters_setframe(marine_anim_shoot);
265 monster_makevectors(self.enemy);
266 self.marine_cycles = 0;
270 case WEP_ROCKET_LAUNCHER:
272 self.currentammo -= 1;
273 self.attack_finished_single = time + 0.8;
280 self.currentammo -= 1;
281 self.attack_finished_single = time + 0.8;
288 self.attack_finished_single = time + 0.8;
289 self.delay = time + 0.1;
290 self.monster_delayedattack = marine_uzi;
296 self.attack_finished_single = time + 0.8;
312 Monster_CheckDropCvars ("marine");
314 self.think = monster_dead_think;
315 self.nextthink = time + self.ticrate;
316 self.ltime = time + 5;
317 monsters_setframe((random() > 0.5) ? marine_anim_die1 : marine_anim_die2);
319 monster_hook_death(); // for post-death mods
325 self.health = autocvar_g_monster_marine_health;
327 self.damageforcescale = 0.003;
328 self.classname = "monster_marine";
329 self.monster_attackfunc = marine_attack;
330 self.nextthink = time + random() * 0.5 + 0.1;
331 self.think = marine_think;
332 self.currentammo = 3;
333 self.items = (IT_SHELLS | IT_ROCKETS | IT_NAILS);
335 monsters_setframe(marine_anim_draw);
337 monster_setupsounds("marine");
339 setmodel(self, MARINE_MODEL);
341 RandomSelection_Init();
342 RandomSelection_Add(world, WEP_LASER, string_null, autocvar_g_monster_marine_weapon_laser_chance, 1);
343 RandomSelection_Add(world, WEP_SHOTGUN, string_null, autocvar_g_monster_marine_weapon_shotgun_chance, 1);
344 RandomSelection_Add(world, WEP_UZI, string_null, autocvar_g_monster_marine_weapon_machinegun_chance, 1);
345 RandomSelection_Add(world, WEP_ROCKET_LAUNCHER, string_null, autocvar_g_monster_marine_weapon_rocketlauncher_chance, 1);
347 self.weaponentity = spawn();
348 self.weaponentity.movetype = MOVETYPE_NOCLIP;
349 self.weaponentity.team = self.team;
350 self.weaponentity.solid = SOLID_NOT;
351 self.weaponentity.owner = self.weaponentity.realowner = self;
352 setmodel(self.weaponentity, "models/weapons/v_seeker.md3");
353 setattachment(self.weaponentity, self, "bip01 r hand");
355 self.armorvalue = bound(0.5, random(), 1);
356 self.weapon = RandomSelection_chosen_float;
358 monster_hook_spawn(); // for post-spawn mods
361 void spawnfunc_monster_marine()
363 if not(autocvar_g_monster_marine) { remove(self); return; }
365 self.monster_spawnfunc = spawnfunc_monster_marine;
367 if(Monster_CheckAppearFlags(self))
370 precache_model("models/weapons/v_seeker.md3");
371 precache_model(MARINE_MODEL);
373 if not (monster_initialize(
374 "Marine", MONSTER_MARINE,
375 MARINE_MIN, MARINE_MAX,
377 marine_die, marine_spawn))
384 // compatibility with old spawns
385 void spawnfunc_monster_army() { spawnfunc_monster_marine(); }