/* ============================================================================== Teneb coded by Michael Rogers a.k.a Xsniper http://xsniper.virtualave.net/ some code done by iD software This is one of the coolest monsters in the game, was very fun brining him to life! ============================================================================== */ $cd /models/enemies $origin 0 0 24 $base base $skin base $frame idle101 idle102 idle103 idle104 idle105 idle106 idle107 idle108 idle109 idle110 $frame idle111 idle112 idle113 idle114 idle115 idle116 idle117 idle118 idle119 idle120 $frame idle201 idle202 idle203 idle204 idle205 idle206 idle207 idle208 idle209 idle210 $frame idle211 idle212 idle213 idle214 idle215 idle216 idle217 idle218 idle219 idle220 $frame run01 run02 run03 run04 run05 run06 $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 $frame attack301 attack302 attack303 attack304 $frame attack401 attack402 attack403 attack404 $frame attack501 attack502 attack503 attack504 attack505 attack506 attack507 $frame pain101 pain102 pain103 pain104 $frame pain201 pain202 pain203 pain204 pain205 $frame death101 death102 death103 death104 death105 death106 death006 void() teneb_jump1; void() teneb_jump7; void() teneb_idlesound; void() teneb_goinvisible; void() teneb_govisible; /* ============================================================================== teneb ============================================================================== */ /* ============== ChecktenebMelee Returns TRUE if a melee attack would hit right now ============== */ float() ChecktenebMelee = { if (enemy_range == RANGE_MELEE) { // FIXME: check canreach self.attack_state = AS_MELEE; return TRUE; } return FALSE; }; /* ============== ChecktenebJump ============== */ float() ChecktenebJump = { local vector dist; local float d; if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z + 0.75 * self.enemy.size_z) return FALSE; if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z + 0.25 * self.enemy.size_z) return FALSE; dist = self.enemy.origin - self.origin; dist_z = 0; d = vlen(dist); if (d < 100) return FALSE; if (d > 200) { if (random() < 0.9) return FALSE; } return TRUE; }; float() tenebCheckAttack = { local vector vec; // if close enough for slashing, go for it if (ChecktenebMelee ()) { self.attack_state = AS_MELEE; return TRUE; } if (ChecktenebJump ()) { self.attack_state = AS_MISSILE; return TRUE; } return FALSE; }; //=========================================================================== void(float side) teneb_Melee = { local float ldmg; local vector delta; ai_face (); walkmove (self.ideal_yaw, 12); // allow a little closing delta = self.enemy.origin - self.origin; if (vlen(delta) > 100) return; if (!CanDamage (self.enemy, self)) return; sound (self, CHAN_WEAPON, "weapons/demon/clawhit.wav", 1, ATTN_NORM); ldmg = 10 + 5*random(); T_Damage (self.enemy, self, self, ldmg); makevectors (self.angles); }; void() teneb_JumpTouch = { local float ldmg; if (self.health <= 0) return; if (other.takedamage) { if ( vlen(self.velocity) > 400 ) { ldmg = 40 + 10*random(); T_Damage (other, self, self, ldmg); } } if (!checkbottom(self)) { if (self.flags & FL_ONGROUND) { // jump randomly to not get hung up //dprint ("popjump\n"); self.touch = SUB_Null; self.think = teneb_jump1; self.nextthink = time + 0.1; // self.velocity_x = (random() - 0.5) * 600; // self.velocity_y = (random() - 0.5) * 600; // self.velocity_z = 200; // self.flags = self.flags - FL_ONGROUND; } return; // not on ground yet } self.touch = SUB_Null; self.think = teneb_jump7; self.nextthink = time + 0.1; }; //============================================================================ void() teneb_stand1 =[ $idle101, teneb_stand2 ] {ai_stand();teneb_idlesound();}; void() teneb_stand2 =[ $idle102, teneb_stand3 ] {ai_stand();}; void() teneb_stand3 =[ $idle103, teneb_stand4 ] {ai_stand();}; void() teneb_stand4 =[ $idle104, teneb_stand5 ] {ai_stand();}; void() teneb_stand5 =[ $idle105, teneb_stand6 ] {ai_stand();}; void() teneb_stand6 =[ $idle106, teneb_stand7 ] {ai_stand();}; void() teneb_stand7 =[ $idle107, teneb_stand8 ] {ai_stand();}; void() teneb_stand8 =[ $idle108, teneb_stand9 ] {ai_stand();}; void() teneb_stand9 =[ $idle109, teneb_stand10 ] {ai_stand();}; void() teneb_stand10 =[ $idle110, teneb_stand11 ] {ai_stand();}; void() teneb_stand11 =[ $idle111, teneb_stand12 ] {ai_stand();}; void() teneb_stand12 =[ $idle112, teneb_stand13 ] {ai_stand();}; void() teneb_stand13 =[ $idle113, teneb_stand14 ] {ai_stand();}; void() teneb_stand14 =[ $idle104, teneb_stand15 ] {ai_stand();}; void() teneb_stand15 =[ $idle105, teneb_stand16 ] {ai_stand();}; void() teneb_stand16 =[ $idle106, teneb_stand17 ] {ai_stand();}; void() teneb_stand17 =[ $idle107, teneb_stand18 ] {ai_stand();}; void() teneb_stand18 =[ $idle108, teneb_stand19 ] {ai_stand();}; void() teneb_stand19 =[ $idle109, teneb_stand20 ] {ai_stand();}; void() teneb_stand20 =[ $idle120, teneb_stand1 ] {ai_stand();}; //============================================================================ void() teneb_walk1 =[ $walk01, teneb_walk2 ] {ai_walk(8);teneb_idlesound();}; void() teneb_walk2 =[ $walk02, teneb_walk3 ] {ai_walk(6);}; void() teneb_walk3 =[ $walk03, teneb_walk4 ] {ai_walk(6);}; void() teneb_walk4 =[ $walk04, teneb_walk5 ] {ai_walk(7);}; void() teneb_walk5 =[ $walk05, teneb_walk6 ] {ai_walk(4);}; void() teneb_walk6 =[ $walk06, teneb_walk7 ] {ai_walk(6);}; void() teneb_walk7 =[ $walk07, teneb_walk8 ] {ai_walk(10);}; void() teneb_walk8 =[ $walk08, teneb_walk9 ] {ai_walk(10);}; void() teneb_walk9 =[ $walk09, teneb_walk10 ] {ai_walk(4);}; void() teneb_walk10 =[ $walk10, teneb_walk11 ] {ai_walk(6);}; void() teneb_walk11 =[ $walk11, teneb_walk12 ] {ai_walk(10);}; void() teneb_walk12 =[ $walk12, teneb_walk1 ] {ai_walk(10);}; //============================================================================ void() teneb_run1 =[ $run01, teneb_run2 ] {ai_run(20);teneb_idlesound();}; void() teneb_run2 =[ $run02, teneb_run3 ] {ai_run(15);}; void() teneb_run3 =[ $run03, teneb_run4 ] {ai_run(36);}; void() teneb_run4 =[ $run04, teneb_run5 ] {ai_run(20);}; void() teneb_run5 =[ $run05, teneb_run6 ] {ai_run(15);}; void() teneb_run6 =[ $run06, teneb_run1 ] {ai_run(36);}; //============================================================================ void() teneb_jump1 =[ $attack501, teneb_jump2 ] {ai_face();}; void() teneb_jump2 =[ $attack502, teneb_jump3 ] {ai_face();}; void() teneb_jump3 =[ $attack503, teneb_jump4 ] { ai_face(); self.touch = teneb_JumpTouch; makevectors (self.angles); self.origin_z = self.origin_z + 1; self.velocity = v_forward * 600 + '0 0 250'; if (self.flags & FL_ONGROUND) self.flags = self.flags - FL_ONGROUND; }; void() teneb_jump4 =[ $attack504, teneb_jump5 ] {}; void() teneb_jump5 =[ $attack505, teneb_jump6 ] {}; void() teneb_jump6 =[ $attack506, teneb_jump1 ] { self.nextthink = time + 3; // if three seconds pass, assume teneb is stuck and jump again }; void() teneb_jump7 =[ $attack507, teneb_run1 ] {}; //============================================================================ void() teneb_atta1 =[ $attack101, teneb_atta2 ] {ai_charge(20);teneb_govisible();}; void() teneb_atta2 =[ $attack102, teneb_atta3 ] {ai_charge(25);}; void() teneb_atta3 =[ $attack103, teneb_atta4 ] {ai_charge(30);teneb_Melee(200);}; void() teneb_atta4 =[ $attack104, teneb_atta5 ] {ai_charge(25);}; void() teneb_atta5 =[ $attack105, teneb_atta6 ] {ai_charge(20);}; void() teneb_atta6 =[ $attack106, teneb_atta7 ] {ai_charge(30);}; void() teneb_atta7 =[ $attack107, teneb_atta8 ] {ai_charge(25);teneb_Melee(-200);}; void() teneb_atta8 =[ $attack108, teneb_atta9 ] {ai_charge(20);}; void() teneb_atta9 =[ $attack109, teneb_run1 ] {ai_charge(30);teneb_goinvisible();}; //============================================================================ void() teneb_attb1 =[ $attack301, teneb_attb2 ] {ai_charge(20);teneb_govisible();ai_melee();}; void() teneb_attb2 =[ $attack302, teneb_attb3 ] {ai_charge(25);ai_melee();}; void() teneb_attb3 =[ $attack303, teneb_attb4 ] {ai_charge(30);ai_melee();}; void() teneb_attb4 =[ $attack304, teneb_run1 ] {ai_charge(25);ai_melee();teneb_goinvisible();}; //============================================================================ void() teneb_paina1 =[ $pain101, teneb_paina2 ] {}; void() teneb_paina2 =[ $pain102, teneb_paina3 ] {}; void() teneb_paina3 =[ $pain103, teneb_paina4 ] {}; void() teneb_paina4 =[ $pain104, teneb_run1 ] {}; //============================================================================ void() teneb_painb1 =[ $pain201, teneb_painb2 ] {}; void() teneb_painb2 =[ $pain202, teneb_painb3 ] {}; void() teneb_painb3 =[ $pain203, teneb_painb4 ] {}; void() teneb_painb4 =[ $pain204, teneb_painb5 ] {}; void() teneb_painb5 =[ $pain205, teneb_run1 ] {}; void(entity attacker, float damage) teneb_pain = { if (self.touch == teneb_JumpTouch) return; if (self.pain_finished > time) return; self.pain_finished = time + 1; //OUCH THAT HURT! sound (self, CHAN_VOICE, "enemy/teneb/pain1.wav", 1, ATTN_NORM); if (random()*200 > damage) return; // didn't flinch if (random() <= 0.5) teneb_paina1 (); else teneb_painb1 (); }; //============================================================================ void() teneb_die1 =[ $death101, teneb_die2 ] {}; void() teneb_die2 =[ $death102, teneb_die3 ] {}; void() teneb_die3 =[ $death103, teneb_die4 ] {}; void() teneb_die4 =[ $death104, teneb_die5 ] {}; void() teneb_die5 =[ $death105, teneb_die6 ] {}; void() teneb_die6 =[ $death106, teneb_die7 ] {self.solid = SOLID_NOT;}; void() teneb_die7 =[ $death006, teneb_die7 ] {banish_monster();}; void() teneb_die = { //ARG I'M DIEING TELL THE WORLD ABOUT IT! MAKE SOME NOISE BABY! sound (self, CHAN_VOICE, "enemy/teneb/death.wav", 1, ATTN_NORM); //Make sure they can see me die teneb_govisible(); //Just die already! teneb_die1 (); }; //============================================================================ void() teneb_attack = { //TAKE THIS! GRRR I SOUND FEROCIOUS! if (random() <= 0.9) sound (self, CHAN_VOICE, "enemy/teneb/pain2.wav", 1, ATTN_NORM); //Hmm... should I claw him or bite him? if (random() <= 0.7) teneb_atta1(); //I think I'll claw him most of the time! else teneb_attb1(); //Sometimes I like to chew on things... ;) }; void() teneb_missile = { //TAKE THIS! GRRR I SOUND FEROCIOUS! if (random() <= 0.9) sound (self, CHAN_VOICE, "enemy/teneb/pain2.wav", 1, ATTN_NORM); //I'm gonna jump all over him! teneb_jump1(); }; void() teneb_idlesound = { local float r; //make a lot of noise, but not all the time if (random() <= 0.7) { //pick one of three random sounds r = random(); if (r <= 0.33) sound (self, CHAN_VOICE, "enemy/teneb/idle2.wav", 1, ATTN_NORM); else if (r <= 0.66) sound (self, CHAN_VOICE, "enemy/teneb/idle3.wav", 1, ATTN_NORM); else sound (self, CHAN_VOICE, "enemy/teneb/idle4.wav", 1, ATTN_NORM); } }; void() teneb_goinvisible = { //setmodel (self, ""); //setsize (self, '-32 -32 -24', '32 32 64'); self.alpha = set_fade(0.2); }; void() teneb_govisible = { //setmodel (self, "models/enemies/teneb.md2"); //setsize (self, '-32 -32 -24', '32 32 64'); self.alpha = 1; }; //============================================================================ /*QUAKED monster_teneb (1 0 0) (-32 -32 -24) (32 32 64) Ambush */ void() monster_teneb = { if (deathmatch) { remove(self); return; } precache_model ("models/enemies/teneb.md2"); precache_sound ("enemy/teneb/death.wav"); //death sound precache_sound ("enemy/teneb/idle2.wav"); //idle sound precache_sound ("enemy/teneb/idle3.wav"); //idle sound precache_sound ("enemy/teneb/idle4.wav"); //idle sound precache_sound ("enemy/teneb/pain1.wav"); //pain sound precache_sound ("enemy/teneb/pain2.wav"); //attack sound precache_sound ("weapons/demon/clawhit.wav"); //attack sound self.solid = SOLID_SLIDEBOX; self.movetype = MOVETYPE_STEP; setmodel (self, "models/enemies/teneb.md2"); setsize (self, '-32 -32 -24', '32 32 64'); // setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); self.health = set_health(300); self.speed = set_speed(900); self.dtype = 4; //dodge type do nothing self.th_stand = teneb_stand1; self.th_walk = teneb_walk1; self.th_run = teneb_run1; self.th_die = teneb_die; self.th_melee = teneb_attack; self.th_missile = teneb_missile; self.th_pain = teneb_pain; //my new classname is? self.classname = "monster_teneb"; //set up our monflag self.monflag = "TRUE"; //difficulty optimization remove_monster(); //start out invisible teneb_goinvisible(); walkmonster_start(); }; /* ================= create_tenebbot Creates a Teneb at the specified 'spot'. This is used by demon portals in Flood Co-op. ================= */ void(vector spot) create_tenebbot = { 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/teneb.md2"); setsize (bot, '-32 -32 -24', '32 32 64'); bot.flags = bot.flags | FL_MONSTER; bot.takedamage = DAMAGE_AIM; // define his animation bot.th_stand = teneb_stand1; bot.th_walk = teneb_walk1; bot.th_run = teneb_run1; bot.th_die = teneb_die; bot.th_melee = teneb_attack; bot.th_missile = teneb_missile; bot.th_pain = teneb_pain; bot.health = set_health(300); bot.speed = set_speed(900); bot.dtype = 4; //dodge type do nothing // polish him up bot.classname = "monster_teneb"; 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"; //start out invisible bot.alpha = set_fade(0.2); // begin his thinking bot.nextthink = time + 0.1 + random(); bot.think = th_stuck; };