1/* 2============================================================================== 3 4DEMON 5 6============================================================================== 7*/ 8 9$cd /raid/quake/id1/models/demon3 10$scale 0.8 11$origin 0 0 24 12$base base 13$skin base 14 15$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 16$frame stand10 stand11 stand12 stand13 17 18$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 19 20$frame run1 run2 run3 run4 run5 run6 21 22$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9 leap10 23$frame leap11 leap12 24 25$frame pain1 pain2 pain3 pain4 pain5 pain6 26 27$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 28 29$frame attacka1 attacka2 attacka3 attacka4 attacka5 attacka6 attacka7 attacka8 30$frame attacka9 attacka10 attacka11 attacka12 attacka13 attacka14 attacka15 31 32//============================================================================ 33 34void() Demon_JumpTouch; 35 36void() demon1_stand1 =[ $stand1, demon1_stand2 ] {ai_stand();}; 37void() demon1_stand2 =[ $stand2, demon1_stand3 ] {ai_stand();}; 38void() demon1_stand3 =[ $stand3, demon1_stand4 ] {ai_stand();}; 39void() demon1_stand4 =[ $stand4, demon1_stand5 ] {ai_stand();}; 40void() demon1_stand5 =[ $stand5, demon1_stand6 ] {ai_stand();}; 41void() demon1_stand6 =[ $stand6, demon1_stand7 ] {ai_stand();}; 42void() demon1_stand7 =[ $stand7, demon1_stand8 ] {ai_stand();}; 43void() demon1_stand8 =[ $stand8, demon1_stand9 ] {ai_stand();}; 44void() demon1_stand9 =[ $stand9, demon1_stand10 ] {ai_stand();}; 45void() demon1_stand10 =[ $stand10, demon1_stand11 ] {ai_stand();}; 46void() demon1_stand11 =[ $stand11, demon1_stand12 ] {ai_stand();}; 47void() demon1_stand12 =[ $stand12, demon1_stand13 ] {ai_stand();}; 48void() demon1_stand13 =[ $stand13, demon1_stand1 ] {ai_stand();}; 49 50void() demon1_walk1 =[ $walk1, demon1_walk2 ] { 51if (random() < 0.2) 52 sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE); 53ai_walk(8); 54}; 55void() demon1_walk2 =[ $walk2, demon1_walk3 ] {ai_walk(6);}; 56void() demon1_walk3 =[ $walk3, demon1_walk4 ] {ai_walk(6);}; 57void() demon1_walk4 =[ $walk4, demon1_walk5 ] {ai_walk(7);}; 58void() demon1_walk5 =[ $walk5, demon1_walk6 ] {ai_walk(4);}; 59void() demon1_walk6 =[ $walk6, demon1_walk7 ] {ai_walk(6);}; 60void() demon1_walk7 =[ $walk7, demon1_walk8 ] {ai_walk(10);}; 61void() demon1_walk8 =[ $walk8, demon1_walk1 ] {ai_walk(10);}; 62 63void() demon1_run1 =[ $run1, demon1_run2 ] { 64if (random() < 0.2) 65 sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE); 66ai_run(20);}; 67void() demon1_run2 =[ $run2, demon1_run3 ] {ai_run(15);}; 68void() demon1_run3 =[ $run3, demon1_run4 ] {ai_run(36);}; 69void() demon1_run4 =[ $run4, demon1_run5 ] {ai_run(20);}; 70void() demon1_run5 =[ $run5, demon1_run6 ] {ai_run(15);}; 71void() demon1_run6 =[ $run6, demon1_run1 ] {ai_run(36);}; 72 73void() demon1_jump1 =[ $leap1, demon1_jump2 ] {ai_face();}; 74void() demon1_jump2 =[ $leap2, demon1_jump3 ] {ai_face();}; 75void() demon1_jump3 =[ $leap3, demon1_jump4 ] {ai_face();}; 76void() demon1_jump4 =[ $leap4, demon1_jump5 ] 77{ 78 ai_face(); 79 80 self.touch = Demon_JumpTouch; 81 makevectors (self.angles); 82 self.origin_z = self.origin_z + 1; 83 self.velocity = v_forward * 600 + '0 0 250'; 84 if (self.flags & FL_ONGROUND) 85 self.flags = self.flags - FL_ONGROUND; 86}; 87void() demon1_jump5 =[ $leap5, demon1_jump6 ] {}; 88void() demon1_jump6 =[ $leap6, demon1_jump7 ] {}; 89void() demon1_jump7 =[ $leap7, demon1_jump8 ] {}; 90void() demon1_jump8 =[ $leap8, demon1_jump9 ] {}; 91void() demon1_jump9 =[ $leap9, demon1_jump10 ] {}; 92void() demon1_jump10 =[ $leap10, demon1_jump1 ] { 93self.nextthink = time + 3; 94// if three seconds pass, assume demon is stuck and jump again 95}; 96 97void() demon1_jump11 =[ $leap11, demon1_jump12 ] {}; 98void() demon1_jump12 =[ $leap12, demon1_run1 ] {}; 99 100 101void() demon1_atta1 =[ $attacka1, demon1_atta2 ] {ai_charge(4);}; 102void() demon1_atta2 =[ $attacka2, demon1_atta3 ] {ai_charge(0);}; 103void() demon1_atta3 =[ $attacka3, demon1_atta4 ] {ai_charge(0);}; 104void() demon1_atta4 =[ $attacka4, demon1_atta5 ] {ai_charge(1);}; 105void() demon1_atta5 =[ $attacka5, demon1_atta6 ] {ai_charge(2); Demon_Melee(200);}; 106void() demon1_atta6 =[ $attacka6, demon1_atta7 ] {ai_charge(1);}; 107void() demon1_atta7 =[ $attacka7, demon1_atta8 ] {ai_charge(6);}; 108void() demon1_atta8 =[ $attacka8, demon1_atta9 ] {ai_charge(8);}; 109void() demon1_atta9 =[ $attacka9, demon1_atta10] {ai_charge(4);}; 110void() demon1_atta10 =[ $attacka10, demon1_atta11] {ai_charge(2);}; 111void() demon1_atta11 =[ $attacka11, demon1_atta12] {Demon_Melee(-200);}; 112void() demon1_atta12 =[ $attacka12, demon1_atta13] {ai_charge(5);}; 113void() demon1_atta13 =[ $attacka13, demon1_atta14] {ai_charge(8);}; 114void() demon1_atta14 =[ $attacka14, demon1_atta15] {ai_charge(4);}; 115void() demon1_atta15 =[ $attacka15, demon1_run1] {ai_charge(4);}; 116 117void() demon1_pain1 =[ $pain1, demon1_pain2 ] {}; 118void() demon1_pain2 =[ $pain2, demon1_pain3 ] {}; 119void() demon1_pain3 =[ $pain3, demon1_pain4 ] {}; 120void() demon1_pain4 =[ $pain4, demon1_pain5 ] {}; 121void() demon1_pain5 =[ $pain5, demon1_pain6 ] {}; 122void() demon1_pain6 =[ $pain6, demon1_run1 ] {}; 123 124void(entity attacker, float damage) demon1_pain = 125{ 126 if (self.touch == Demon_JumpTouch) 127 return; 128 129 if (self.pain_finished > time) 130 return; 131 132 self.pain_finished = time + 1; 133 sound (self, CHAN_VOICE, "demon/dpain1.wav", 1, ATTN_NORM); 134 135 if (random()*200 > damage) 136 return; // didn't flinch 137 138 demon1_pain1 (); 139}; 140 141void() demon1_die1 =[ $death1, demon1_die2 ] { 142sound (self, CHAN_VOICE, "demon/ddeath.wav", 1, ATTN_NORM);}; 143void() demon1_die2 =[ $death2, demon1_die3 ] {}; 144void() demon1_die3 =[ $death3, demon1_die4 ] {}; 145void() demon1_die4 =[ $death4, demon1_die5 ] {}; 146void() demon1_die5 =[ $death5, demon1_die6 ] {}; 147void() demon1_die6 =[ $death6, demon1_die7 ] 148{self.solid = SOLID_NOT;}; 149void() demon1_die7 =[ $death7, demon1_die8 ] {}; 150void() demon1_die8 =[ $death8, demon1_die9 ] {}; 151void() demon1_die9 =[ $death9, demon1_die9 ] {}; 152 153void() demon_die = 154{ 155// check for gib 156 if (self.health < -80) 157 { 158 sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); 159 ThrowHead ("progs/h_demon.mdl", self.health); 160 ThrowGib ("progs/gib1.mdl", self.health); 161 ThrowGib ("progs/gib1.mdl", self.health); 162 ThrowGib ("progs/gib1.mdl", self.health); 163 return; 164 } 165 166// regular death 167 demon1_die1 (); 168}; 169 170 171void() Demon_MeleeAttack = 172{ 173 demon1_atta1 (); 174}; 175 176 177/*QUAKED monster_demon1 (1 0 0) (-32 -32 -24) (32 32 64) Ambush 178 179*/ 180void() monster_demon1 = 181{ 182 if (deathmatch) 183 { 184 remove(self); 185 return; 186 } 187 precache_model ("progs/demon.mdl"); 188 precache_model ("progs/h_demon.mdl"); 189 190 precache_sound ("demon/ddeath.wav"); 191 precache_sound ("demon/dhit2.wav"); 192 precache_sound ("demon/djump.wav"); 193 precache_sound ("demon/dpain1.wav"); 194 precache_sound ("demon/idle1.wav"); 195 precache_sound ("demon/sight2.wav"); 196 197 self.solid = SOLID_SLIDEBOX; 198 self.movetype = MOVETYPE_STEP; 199 200 setmodel (self, "progs/demon.mdl"); 201 202 setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); 203 self.health = 300; 204 205 self.th_stand = demon1_stand1; 206 self.th_walk = demon1_walk1; 207 self.th_run = demon1_run1; 208 self.th_die = demon_die; 209 self.th_melee = Demon_MeleeAttack; // one of two attacks 210 self.th_missile = demon1_jump1; // jump attack 211 self.th_pain = demon1_pain; 212 213 walkmonster_start(); 214}; 215 216 217/* 218============================================================================== 219 220DEMON 221 222============================================================================== 223*/ 224 225/* 226============== 227CheckDemonMelee 228 229Returns TRUE if a melee attack would hit right now 230============== 231*/ 232float() CheckDemonMelee = 233{ 234 if (enemy_range == RANGE_MELEE) 235 { // FIXME: check canreach 236 self.attack_state = AS_MELEE; 237 return TRUE; 238 } 239 return FALSE; 240}; 241 242/* 243============== 244CheckDemonJump 245 246============== 247*/ 248float() CheckDemonJump = 249{ 250 local vector dist; 251 local float d; 252 253 if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z 254 + 0.75 * self.enemy.size_z) 255 return FALSE; 256 257 if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z 258 + 0.25 * self.enemy.size_z) 259 return FALSE; 260 261 dist = self.enemy.origin - self.origin; 262 dist_z = 0; 263 264 d = vlen(dist); 265 266 if (d < 100) 267 return FALSE; 268 269 if (d > 200) 270 { 271 if (random() < 0.9) 272 return FALSE; 273 } 274 275 return TRUE; 276}; 277 278float() DemonCheckAttack = 279{ 280 local vector vec; 281 282// if close enough for slashing, go for it 283 if (CheckDemonMelee ()) 284 { 285 self.attack_state = AS_MELEE; 286 return TRUE; 287 } 288 289 if (CheckDemonJump ()) 290 { 291 self.attack_state = AS_MISSILE; 292 sound (self, CHAN_VOICE, "demon/djump.wav", 1, ATTN_NORM); 293 return TRUE; 294 } 295 296 return FALSE; 297}; 298 299 300//=========================================================================== 301 302void(float side) Demon_Melee = 303{ 304 local float ldmg; 305 local vector delta; 306 307 ai_face (); 308 walkmove (self.ideal_yaw, 12); // allow a little closing 309 310 delta = self.enemy.origin - self.origin; 311 312 if (vlen(delta) > 100) 313 return; 314 if (!CanDamage (self.enemy, self)) 315 return; 316 317 sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM); 318 ldmg = 10 + 5*random(); 319 T_Damage (self.enemy, self, self, ldmg); 320 321 makevectors (self.angles); 322 SpawnMeatSpray (self.origin + v_forward*16, side * v_right); 323}; 324 325 326void() Demon_JumpTouch = 327{ 328 local float ldmg; 329 330 if (self.health <= 0) 331 return; 332 333 if (other.takedamage) 334 { 335 if ( vlen(self.velocity) > 400 ) 336 { 337 ldmg = 40 + 10*random(); 338 T_Damage (other, self, self, ldmg); 339 } 340 } 341 342 if (!checkbottom(self)) 343 { 344 if (self.flags & FL_ONGROUND) 345 { // jump randomly to not get hung up 346//dprint ("popjump\n"); 347 self.touch = SUB_Null; 348 self.think = demon1_jump1; 349 self.nextthink = time + 0.1; 350 351// self.velocity_x = (random() - 0.5) * 600; 352// self.velocity_y = (random() - 0.5) * 600; 353// self.velocity_z = 200; 354// self.flags = self.flags - FL_ONGROUND; 355 } 356 return; // not on ground yet 357 } 358 359 self.touch = SUB_Null; 360 self.think = demon1_jump11; 361 self.nextthink = time + 0.1; 362}; 363 364