boss.qc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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. /*
  16. ==============================================================================
  17. BOSS-ONE
  18. ==============================================================================
  19. */
  20. $cd /raid/quake/id1/models/boss1
  21. $origin 0 0 -15
  22. $base base
  23. $skin skin
  24. $scale 5
  25. $frame rise1 rise2 rise3 rise4 rise5 rise6 rise7 rise8 rise9 rise10
  26. $frame rise11 rise12 rise13 rise14 rise15 rise16 rise17
  27. $frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
  28. $frame walk9 walk10 walk11 walk12 walk13 walk14 walk15
  29. $frame walk16 walk17 walk18 walk19 walk20 walk21 walk22
  30. $frame walk23 walk24 walk25 walk26 walk27 walk28 walk29 walk30 walk31
  31. $frame death1 death2 death3 death4 death5 death6 death7 death8 death9
  32. $frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8
  33. $frame attack9 attack10 attack11 attack12 attack13 attack14 attack15
  34. $frame attack16 attack17 attack18 attack19 attack20 attack21 attack22
  35. $frame attack23
  36. $frame shocka1 shocka2 shocka3 shocka4 shocka5 shocka6 shocka7 shocka8
  37. $frame shocka9 shocka10
  38. $frame shockb1 shockb2 shockb3 shockb4 shockb5 shockb6
  39. $frame shockc1 shockc2 shockc3 shockc4 shockc5 shockc6 shockc7 shockc8
  40. $frame shockc9 shockc10
  41. void(vector p) boss_missile;
  42. void() boss_face =
  43. {
  44. // go for another player if multi player
  45. if (self.enemy.health <= 0 || random() < 0.02)
  46. {
  47. self.enemy = find(self.enemy, classname, "player");
  48. if (!self.enemy)
  49. self.enemy = find(self.enemy, classname, "player");
  50. }
  51. ai_face();
  52. };
  53. void() boss_rise1 =[ $rise1, boss_rise2 ] {
  54. sound (self, CHAN_WEAPON, "boss1/out1.wav", 1, ATTN_NORM);
  55. };
  56. void() boss_rise2 =[ $rise2, boss_rise3 ] {
  57. sound (self, CHAN_VOICE, "boss1/sight1.wav", 1, ATTN_NORM);
  58. };
  59. void() boss_rise3 =[ $rise3, boss_rise4 ] {};
  60. void() boss_rise4 =[ $rise4, boss_rise5 ] {};
  61. void() boss_rise5 =[ $rise5, boss_rise6 ] {};
  62. void() boss_rise6 =[ $rise6, boss_rise7 ] {};
  63. void() boss_rise7 =[ $rise7, boss_rise8 ] {};
  64. void() boss_rise8 =[ $rise8, boss_rise9 ] {};
  65. void() boss_rise9 =[ $rise9, boss_rise10 ] {};
  66. void() boss_rise10 =[ $rise10, boss_rise11 ] {};
  67. void() boss_rise11 =[ $rise11, boss_rise12 ] {};
  68. void() boss_rise12 =[ $rise12, boss_rise13 ] {};
  69. void() boss_rise13 =[ $rise13, boss_rise14 ] {};
  70. void() boss_rise14 =[ $rise14, boss_rise15 ] {};
  71. void() boss_rise15 =[ $rise15, boss_rise16 ] {};
  72. void() boss_rise16 =[ $rise16, boss_rise17 ] {};
  73. void() boss_rise17 =[ $rise17, boss_missile1 ] {};
  74. void() boss_idle1 =[ $walk1, boss_idle2 ]
  75. {
  76. // look for other players
  77. };
  78. void() boss_idle2 =[ $walk2, boss_idle3 ] {boss_face();};
  79. void() boss_idle3 =[ $walk3, boss_idle4 ] {boss_face();};
  80. void() boss_idle4 =[ $walk4, boss_idle5 ] {boss_face();};
  81. void() boss_idle5 =[ $walk5, boss_idle6 ] {boss_face();};
  82. void() boss_idle6 =[ $walk6, boss_idle7 ] {boss_face();};
  83. void() boss_idle7 =[ $walk7, boss_idle8 ] {boss_face();};
  84. void() boss_idle8 =[ $walk8, boss_idle9 ] {boss_face();};
  85. void() boss_idle9 =[ $walk9, boss_idle10 ] {boss_face();};
  86. void() boss_idle10 =[ $walk10, boss_idle11 ] {boss_face();};
  87. void() boss_idle11 =[ $walk11, boss_idle12 ] {boss_face();};
  88. void() boss_idle12 =[ $walk12, boss_idle13 ] {boss_face();};
  89. void() boss_idle13 =[ $walk13, boss_idle14 ] {boss_face();};
  90. void() boss_idle14 =[ $walk14, boss_idle15 ] {boss_face();};
  91. void() boss_idle15 =[ $walk15, boss_idle16 ] {boss_face();};
  92. void() boss_idle16 =[ $walk16, boss_idle17 ] {boss_face();};
  93. void() boss_idle17 =[ $walk17, boss_idle18 ] {boss_face();};
  94. void() boss_idle18 =[ $walk18, boss_idle19 ] {boss_face();};
  95. void() boss_idle19 =[ $walk19, boss_idle20 ] {boss_face();};
  96. void() boss_idle20 =[ $walk20, boss_idle21 ] {boss_face();};
  97. void() boss_idle21 =[ $walk21, boss_idle22 ] {boss_face();};
  98. void() boss_idle22 =[ $walk22, boss_idle23 ] {boss_face();};
  99. void() boss_idle23 =[ $walk23, boss_idle24 ] {boss_face();};
  100. void() boss_idle24 =[ $walk24, boss_idle25 ] {boss_face();};
  101. void() boss_idle25 =[ $walk25, boss_idle26 ] {boss_face();};
  102. void() boss_idle26 =[ $walk26, boss_idle27 ] {boss_face();};
  103. void() boss_idle27 =[ $walk27, boss_idle28 ] {boss_face();};
  104. void() boss_idle28 =[ $walk28, boss_idle29 ] {boss_face();};
  105. void() boss_idle29 =[ $walk29, boss_idle30 ] {boss_face();};
  106. void() boss_idle30 =[ $walk30, boss_idle31 ] {boss_face();};
  107. void() boss_idle31 =[ $walk31, boss_idle1 ] {boss_face();};
  108. void() boss_missile1 =[ $attack1, boss_missile2 ] {boss_face();};
  109. void() boss_missile2 =[ $attack2, boss_missile3 ] {boss_face();};
  110. void() boss_missile3 =[ $attack3, boss_missile4 ] {boss_face();};
  111. void() boss_missile4 =[ $attack4, boss_missile5 ] {boss_face();};
  112. void() boss_missile5 =[ $attack5, boss_missile6 ] {boss_face();};
  113. void() boss_missile6 =[ $attack6, boss_missile7 ] {boss_face();};
  114. void() boss_missile7 =[ $attack7, boss_missile8 ] {boss_face();};
  115. void() boss_missile8 =[ $attack8, boss_missile9 ] {boss_face();};
  116. void() boss_missile9 =[ $attack9, boss_missile10 ] {boss_missile('100 100 200');};
  117. void() boss_missile10 =[ $attack10, boss_missile11 ] {boss_face();};
  118. void() boss_missile11 =[ $attack11, boss_missile12 ] {boss_face();};
  119. void() boss_missile12 =[ $attack12, boss_missile13 ] {boss_face();};
  120. void() boss_missile13 =[ $attack13, boss_missile14 ] {boss_face();};
  121. void() boss_missile14 =[ $attack14, boss_missile15 ] {boss_face();};
  122. void() boss_missile15 =[ $attack15, boss_missile16 ] {boss_face();};
  123. void() boss_missile16 =[ $attack16, boss_missile17 ] {boss_face();};
  124. void() boss_missile17 =[ $attack17, boss_missile18 ] {boss_face();};
  125. void() boss_missile18 =[ $attack18, boss_missile19 ] {boss_face();};
  126. void() boss_missile19 =[ $attack19, boss_missile20 ] {boss_face();};
  127. void() boss_missile20 =[ $attack20, boss_missile21 ] {boss_missile('100 -100 200');};
  128. void() boss_missile21 =[ $attack21, boss_missile22 ] {boss_face();};
  129. void() boss_missile22 =[ $attack22, boss_missile23 ] {boss_face();};
  130. void() boss_missile23 =[ $attack23, boss_missile1 ] {boss_face();};
  131. void() boss_shocka1 =[ $shocka1, boss_shocka2 ] {};
  132. void() boss_shocka2 =[ $shocka2, boss_shocka3 ] {};
  133. void() boss_shocka3 =[ $shocka3, boss_shocka4 ] {};
  134. void() boss_shocka4 =[ $shocka4, boss_shocka5 ] {};
  135. void() boss_shocka5 =[ $shocka5, boss_shocka6 ] {};
  136. void() boss_shocka6 =[ $shocka6, boss_shocka7 ] {};
  137. void() boss_shocka7 =[ $shocka7, boss_shocka8 ] {};
  138. void() boss_shocka8 =[ $shocka8, boss_shocka9 ] {};
  139. void() boss_shocka9 =[ $shocka9, boss_shocka10 ] {};
  140. void() boss_shocka10 =[ $shocka10, boss_missile1 ] {};
  141. void() boss_shockb1 =[ $shockb1, boss_shockb2 ] {};
  142. void() boss_shockb2 =[ $shockb2, boss_shockb3 ] {};
  143. void() boss_shockb3 =[ $shockb3, boss_shockb4 ] {};
  144. void() boss_shockb4 =[ $shockb4, boss_shockb5 ] {};
  145. void() boss_shockb5 =[ $shockb5, boss_shockb6 ] {};
  146. void() boss_shockb6 =[ $shockb6, boss_shockb7 ] {};
  147. void() boss_shockb7 =[ $shockb1, boss_shockb8 ] {};
  148. void() boss_shockb8 =[ $shockb2, boss_shockb9 ] {};
  149. void() boss_shockb9 =[ $shockb3, boss_shockb10 ] {};
  150. void() boss_shockb10 =[ $shockb4, boss_missile1 ] {};
  151. void() boss_shockc1 =[ $shockc1, boss_shockc2 ] {};
  152. void() boss_shockc2 =[ $shockc2, boss_shockc3 ] {};
  153. void() boss_shockc3 =[ $shockc3, boss_shockc4 ] {};
  154. void() boss_shockc4 =[ $shockc4, boss_shockc5 ] {};
  155. void() boss_shockc5 =[ $shockc5, boss_shockc6 ] {};
  156. void() boss_shockc6 =[ $shockc6, boss_shockc7 ] {};
  157. void() boss_shockc7 =[ $shockc7, boss_shockc8 ] {};
  158. void() boss_shockc8 =[ $shockc8, boss_shockc9 ] {};
  159. void() boss_shockc9 =[ $shockc9, boss_shockc10 ] {};
  160. void() boss_shockc10 =[ $shockc10, boss_death1 ] {};
  161. void() boss_death1 = [$death1, boss_death2] {
  162. sound (self, CHAN_VOICE, "boss1/death.wav", 1, ATTN_NORM);
  163. };
  164. void() boss_death2 = [$death2, boss_death3] {};
  165. void() boss_death3 = [$death3, boss_death4] {};
  166. void() boss_death4 = [$death4, boss_death5] {};
  167. void() boss_death5 = [$death5, boss_death6] {};
  168. void() boss_death6 = [$death6, boss_death7] {};
  169. void() boss_death7 = [$death7, boss_death8] {};
  170. void() boss_death8 = [$death8, boss_death9] {};
  171. void() boss_death9 = [$death9, boss_death10]
  172. {
  173. sound (self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM);
  174. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  175. WriteByte (MSG_BROADCAST, TE_LAVASPLASH);
  176. WriteCoord (MSG_BROADCAST, self.origin_x);
  177. WriteCoord (MSG_BROADCAST, self.origin_y);
  178. WriteCoord (MSG_BROADCAST, self.origin_z);
  179. };
  180. void() boss_death10 = [$death9, boss_death10]
  181. {
  182. killed_monsters = killed_monsters + 1;
  183. WriteByte (MSG_ALL, SVC_KILLEDMONSTER); // FIXME: reliable broadcast
  184. SUB_UseTargets ();
  185. remove (self);
  186. };
  187. void(vector p) boss_missile =
  188. {
  189. local vector offang;
  190. local vector org, vec, d;
  191. local float t;
  192. offang = vectoangles (self.enemy.origin - self.origin);
  193. makevectors (offang);
  194. org = self.origin + p_x*v_forward + p_y*v_right + p_z*'0 0 1';
  195. // lead the player on hard mode
  196. if (skill > 1)
  197. {
  198. t = vlen(self.enemy.origin - org) / 300;
  199. vec = self.enemy.velocity;
  200. vec_z = 0;
  201. d = self.enemy.origin + t * vec;
  202. }
  203. else
  204. {
  205. d = self.enemy.origin;
  206. }
  207. vec = normalize (d - org);
  208. launch_spike (org, vec);
  209. setmodel (newmis, "progs/lavaball.mdl");
  210. newmis.avelocity = '200 100 300';
  211. setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  212. newmis.velocity = vec*300;
  213. newmis.touch = T_MissileTouch; // rocket explosion
  214. sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);
  215. // check for dead enemy
  216. if (self.enemy.health <= 0)
  217. boss_idle1 ();
  218. };
  219. void() boss_awake =
  220. {
  221. self.solid = SOLID_SLIDEBOX;
  222. self.movetype = MOVETYPE_STEP;
  223. self.takedamage = DAMAGE_NO;
  224. setmodel (self, "progs/boss.mdl");
  225. setsize (self, '-128 -128 -24', '128 128 256');
  226. if (skill == 0)
  227. self.health = 1;
  228. else
  229. self.health = 3;
  230. self.enemy = activator;
  231. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  232. WriteByte (MSG_BROADCAST, TE_LAVASPLASH);
  233. WriteCoord (MSG_BROADCAST, self.origin_x);
  234. WriteCoord (MSG_BROADCAST, self.origin_y);
  235. WriteCoord (MSG_BROADCAST, self.origin_z);
  236. self.yaw_speed = 20;
  237. boss_rise1 ();
  238. };
  239. /*QUAKED monster_boss (1 0 0) (-128 -128 -24) (128 128 256)
  240. */
  241. void() monster_boss =
  242. {
  243. if (deathmatch)
  244. {
  245. remove(self);
  246. return;
  247. }
  248. precache_model ("progs/boss.mdl");
  249. precache_model ("progs/lavaball.mdl");
  250. precache_sound ("weapons/rocket1i.wav");
  251. precache_sound ("boss1/out1.wav");
  252. precache_sound ("boss1/sight1.wav");
  253. precache_sound ("misc/power.wav");
  254. precache_sound ("boss1/throw.wav");
  255. precache_sound ("boss1/pain.wav");
  256. precache_sound ("boss1/death.wav");
  257. total_monsters = total_monsters + 1;
  258. self.use = boss_awake;
  259. };
  260. //===========================================================================
  261. entity le1, le2;
  262. float lightning_end;
  263. void() lightning_fire =
  264. {
  265. local vector p1, p2;
  266. if (time >= lightning_end)
  267. { // done here, put the terminals back up
  268. self = le1;
  269. door_go_down ();
  270. self = le2;
  271. door_go_down ();
  272. return;
  273. }
  274. p1 = (le1.mins + le1.maxs) * 0.5;
  275. p1_z = le1.absmin_z - 16;
  276. p2 = (le2.mins + le2.maxs) * 0.5;
  277. p2_z = le2.absmin_z - 16;
  278. // compensate for length of bolt
  279. p2 = p2 - normalize(p2-p1)*100;
  280. self.nextthink = time + 0.1;
  281. self.think = lightning_fire;
  282. WriteByte (MSG_ALL, SVC_TEMPENTITY);
  283. WriteByte (MSG_ALL, TE_LIGHTNING3);
  284. WriteEntity (MSG_ALL, world);
  285. WriteCoord (MSG_ALL, p1_x);
  286. WriteCoord (MSG_ALL, p1_y);
  287. WriteCoord (MSG_ALL, p1_z);
  288. WriteCoord (MSG_ALL, p2_x);
  289. WriteCoord (MSG_ALL, p2_y);
  290. WriteCoord (MSG_ALL, p2_z);
  291. };
  292. void() lightning_use =
  293. {
  294. if (lightning_end >= time + 1)
  295. return;
  296. le1 = find( world, target, "lightning");
  297. le2 = find( le1, target, "lightning");
  298. if (!le1 || !le2)
  299. {
  300. dprint ("missing lightning targets\n");
  301. return;
  302. }
  303. if (
  304. (le1.state != STATE_TOP && le1.state != STATE_BOTTOM)
  305. || (le2.state != STATE_TOP && le2.state != STATE_BOTTOM)
  306. || (le1.state != le2.state) )
  307. {
  308. // dprint ("not aligned\n");
  309. return;
  310. }
  311. // don't let the electrodes go back up until the bolt is done
  312. le1.nextthink = -1;
  313. le2.nextthink = -1;
  314. lightning_end = time + 1;
  315. sound (self, CHAN_VOICE, "misc/power.wav", 1, ATTN_NORM);
  316. lightning_fire ();
  317. // advance the boss pain if down
  318. self = find (world, classname, "monster_boss");
  319. if (!self)
  320. return;
  321. self.enemy = activator;
  322. if (le1.state == STATE_TOP && self.health > 0)
  323. {
  324. sound (self, CHAN_VOICE, "boss1/pain.wav", 1, ATTN_NORM);
  325. self.health = self.health - 1;
  326. if (self.health >= 2)
  327. boss_shocka1();
  328. else if (self.health == 1)
  329. boss_shockb1();
  330. else if (self.health == 0)
  331. boss_shockc1();
  332. }
  333. };
  334. /*QUAKED event_lightning (0 1 1) (-16 -16 -16) (16 16 16)
  335. Just for boss level.
  336. */
  337. void() event_lightning =
  338. {
  339. self.use = lightning_use;
  340. };