dragon.qc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. /* Copyright (C) 1996-2022 id Software LLC
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. // dragon.qc
  16. $base dragrest
  17. $skin dragskin
  18. $frame dragon6
  19. $frame drgfly01 drgfly02 drgfly03 drgfly04
  20. $frame drgfly05 drgfly06 drgfly07 drgfly08
  21. $frame drgfly09 drgfly10 drgfly11 drgfly12 drgfly13
  22. $frame drgtrn01 drgtrn02 drgtrn03 drgtrn04 drgtrn05 drgtrn06
  23. $frame drgslh01 drgslh02 drgslh03 drgslh04 drgslh05 drgslh06
  24. $frame drgslh07 drgslh08 drgslh09 drgslh10 drgslh11 drgslh12 drgslh13
  25. $frame drgfir01 drgfir02 drgfir03 drgfir04 drgfir05
  26. $frame drgfir06 drgfir07 drgfir08 drgfir09 drgfir10
  27. $frame drgfix1a drgfix1b drgfix1c
  28. $frame drgfix2a drgfix2b drgfix2c
  29. $frame drgfix3a drgfix3b drgfix3c
  30. $frame drgfix4a drgfix4b drgfix4c
  31. $frame drgfix5a drgfix5b drgfix5c
  32. $frame drgfix6a drgfix6b drgfix6c drgfix6d
  33. $frame drgpan1a drgpan1b drgpan1c
  34. $frame drgpan2a drgpan2b drgpan2c
  35. $frame drgpan3a drgpan3b drgpan3c
  36. $frame drgpan4a drgpan4b drgpan4c
  37. $frame drgpan5a drgpan5b drgpan5c
  38. $frame drgpan6a drgpan6b drgpan6c
  39. $frame drgdth01 drgdth02 drgdth03 drgdth04 drgdth05 drgdth06
  40. $frame drgdth07 drgdth08 drgdth09 drgdth10 drgdth11 drgdth12
  41. $frame drgdth13 drgdth14 drgdth15 drgdth16 drgdth17 drgdth18
  42. $frame drgdth19 drgdth20 drgdth21
  43. void() dragon_fireball;
  44. void() dragon_melee1;
  45. // ===================================
  46. // global variables
  47. // ===================================
  48. float DDIE_FALLING = 1;
  49. float DDIE_STOPPED = 2;
  50. float DDIE_EXPLODED = 3;
  51. float DT_ROOM_A = 1;
  52. float DT_ROOM_B = 2;
  53. float DT_ROOM_C = 4;
  54. float FIRE_PLASMA = 1;
  55. float FIRE_FIREBALL = 2;
  56. // ===================================
  57. // dragon_stop_attack
  58. // ===================================
  59. void() dragon_stop_attack =
  60. {
  61. local entity tempDest;
  62. if (self.dragonAttacking == FALSE)
  63. return;
  64. // skill ramp?
  65. self.attack_finished = time + (random() * 2 ) + 4;
  66. self.attack_finished = self.attack_finished - skill;
  67. self.dragonAttacking = FALSE;
  68. traceline (self.origin, self.movetarget.origin, TRUE, world);
  69. if (trace_fraction == 1)
  70. return;
  71. else
  72. bprint ("Error: Dragon cannot get to next target!\n");
  73. };
  74. // ===================================
  75. // dragon_check_attack
  76. // ===================================
  77. void() dragon_check_attack =
  78. {
  79. local vector vec;
  80. local float dot;
  81. if ( self.dragonAttacking == TRUE)
  82. return;
  83. if ( self.th_missile == SUB_Null)
  84. return;
  85. if ( self.attack_finished > time )
  86. return;
  87. if ( self.enemy.health < 0)
  88. self.enemy = world;
  89. if ( self.enemy.flags & FL_NOTARGET )
  90. return;
  91. if (self.enemy == world)
  92. FindTarget();
  93. else
  94. {
  95. makevectors (self.angles);
  96. vec = normalize (self.enemy.origin - self.origin);
  97. dot = vec * v_forward;
  98. // if ( dot > 0.55 )
  99. if ( dot > 0.3 )
  100. {
  101. traceline (self.origin, self.enemy.origin, TRUE, world);
  102. if (trace_fraction == 1)
  103. {
  104. dot = vlen ( self.enemy.origin - self.origin );
  105. if (dot < 350)
  106. {
  107. self.dragonAttacking = TRUE;
  108. self.think = dragon_melee1;
  109. return;
  110. }
  111. else
  112. {
  113. self.dragonAttacking = TRUE;
  114. self.think = self.th_missile;
  115. }
  116. }
  117. // else
  118. // bprint ("can't see player!\n");
  119. }
  120. }
  121. };
  122. // ===================================
  123. // dragon_move
  124. // ===================================
  125. void(float dist) dragon_move =
  126. {
  127. local vector moveDir;
  128. local vector moveAngles;
  129. local float leftTurn, rightTurn, turnOffset;
  130. local entity oldEnemy;
  131. if ( self.health < 1 )
  132. {
  133. remove(self);
  134. return;
  135. }
  136. if (self.dragonAttacking == FALSE) // && self.dragonInTransit == FALSE)
  137. dragon_check_attack();
  138. oldEnemy = self.enemy;
  139. if ( self.dragonAttacking == FALSE )
  140. {
  141. moveDir = self.movetarget.origin - self.origin;
  142. moveAngles = vectoangles ( moveDir );
  143. self.enemy = self.movetarget;
  144. }
  145. else
  146. {
  147. moveDir = self.enemy.origin - self.origin;
  148. moveAngles = vectoangles ( moveDir );
  149. }
  150. turnOffset = self.angles_y - moveAngles_y;
  151. if (turnOffset != 0)
  152. {
  153. turnOffset = 180 - self.angles_y;
  154. leftTurn = anglemod ( moveAngles_y + turnOffset ) - 180;
  155. rightTurn = 180 - anglemod ( moveAngles_y + turnOffset );
  156. if (leftTurn < 0)
  157. leftTurn = 360;
  158. else if (rightTurn < 0)
  159. rightTurn = 360;
  160. self.yaw_speed = 10;
  161. if (rightTurn < 180)
  162. {
  163. if ( self.yaw_speed < rightTurn )
  164. self.angles_y = self.angles_y - self.yaw_speed;
  165. else
  166. self.angles_y = moveAngles_y;
  167. if ( rightTurn > 5 )
  168. {
  169. self.angles_z = self.angles_z + 5;
  170. if (self.angles_z > 30)
  171. self.angles_z = 30;
  172. }
  173. turnOffset = rightTurn;
  174. }
  175. else
  176. {
  177. if ( self.yaw_speed < rightTurn )
  178. self.angles_y = self.angles_y + self.yaw_speed;
  179. else
  180. self.angles_y = moveAngles_y;
  181. if ( leftTurn > 5 )
  182. {
  183. self.angles_z = self.angles_z - 5;
  184. if (self.angles_z < -30)
  185. self.angles_z = -30;
  186. }
  187. turnOffset = leftTurn;
  188. }
  189. }
  190. else if (self.angles_z != 0)
  191. {
  192. if (self.angles_z < -5)
  193. self.angles_z = self.angles_z + 5;
  194. else if (self.angles_z < 5)
  195. self.angles_z = 0;
  196. else if (self.angles_z > 5)
  197. self.angles_z = self.angles_z - 5;
  198. }
  199. if ( moveDir_z > 5)
  200. setorigin ( self, self.origin + '0 0 5');
  201. else if ( moveDir_z < -5)
  202. setorigin ( self, self.origin - '0 0 5');
  203. moveAngles = self.origin;
  204. walkmove ( self.angles_y, dist );
  205. if (moveAngles == self.origin)
  206. {
  207. // bprint ( "Cannot move smoothly. movetogoal..\n");
  208. movetogoal ( dist );
  209. }
  210. self.enemy = oldEnemy;
  211. };
  212. // ===================================
  213. // movement
  214. // ===================================
  215. void() dragon_stand1 = [ $drgfly01, dragon_walk1 ]
  216. {
  217. // bprint ( "dragon_stand1: ERROR - got to stand frame!\n");
  218. };
  219. // attack A: start - walk1 stop - walk 5
  220. // ================
  221. void() dragon_atk_a1=[$drgfix1a, dragon_atk_a2 ]
  222. { dragon_move(17); };
  223. void() dragon_atk_a2=[$drgfix1b, dragon_atk_a3 ]
  224. { dragon_move(17);dragon_fireball();};
  225. void() dragon_atk_a3=[$drgfix1c, dragon_walk5 ]
  226. { dragon_move(17);dragon_stop_attack();};
  227. // attack B: start - walk3 stop - walk7
  228. // ================
  229. void() dragon_atk_b1=[$drgfix2a, dragon_atk_b2 ]
  230. { dragon_move(17); };
  231. void() dragon_atk_b2=[$drgfix2b, dragon_atk_b3 ]
  232. { dragon_move(17);dragon_fireball();};
  233. void() dragon_atk_b3=[$drgfix2c, dragon_walk7 ]
  234. { dragon_move(17);dragon_stop_attack();};
  235. // attack C: start - walk5 stop - walk9
  236. // ================
  237. void() dragon_atk_c1=[$drgfix3a, dragon_atk_c2 ]
  238. {dragon_move(17); };
  239. void() dragon_atk_c2=[$drgfix3b, dragon_atk_c3 ]
  240. { dragon_move(17);dragon_fireball();};
  241. void() dragon_atk_c3=[$drgfix3c, dragon_walk9 ]
  242. { dragon_move(17);dragon_stop_attack();};
  243. // attack d: start - walk7 stop - walk11
  244. // ================
  245. void() dragon_atk_d1=[$drgfix4a, dragon_atk_d2 ]
  246. { dragon_move(17); };
  247. void() dragon_atk_d2=[$drgfix4b, dragon_atk_d3 ]
  248. { dragon_move(17);dragon_fireball();};
  249. void() dragon_atk_d3=[$drgfix4c, dragon_walk11 ]
  250. { dragon_move(17);dragon_stop_attack();};
  251. // attack E: start - walk9 stop - walk13
  252. // ================
  253. void() dragon_atk_e1=[$drgfix5a, dragon_atk_e2 ]
  254. { dragon_move(17); };
  255. void() dragon_atk_e2=[$drgfix5b, dragon_atk_e3 ]
  256. { dragon_move(17);dragon_fireball();};
  257. void() dragon_atk_e3=[$drgfix5c, dragon_walk13 ]
  258. { dragon_move(17);dragon_stop_attack();};
  259. // attack F: start - walk11 stop - walk3
  260. // ================
  261. void() dragon_atk_f1=[$drgfix6a, dragon_atk_f2 ]
  262. {dragon_move(17); };
  263. void() dragon_atk_f2=[$drgfix6b, dragon_atk_f3 ]
  264. { dragon_move(17);dragon_fireball();};
  265. void() dragon_atk_f3=[$drgfix6c, dragon_atk_f4 ]
  266. { dragon_move(17); };
  267. void() dragon_atk_f4=[$drgfix6c, dragon_walk3 ]
  268. { dragon_move(17);dragon_stop_attack();};
  269. // ===================================
  270. // dragon walk frames
  271. // ===================================
  272. void() dragon_walk1 =[ $drgfly01, dragon_walk2 ]
  273. {
  274. if (self.dragonAttacking)
  275. dragon_stop_attack();
  276. self.th_missile=dragon_atk_a1;
  277. self.dragonPainSequence = 1;
  278. dragon_move(17);
  279. if (random() < 0.2)
  280. sound (self, CHAN_VOICE, "dragon/active.wav", 0.6, ATTN_IDLE);
  281. };
  282. void() dragon_walk2 =[ $drgfly02, dragon_walk3 ]
  283. { self.th_missile=SUB_Null; dragon_move(17);};
  284. void() dragon_walk3 =[ $drgfly03, dragon_walk4 ]
  285. {
  286. self.th_missile=dragon_atk_b1; dragon_move(17);
  287. self.dragonPainSequence=2;
  288. };
  289. void() dragon_walk4 =[ $drgfly04, dragon_walk5 ]
  290. { self.th_missile=SUB_Null; dragon_move(17);};
  291. void() dragon_walk5 =[ $drgfly05, dragon_walk6 ]
  292. {
  293. self.th_missile=dragon_atk_c1; dragon_move(17);
  294. self.dragonPainSequence=3;
  295. };
  296. void() dragon_walk6 =[ $drgfly06, dragon_walk7 ]
  297. { self.th_missile=SUB_Null; dragon_move(17); };
  298. void() dragon_walk7 =[ $drgfly07, dragon_walk8 ]
  299. {
  300. self.th_missile=dragon_atk_d1; dragon_move(17);
  301. self.dragonPainSequence=4;
  302. };
  303. void() dragon_walk8 =[ $drgfly08, dragon_walk9 ]
  304. { self.th_missile=SUB_Null; dragon_move(17); };
  305. void() dragon_walk9 =[ $drgfly09, dragon_walk10 ]
  306. {
  307. self.th_missile=dragon_atk_e1; dragon_move(17);
  308. self.dragonPainSequence=5;
  309. };
  310. void() dragon_walk10 =[ $drgfly10, dragon_walk11 ]
  311. { self.th_missile=SUB_Null; dragon_move(17); };
  312. void() dragon_walk11 =[ $drgfly11, dragon_walk12 ]
  313. {
  314. self.th_missile=dragon_atk_f1; dragon_move(17);
  315. self.dragonPainSequence=6;
  316. };
  317. void() dragon_walk12 =[ $drgfly12, dragon_walk13 ]
  318. { self.th_missile=SUB_Null; dragon_move(17); };
  319. void() dragon_walk13 =[ $drgfly13, dragon_walk1 ]
  320. { self.th_missile=SUB_Null; dragon_move(17); self.dragonPainSequence=1;};
  321. // ===================================
  322. // attack
  323. // ===================================
  324. void() FireballTouch =
  325. {
  326. if (other == self.owner)
  327. return; // don't explode on owner
  328. if (self.owner.classname == "monster_dragon")
  329. T_RadiusDamage (self, self.owner, 90, self.owner);
  330. else
  331. T_RadiusDamage (self, self.owner, 30, world);
  332. sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  333. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  334. WriteByte (MSG_BROADCAST, TE_EXPLOSION2);
  335. WriteCoord (MSG_BROADCAST, self.origin_x);
  336. WriteCoord (MSG_BROADCAST, self.origin_y);
  337. WriteCoord (MSG_BROADCAST, self.origin_z);
  338. WriteByte (MSG_BROADCAST, 228); // 247
  339. WriteByte (MSG_BROADCAST, 5);
  340. remove(self);
  341. // BecomeExplosion();
  342. };
  343. void(vector org, vector dir) launch_fireball =
  344. {
  345. local entity fireball;
  346. local float fireSpeed;
  347. self.effects = self.effects | EF_MUZZLEFLASH;
  348. fireball = spawn();
  349. fireball.owner = self;
  350. fireball.movetype = MOVETYPE_FLYMISSILE;
  351. fireball.solid = SOLID_BBOX;
  352. fireball.classname = "fireball";
  353. setmodel (fireball, "progs/fireball.mdl");
  354. setorigin (fireball, org);
  355. setsize (fireball, '0 0 0', '0 0 0');
  356. fireSpeed = random() * 300 + 900;
  357. fireball.velocity = dir * fireSpeed;
  358. fireball.avelocity = '0 0 300';
  359. fireball.angles = vectoangles(fireball.velocity);
  360. fireball.enemy = self.enemy;
  361. fireball.touch = FireballTouch;
  362. fireball.nextthink = time + 6;
  363. fireball.think = SUB_Remove;
  364. };
  365. // ===========================================
  366. // dragon_fireball
  367. // ===========================================
  368. void() dragon_fireball =
  369. {
  370. local float fireCount;
  371. local vector org, dir;
  372. local float distortion;
  373. local float fireType;
  374. sound (self, CHAN_VOICE, "dragon/attack.wav", 1, ATTN_NORM);
  375. makevectors (self.angles);
  376. org = self.origin + v_forward*112 + v_up*32;
  377. if (random() > 0.66)
  378. {
  379. fireCount = 1;
  380. if ( skill > 1)
  381. fireCount = 2;
  382. fireType = FIRE_PLASMA;
  383. }
  384. else
  385. {
  386. fireType = FIRE_FIREBALL;
  387. fireCount = random() * skill; // easy 0, med 0-1, hard 0-2
  388. fireCount = rint ( fireCount ) + 1;
  389. // easy 1, med 1-2, hard 1-3
  390. }
  391. while (fireCount > 0)
  392. {
  393. distortion = ( random() - 0.5 ) * 0.25;
  394. dir = normalize ( self.enemy.origin - org );
  395. makevectors (dir);
  396. dir = dir + v_right * distortion;
  397. if (fireType == FIRE_FIREBALL)
  398. launch_fireball(org, dir);
  399. else
  400. launch_plasma(org, dir);
  401. fireCount = fireCount - 1;
  402. }
  403. };
  404. // ===================================
  405. // melee attacks
  406. // ===================================
  407. void() dragon_tail_touch =
  408. {
  409. local vector delta;
  410. local float tailDamage;
  411. if (!self.enemy)
  412. return;
  413. if (!CanDamage (self.enemy, self))
  414. return;
  415. ai_charge(10);
  416. delta = self.enemy.origin - self.origin;
  417. tailDamage = vlen(delta);
  418. if (vlen(delta) > 150)
  419. {
  420. return;
  421. }
  422. tailDamage = ( random() * 30 ) + 30;
  423. T_Damage ( self.enemy, self, self, tailDamage);
  424. };
  425. void() dragon_tail =
  426. {
  427. local float dist;
  428. local vector dir;
  429. if (!self.enemy)
  430. return;
  431. if (!CanDamage (self.enemy, self))
  432. return;
  433. dragon_move(10);
  434. dir = self.enemy.origin - self.origin;
  435. dist = vlen ( dir );
  436. if ( dist < 250 )
  437. {
  438. T_Damage ( self.enemy, self, self, 30 );
  439. dir = normalize (dir);
  440. self.enemy.velocity = dir * 500;
  441. self.enemy.velocity_z = 350;
  442. }
  443. dragon_stop_attack();
  444. };
  445. void() dragon_melee1=[$drgslh01, dragon_melee2 ] { dragon_move(12);};
  446. void() dragon_melee2=[$drgslh02, dragon_melee3 ] { dragon_move(12);};
  447. void() dragon_melee3=[$drgslh03, dragon_melee4 ] { dragon_move(12);};
  448. void() dragon_melee4=[$drgslh04, dragon_melee5 ] { dragon_move(12);};
  449. void() dragon_melee5=[$drgslh05, dragon_melee6 ] { dragon_move(12);};
  450. void() dragon_melee6=[$drgslh06, dragon_melee7 ] { dragon_move(12);};
  451. void() dragon_melee7=[$drgslh07, dragon_melee8 ] { dragon_move(12);};
  452. void() dragon_melee8=[$drgslh08, dragon_melee9 ] { dragon_move(12);};
  453. void() dragon_melee9=[$drgslh09, dragon_melee10] { dragon_move(12);};
  454. void() dragon_melee10=[$drgslh10, dragon_melee11] { dragon_tail();};
  455. void() dragon_melee11=[$drgslh11, dragon_melee12] { dragon_move(10);};
  456. void() dragon_melee12=[$drgslh12, dragon_melee13] { dragon_move(10);};
  457. void() dragon_melee13=[$drgslh13, dragon_walk1 ]
  458. { dragon_move(10);};
  459. // ===================================
  460. // pain
  461. // ===================================
  462. void() dragon_painA1 = [ $drgpan1a, dragon_painA2 ] {dragon_move(12);};
  463. void() dragon_painA2 = [ $drgpan1b, dragon_painA3 ] {dragon_move(12);};
  464. void() dragon_painA3 = [ $drgpan1c, dragon_walk5 ] {dragon_move(12);};
  465. void() dragon_painB1 = [ $drgpan2a, dragon_painB2 ] {dragon_move(12);};
  466. void() dragon_painB2 = [ $drgpan2b, dragon_painB3 ] {dragon_move(12);};
  467. void() dragon_painB3 = [ $drgpan2c, dragon_walk7 ] {dragon_move(12);};
  468. void() dragon_painC1 = [ $drgpan3a, dragon_painC2 ] {dragon_move(12);};
  469. void() dragon_painC2 = [ $drgpan3b, dragon_painC3 ] {dragon_move(12);};
  470. void() dragon_painC3 = [ $drgpan3c, dragon_walk9 ] {dragon_move(12);};
  471. void() dragon_painD1 = [ $drgpan4a, dragon_painD2 ] {dragon_move(12);};
  472. void() dragon_painD2 = [ $drgpan4b, dragon_painD3 ] {dragon_move(12);};
  473. void() dragon_painD3 = [ $drgpan4c, dragon_walk11 ] {dragon_move(12);};
  474. void() dragon_painE1 = [ $drgpan5a, dragon_painE2 ] {dragon_move(12);};
  475. void() dragon_painE2 = [ $drgpan5b, dragon_painE3 ] {dragon_move(12);};
  476. void() dragon_painE3 = [ $drgpan5c, dragon_walk13 ] {dragon_move(12);};
  477. void() dragon_painF1 = [ $drgpan6a, dragon_painF2 ] {dragon_move(12);};
  478. void() dragon_painF2 = [ $drgpan6b, dragon_painF3 ] {dragon_move(12);};
  479. void() dragon_painF3 = [ $drgpan6c, dragon_walk2 ] {dragon_move(12);};
  480. void() dragon_pain =
  481. {
  482. local float r;
  483. if (self.pain_finished > time)
  484. return;
  485. r = random();
  486. if (r < 0.25)
  487. {
  488. dragon_stop_attack();
  489. sound (self, CHAN_VOICE, "dragon/pain.wav", 1, ATTN_NORM);
  490. self.pain_finished = time + 2;
  491. if (self.dragonPainSequence == 1)
  492. self.think = dragon_painA1;
  493. else if (self.dragonPainSequence == 2)
  494. self.think = dragon_painF1;
  495. else if (self.dragonPainSequence == 3)
  496. self.think = dragon_painE1;
  497. else if (self.dragonPainSequence == 4)
  498. self.think = dragon_painD1;
  499. else if (self.dragonPainSequence == 5)
  500. self.think = dragon_painC1;
  501. else if (self.dragonPainSequence == 6)
  502. self.think = dragon_painB1;
  503. }
  504. };
  505. // ===================================
  506. // death
  507. // ===================================
  508. void() dragon_boom2 =
  509. {
  510. self.velocity = self.dragonLastVelocity;
  511. ViolentDeath(15);
  512. self.target = "dragondoor";
  513. SUB_UseTargets();
  514. remove(self);
  515. };
  516. void() dragon_boom1 =
  517. {
  518. if ( self.dragonDeathState > DDIE_STOPPED )
  519. // objerror ( "dragon_boom1");
  520. return;
  521. self.dragonDeathState = DDIE_EXPLODED;
  522. ThrowGib ("progs/drggib01.mdl", -100);
  523. ThrowGib ("progs/drggib02.mdl", -100);
  524. ThrowGib ("progs/drggib03.mdl", -100);
  525. sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
  526. self.think = dragon_boom2;
  527. self.nextthink = time + 0.1;
  528. };
  529. void() dragon_explode =
  530. {
  531. if ( self.dragonDeathState > DDIE_FALLING )
  532. // objerror ( "dragon_explode");
  533. return;
  534. if (vlen(self.velocity) < 100 || self.flags & FL_INWATER)
  535. {
  536. self.dragonDeathState = DDIE_STOPPED;
  537. dragon_boom1();
  538. }
  539. else
  540. {
  541. makevectors ( self.angles );
  542. self.velocity = self.velocity - 40 * v_up;
  543. self.dragonLastVelocity = self.velocity;
  544. }
  545. };
  546. void() dragon_squish =
  547. {
  548. if (other.classname == "player")
  549. {
  550. self.classname = "monster_dragon_dead";
  551. T_Damage( other, self, self, 200);
  552. }
  553. if (other == world)
  554. {
  555. self.velocity = '0 0 0';
  556. dragon_explode();
  557. }
  558. };
  559. void() dragon_death1 = [ $drgdth01, dragon_death2 ]
  560. {
  561. if ( self.dragonDeathState > 0)
  562. // objerror ( "dragon_death1");
  563. return;
  564. self.dragonDeathState = DDIE_FALLING;
  565. self.use = SUB_Null;
  566. makevectors ( self.angles );
  567. self.velocity = 300 * v_forward - 40 * v_up;
  568. self.flags = self.flags - (self.flags & FL_ONGROUND);
  569. setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
  570. self.touch = dragon_squish;
  571. sound (self, CHAN_VOICE, "dragon/death.wav", 1, ATTN_NONE);
  572. self.dragonAttacking = FALSE;
  573. };
  574. void() dragon_death2 = [ $drgdth02, dragon_death3 ] {dragon_explode();};
  575. void() dragon_death3 = [ $drgdth03, dragon_death4 ] {dragon_explode();};
  576. void() dragon_death4 = [ $drgdth04, dragon_death5 ] {dragon_explode();};
  577. void() dragon_death5 = [ $drgdth05, dragon_death6 ] {dragon_explode();};
  578. void() dragon_death6 = [ $drgdth06, dragon_death7 ] {dragon_explode();};
  579. void() dragon_death7 = [ $drgdth07, dragon_death8 ] {dragon_explode();};
  580. void() dragon_death8 = [ $drgdth08, dragon_death9 ] {dragon_explode();};
  581. void() dragon_death9 = [ $drgdth09, dragon_death10 ] {dragon_explode();};
  582. void() dragon_death10 = [ $drgdth10, dragon_death11 ] {dragon_explode();};
  583. void() dragon_death11 = [ $drgdth11, dragon_death12 ] {dragon_explode();};
  584. void() dragon_death12 = [ $drgdth12, dragon_death13 ] {dragon_explode();};
  585. void() dragon_death13 = [ $drgdth13, dragon_death14 ] {dragon_explode();};
  586. void() dragon_death14 = [ $drgdth14, dragon_death15 ] {dragon_explode();};
  587. void() dragon_death15 = [ $drgdth15, dragon_death16 ] {dragon_explode();};
  588. void() dragon_death16 = [ $drgdth16, dragon_death17 ] {dragon_explode();};
  589. void() dragon_death17 = [ $drgdth17, dragon_death18 ] {dragon_explode();};
  590. void() dragon_death18 = [ $drgdth18, dragon_death19 ] {dragon_explode();};
  591. void() dragon_death19 = [ $drgdth19, dragon_death20 ] {dragon_explode();};
  592. void() dragon_death20 = [ $drgdth20, dragon_death21 ] {dragon_explode();};
  593. void() dragon_death21 = [ $drgdth21, dragon_death21 ]
  594. {
  595. ViolentDeath(39);
  596. self.target = "dragondoor";
  597. SUB_UseTargets();
  598. remove(self);
  599. };
  600. // ===================================
  601. // Delayed Activation
  602. // ===================================
  603. void() dragon_use =
  604. {
  605. if (self.health < 1)
  606. {
  607. self.use = SUB_Null;
  608. return;
  609. }
  610. self.th_stand = dragon_walk1;
  611. self.th_walk = dragon_walk1;
  612. self.think = dragon_walk1;
  613. self.nextthink = time + 0.1;
  614. };
  615. // ===================================
  616. // dragon activation code
  617. // ===================================
  618. void() dragon_activate =
  619. {
  620. self.takedamage = DAMAGE_AIM;
  621. self.ideal_yaw = self.angles * '0 1 0';
  622. if (!self.yaw_speed)
  623. self.yaw_speed = 10;
  624. self.view_ofs = '0 0 25';
  625. self.flags = self.flags | FL_FLY;
  626. self.flags = self.flags | FL_MONSTER;
  627. if (!walkmove(0,0))
  628. {
  629. dprint ("flymonster in wall!\n");
  630. dprint (self.classname);
  631. dprint (" at ");
  632. dprint (vtos(self.origin));
  633. dprint ("\n");
  634. }
  635. if (self.target)
  636. {
  637. self.movetarget = find(world, targetname, self.target);
  638. self.goalentity = self.movetarget;
  639. if (!self.movetarget)
  640. {
  641. dprint ("Monster can't find target at ");
  642. dprint (vtos(self.origin));
  643. dprint ("\n");
  644. }
  645. }
  646. if (self.targetname)
  647. self.use = dragon_use;
  648. else
  649. dragon_use();
  650. };
  651. /*QUAKED monster_dragon (1 0 0) (-32 -32 -24) (32 32 64) Ambush
  652. */
  653. void() monster_dragon =
  654. {
  655. if (deathmatch)
  656. {
  657. remove(self);
  658. return;
  659. }
  660. precache_model ("progs/dragon.mdl");
  661. precache_model ("progs/fireball.mdl");
  662. precache_model ("progs/drggib01.mdl");
  663. precache_model ("progs/drggib02.mdl");
  664. precache_model ("progs/drggib03.mdl");
  665. precache_sound ("dragon/see.wav");
  666. precache_sound ("dragon/active.wav");
  667. precache_sound ("dragon/attack.wav");
  668. precache_sound ("dragon/pain.wav");
  669. precache_sound ("dragon/death.wav");
  670. self.dragonInRoom = DT_ROOM_A;
  671. self.dragonInTransit = 0;
  672. self.dragonAttacking = FALSE;
  673. self.playerInRoom = DT_ROOM_A;
  674. self.playerInTransit = 0;
  675. self.solid = SOLID_SLIDEBOX;
  676. self.movetype = MOVETYPE_STEP;
  677. setmodel (self, "progs/dragon.mdl");
  678. setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX);
  679. self.health = 3000 + (1000 * cvar("skill"));
  680. self.th_run = dragon_walk1;
  681. self.th_pain = dragon_pain;
  682. self.th_die = dragon_death1;
  683. self.dragonPainSequence=1;
  684. total_monsters = total_monsters + 1;
  685. self.nextthink = self.nextthink + 0.1;
  686. self.think = dragon_activate;
  687. };
  688. // =================================================
  689. // dragon trigger
  690. // OBSOLETE!!
  691. // =================================================
  692. /*QUAKED trigger_dragon (.5 .5 .5) ? A B C
  693. Trigger to let dragon know what room you're in.
  694. Set the A,B,C to which room this trigger is at.
  695. Point the trigger towards the room. If the player is going
  696. the direction the trigger points, he is entering the room.
  697. If not, he is leaving.
  698. */
  699. void() trigger_dragon =
  700. {
  701. remove(self);
  702. };
  703. // =================================================
  704. // dragon corners
  705. // =================================================
  706. void() dragon_corner_touch =
  707. {
  708. if (other.movetarget != self)
  709. return;
  710. if (other.classname != "monster_dragon")
  711. return;
  712. other.movetarget = find (world, targetname, self.target);
  713. other.goalentity = other.movetarget;
  714. other.target = self.target;
  715. if (!other.movetarget)
  716. {
  717. objerror ("dragon_corner: no target found");
  718. }
  719. };
  720. /*QUAKED dragon_corner (0.5 0.3 0) (-16 -16 -16) (16 16 16)
  721. Only for use with monster_dragon. Use only as transitions
  722. between rooms.
  723. */
  724. void() dragon_corner =
  725. {
  726. if (!self.targetname)
  727. objerror ("dragon_corner: no targetname");
  728. self.solid = SOLID_TRIGGER;
  729. self.movetype = MOVETYPE_NONE;
  730. self.touch = dragon_corner_touch;
  731. self.modelindex = 0;
  732. self.model = "";
  733. setsize (self, '-16 -16 -16', '16 16 16');
  734. };