/* ============================================================================== Torment coded by Michael Rogers a.k.a Xsniper http://xsniper.virtualave.net/ some code done by iD software ============================================================================== */ $cd /models/enemies $origin 0 0 24 $base base $skin base $frame idle101 idle102 idle103 idle104 idle105 idle106 idle107 $frame idle201 idle202 idle203 idle204 idle205 idle206 idle207 idle208 idle209 idle210 $frame idle211 idle212 idle213 idle214 idle215 idle216 idle217 idle218 idle219 idle220 $frame idle301 idle302 idle303 idle304 idle305 idle306 $frame run01 run02 run03 run04 run05 run06 run07 run08 $frame walk01 walk02 walk03 walk04 walk05 walk06 walk07 walk08 walk09 walk10 $frame walk11 walk12 $frame attack101 attack102 attack103 attack104 attack105 attack106 attack107 attack108 attack109 $frame attack201 attack202 attack203 attack204 attack205 attack206 attack207 attack208 $frame pain101 pain102 pain103 pain104 $frame pain201 pain202 pain203 pain204 pain205 pain206 $frame pain301 pain302 pain303 pain304 pain305 $frame death101 death102 death103 death104 death105 death106 death107 void() torment_char_a1; void() torment_run1; void() TormentCheckForCharge = { // check for mad charge if (!enemy_vis) return; if (time < self.attack_finished) return; if ( fabs(self.origin_z - self.enemy.origin_z) > 20) return; // too much height change if ( vlen (self.origin - self.enemy.origin) < 80) return; // use regular attack // charge SUB_AttackFinished (2); torment_char_a1 (); }; void() TormentCheckContinueCharge = { if (time > self.attack_finished) { SUB_AttackFinished (3); torment_run1 (); return; // done charging } sound (self, CHAN_WEAPON, "enemy/torment/miss.wav", 1, ATTN_NORM); }; void() HellStaffExplode = { T_RadiusDamage (self, self.owner, 30, world); WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); BecomeExplosion(); }; void() HellStaffTouch = { if (other == self.owner) return; // don't explode on owner if (other.takedamage == DAMAGE_AIM) { //set everything but the world on fire if (other != world && random() <= 0.2) { other.onfire = 1; other.burningtime = time + 2 + random() * 2; other.burninflictor = self.owner; } //lets explode now HellStaffExplode(); return; } sound (self, CHAN_VOICE, "weapons/demon/firehit.wav", 1, ATTN_NORM); // bounce sound if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; /* ================ HellStaff Hurls multiple fireballs down on enemy from the sky ================ */ void() HellStaff = { local entity missile; local float r; //set random variable r = random(); self.effects = self.effects | EF_MUZZLEFLASH; missile = spawn (); missile.owner = self; missile.movetype = MOVETYPE_BOUNCE; missile.solid = SOLID_BBOX; // set missile speed makevectors (self.v_angle); missile.velocity = normalize(self.enemy.origin - self.origin); missile.velocity = missile.velocity * 500; missile.velocity_z = missile.velocity_z + 200 + (r * 100); //give a little random boost missile.avelocity = '300 300 300'; missile.angles = vectoangles(missile.velocity); missile.touch = HellStaffTouch; // set missile duration missile.nextthink = time + 2.5; missile.think = HellStaffExplode; setmodel (missile, "progs/flame2.mdl"); missile.frame = 1; missile.glow_size = 100; missile.glow_red = 1; missile.glow_green = 0.5; missile.glow_blue = 0; setsize (missile, '0 0 0', '0 0 0'); // random amount to the left or right r = random(); if (random() <= 0.5) { //either r * 10 or r * 25 if (random() <= 0.5) setorigin (missile, self.origin + (v_right * (r * 10)) + '0 0 10'); else setorigin (missile, self.origin + (v_right * (r * 25)) + '0 0 10'); } else { //either r * 10 or r * 25 if (random() <= 0.5) setorigin (missile, self.origin - (v_right * (r * 10)) + '0 0 10'); else setorigin (missile, self.origin - (v_right * (r * 25)) + '0 0 10'); } //make hellstaff sound sound (self, CHAN_WEAPON, "weapons/demon/hellstafffire.wav", 1, ATTN_NORM); }; //=========================================================================== void() torment_stand1 =[ $idle101, torment_stand2 ] {ai_stand();}; void() torment_stand2 =[ $idle102, torment_stand3 ] {ai_stand();}; void() torment_stand3 =[ $idle103, torment_stand4 ] {ai_stand();}; void() torment_stand4 =[ $idle104, torment_stand5 ] {ai_stand();}; void() torment_stand5 =[ $idle105, torment_stand6 ] {ai_stand();}; void() torment_stand6 =[ $idle106, torment_stand7 ] {ai_stand();}; void() torment_stand7 =[ $idle107, torment_stand1 ] {ai_stand();}; //=========================================================================== void() torment_walk1 =[ $walk01, torment_walk2 ] {ai_walk(2);}; void() torment_walk2 =[ $walk02, torment_walk3 ] {ai_walk(5);}; void() torment_walk3 =[ $walk03, torment_walk4 ] {ai_walk(5);}; void() torment_walk4 =[ $walk04, torment_walk5 ] {ai_walk(4);}; void() torment_walk5 =[ $walk05, torment_walk6 ] {ai_walk(4);}; void() torment_walk6 =[ $walk06, torment_walk7 ] {ai_walk(2);}; void() torment_walk7 =[ $walk07, torment_walk8 ] {ai_walk(2);}; void() torment_walk8 =[ $walk08, torment_walk9 ] {ai_walk(3);}; void() torment_walk9 =[ $walk09, torment_walk10 ] {ai_walk(3);}; void() torment_walk10 =[ $walk10, torment_walk11 ] {ai_walk(4);}; void() torment_walk11 =[ $walk11, torment_walk12 ] {ai_walk(3);}; void() torment_walk12 =[ $walk12, torment_walk1 ] {ai_walk(2);}; //=========================================================================== void() torment_run1 =[ $run01, torment_run2 ] { ai_run(20); TormentCheckForCharge(); }; void() torment_run2 =[ $run02, torment_run3 ] {ai_run(25);}; void() torment_run3 =[ $run03, torment_run4 ] {ai_run(18);}; void() torment_run4 =[ $run04, torment_run5 ] {ai_run(16);}; void() torment_run5 =[ $run05, torment_run6 ] {ai_run(14);}; void() torment_run6 =[ $run06, torment_run7 ] {ai_run(13);}; void() torment_run7 =[ $run07, torment_run8 ] {ai_run(14);}; void() torment_run8 =[ $run08, torment_run1 ] {ai_run(13);}; //============================================================================ void() torment_pain1 =[ $pain101, torment_pain2 ] {}; void() torment_pain2 =[ $pain102, torment_pain3 ] {}; void() torment_pain3 =[ $pain103, torment_pain4 ] {}; void() torment_pain4 =[ $pain104, torment_run1 ] {}; //============================================================================ void() torment_die1 =[ $death101, torment_die2 ] {}; void() torment_die2 =[ $death102, torment_die3 ] {}; void() torment_die3 =[ $death103, torment_die4 ] {self.solid = SOLID_NOT;}; void() torment_die4 =[ $death104, torment_die5 ] {}; void() torment_die5 =[ $death105, torment_die6 ] {}; void() torment_die6 =[ $death106, torment_die7 ] {}; void() torment_die7 =[ $death107, torment_die7 ] {banish_monster();}; void() torment_die = { // regular death if (random() <=0.5) sound (self, CHAN_VOICE, "enemy/torment/death1.wav", 1, ATTN_NORM); else sound (self, CHAN_VOICE, "enemy/torment/death2.wav", 1, ATTN_NORM); torment_die1 (); }; //============================================================================ void() torment_char_a1 =[ $run01, torment_char_a2 ] {ai_charge(20);}; void() torment_char_a2 =[ $run02, torment_char_a3 ] {ai_charge(20);}; void() torment_char_a3 =[ $run03, torment_char_a4 ] {ai_charge(21);}; void() torment_char_a4 =[ $run04, torment_char_a5 ] {ai_charge(13);}; void() torment_char_a5 =[ $run05, torment_char_a6 ] {ai_charge(20);}; void() torment_char_a6 =[ $run06, torment_char_a7 ] {ai_charge(13);}; void() torment_char_a7 =[ $run07, torment_char_a8 ] {ai_charge(20);}; void() torment_char_a8 =[ $run08, torment_run1 ] {ai_charge(13);}; //=========================================================================== void() torment_char_b1 =[ $run01, torment_char_b2 ] {TormentCheckContinueCharge();ai_charge(23);}; void() torment_char_b2 =[ $run02, torment_char_b3 ] {ai_charge(17);}; void() torment_char_b3 =[ $run03, torment_char_b4 ] {ai_charge(12);}; void() torment_char_b4 =[ $run04, torment_char_b5 ] {ai_charge(22);}; void() torment_char_b5 =[ $run05, torment_char_b6 ] {ai_charge(18);}; void() torment_char_b6 =[ $run06, torment_char_b7 ] {ai_charge(22);}; void() torment_char_b7 =[ $run07, torment_char_b8 ] {ai_charge(18);}; void() torment_char_b8 =[ $run08, torment_char_b1 ] {ai_charge(8);}; //=========================================================================== void() torment_watk1 =[ $attack101, torment_watk2 ] {ai_charge(9);}; void() torment_watk2 =[ $attack102, torment_watk3 ] {ai_charge(7);}; void() torment_watk3 =[ $attack103, torment_watk4 ] {ai_charge(15);ai_melee();}; void() torment_watk4 =[ $attack104, torment_watk5 ] {ai_charge(8);ai_melee();}; void() torment_watk5 =[ $attack105, torment_watk6 ] {ai_charge(2);ai_melee();}; void() torment_watk6 =[ $attack106, torment_watk7 ] {ai_face();ai_melee();}; void() torment_watk7 =[ $attack107, torment_watk8 ] {ai_face();}; void() torment_watk8 =[ $attack108, torment_watk9 ] {ai_face();}; void() torment_watk9 =[ $attack109, torment_run1 ] {ai_face();}; //=========================================================================== void() torment_hellstaff1 =[ $attack201, torment_hellstaff2 ] {ai_face();HellStaff();}; void() torment_hellstaff2 =[ $attack202, torment_hellstaff3 ] {ai_face();HellStaff();}; void() torment_hellstaff3 =[ $attack203, torment_hellstaff4 ] {ai_face();HellStaff();}; void() torment_hellstaff4 =[ $attack204, torment_hellstaff5 ] {ai_face();HellStaff();}; void() torment_hellstaff5 =[ $attack205, torment_hellstaff6 ] {ai_face();HellStaff();}; void() torment_hellstaff6 =[ $attack206, torment_hellstaff7 ] {ai_face();HellStaff();}; void() torment_hellstaff7 =[ $attack207, torment_hellstaff8 ] {ai_face();HellStaff();}; void() torment_hellstaff8 =[ $attack208, torment_run1 ] {ai_face();HellStaff();}; //=========================================================================== void(entity attacker, float damage) torment_pain = { local float r; r = random(); if (self.pain_finished > time) return; if (r <= 0.3) sound (self, CHAN_VOICE, "enemy/torment/pain1.wav", 1, ATTN_NORM); else if (r <= 0.6) sound (self, CHAN_VOICE, "enemy/torment/pain2.wav", 1, ATTN_NORM); else sound (self, CHAN_VOICE, "enemy/torment/pain3.wav", 1, ATTN_NORM); if (time - self.pain_finished > 5) { // allways go into pain frame if it has been a while torment_pain1 (); self.pain_finished = time + 1; return; } if ((random()*30 > damage) ) return; // didn't flinch self.pain_finished = time + 1; torment_pain1 (); }; void() torment_melee = { sound (self, CHAN_WEAPON, "enemy/torment/miss.wav", 1, ATTN_NORM); torment_watk1 (); }; void() torment_missile = { //Torment shouldnt rely on Hell Staff attack too much //if (random() <= 0.5) torment_hellstaff1 (); }; void() torment_precache = { //torment graphics precache_model ("models/enemies/torment.md2"); precache_model ("progs/flame2.mdl"); //torment sounds precache_sound ("enemy/torment/alert.wav"); precache_sound ("enemy/torment/attack.wav"); precache_sound ("enemy/torment/death1.wav"); precache_sound ("enemy/torment/death2.wav"); precache_sound ("enemy/torment/miss.wav"); precache_sound ("enemy/torment/pain1.wav"); precache_sound ("enemy/torment/pain2.wav"); precache_sound ("enemy/torment/pain3.wav"); precache_sound ("weapons/demon/firehit.wav"); precache_sound ("weapons/demon/hellstafffire.wav"); precache_sound ("weapons/lock4.wav"); //used for missile touch function }; /*EWED monster_torment (1 0 0) (-16 -16 -24) (16 16 40) Ambush */ void() monster_torment = { if (deathmatch) { remove(self); return; } //if we are put in the level directly then call torment_precache if (self.classname != "monster_hell_knight") torment_precache(); self.solid = SOLID_SLIDEBOX; self.movetype = MOVETYPE_STEP; setmodel (self, "models/enemies/torment.md2"); setsize (self, '-16 -16 -24', '16 16 40'); // setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); self.health = set_health(175); self.speed = set_speed(300); self.dtype = 1; //dodge type back_strafe self.alpha = 1; //we aren't transparent self.th_stand = torment_stand1; self.th_walk = torment_walk1; self.th_run = torment_run1; self.th_melee = torment_melee; self.th_missile = torment_missile; self.th_pain = torment_pain; self.th_die = torment_die; //my new classname is? self.classname = "monster_torment"; //set up our monflag self.monflag = "TRUE"; walkmonster_start (); }; /* ================= create_tormentbot Creates a Torment at the specified 'spot'. This is used by demon portals in Flood Co-op. ================= */ void(vector spot) create_tormentbot = { local entity bot; // start entity and place it in world bot = spawn(); bot.angles = self.angles; setorigin (bot, spot); bot.fixangle = TRUE; spawn_tfog (bot.origin); spawn_tdeath (bot.origin, bot); // set size and shape bot.solid = SOLID_SLIDEBOX; bot.movetype = MOVETYPE_STEP; setmodel (bot, "models/enemies/torment.md2"); setsize (bot, '-16 -16 -24', '16 16 40'); bot.flags = bot.flags | FL_MONSTER; bot.takedamage = DAMAGE_AIM; // define his animation bot.th_stand = torment_stand1; bot.th_walk = torment_walk1; bot.th_run = torment_run1; bot.th_melee = torment_melee; bot.th_missile = torment_missile; bot.th_pain = torment_pain; bot.th_die = torment_die; bot.health = set_health(175); bot.speed = set_speed(300); bot.dtype = 1; //dodge type back_strafe bot.alpha = 1; //we aren't transparent // polish him up bot.classname = "monster_torment"; bot.ideal_yaw = bot.angles * '0 1 0'; bot.yaw_speed = 120; bot.view_ofs = '0 0 22'; //set up our monflag bot.monflag = "TRUE"; // begin his thinking bot.nextthink = time + 0.1 + random(); bot.think = th_stuck; };