plats.qc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. plats.qc
  3. platform functions
  4. Copyright (C) 1996-1997 Id Software, Inc.
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. See the GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to:
  15. Free Software Foundation, Inc.
  16. 59 Temple Place - Suite 330
  17. Boston, MA 02111-1307, USA
  18. */
  19. void() plat_center_touch;
  20. void() plat_outside_touch;
  21. void() plat_trigger_use;
  22. void() plat_go_up;
  23. void() plat_go_down;
  24. void() plat_crush;
  25. float PLAT_LOW_TRIGGER = 1;
  26. void() plat_spawn_inside_trigger =
  27. {
  28. local entity trigger;
  29. local vector tmin, tmax;
  30. //
  31. // middle trigger
  32. //
  33. trigger = spawn();
  34. trigger.touch = plat_center_touch;
  35. trigger.movetype = MOVETYPE_NONE;
  36. trigger.solid = SOLID_TRIGGER;
  37. trigger.enemy = self;
  38. tmin = self.mins + '25 25 0';
  39. tmax = self.maxs - '25 25 -8';
  40. tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
  41. if (self.spawnflags & PLAT_LOW_TRIGGER)
  42. tmax_z = tmin_z + 8;
  43. if (self.size_x <= 50)
  44. {
  45. tmin_x = (self.mins_x + self.maxs_x) / 2;
  46. tmax_x = tmin_x + 1;
  47. }
  48. if (self.size_y <= 50)
  49. {
  50. tmin_y = (self.mins_y + self.maxs_y) / 2;
  51. tmax_y = tmin_y + 1;
  52. }
  53. setsize (trigger, tmin, tmax);
  54. };
  55. void() plat_hit_top =
  56. {
  57. sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  58. self.state = STATE_TOP;
  59. self.think = plat_go_down;
  60. self.nextthink = self.ltime + 3;
  61. };
  62. void() plat_hit_bottom =
  63. {
  64. sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  65. self.state = STATE_BOTTOM;
  66. };
  67. void() plat_go_down =
  68. {
  69. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  70. self.state = STATE_DOWN;
  71. SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
  72. };
  73. void() plat_go_up =
  74. {
  75. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  76. self.state = STATE_UP;
  77. SUB_CalcMove (self.pos1, self.speed, plat_hit_top);
  78. };
  79. void() plat_center_touch =
  80. {
  81. if (other.classname != "player")
  82. return;
  83. if (other.health <= 0)
  84. return;
  85. self = self.enemy;
  86. if (self.state == STATE_BOTTOM)
  87. plat_go_up ();
  88. else if (self.state == STATE_TOP)
  89. self.nextthink = self.ltime + 1; // delay going down
  90. };
  91. void() plat_outside_touch =
  92. {
  93. if (other.classname != "player")
  94. return;
  95. if (other.health <= 0)
  96. return;
  97. //dprint ("plat_outside_touch\n");
  98. self = self.enemy;
  99. if (self.state == STATE_TOP)
  100. plat_go_down ();
  101. };
  102. void() plat_trigger_use =
  103. {
  104. if (self.think)
  105. return; // allready activated
  106. plat_go_down();
  107. };
  108. void() plat_crush =
  109. {
  110. //dprint ("plat_crush\n");
  111. other.deathtype = "squish";
  112. T_Damage (other, self, self, 1);
  113. if (self.state == STATE_UP)
  114. plat_go_down ();
  115. else if (self.state == STATE_DOWN)
  116. plat_go_up ();
  117. else
  118. objerror ("plat_crush: bad self.state\n");
  119. };
  120. void() plat_use =
  121. {
  122. self.use = SUB_Null;
  123. if (self.state != STATE_UP)
  124. objerror ("plat_use: not in up state");
  125. plat_go_down();
  126. };
  127. /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
  128. speed default 150
  129. Plats are always drawn in the extended position, so they will light correctly.
  130. If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
  131. If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height.
  132. Set "sounds" to one of the following:
  133. 1) base fast
  134. 2) chain slow
  135. */
  136. void() func_plat =
  137. {
  138. local entity t;
  139. if (!self.t_length)
  140. self.t_length = 80;
  141. if (!self.t_width)
  142. self.t_width = 10;
  143. if (self.sounds == 0)
  144. self.sounds = 2;
  145. // FIX THIS TO LOAD A GENERIC PLAT SOUND
  146. if (self.sounds == 1)
  147. {
  148. precache_sound ("plats/plat1.wav");
  149. precache_sound ("plats/plat2.wav");
  150. self.noise = "plats/plat1.wav";
  151. self.noise1 = "plats/plat2.wav";
  152. }
  153. if (self.sounds == 2)
  154. {
  155. precache_sound ("plats/medplat1.wav");
  156. precache_sound ("plats/medplat2.wav");
  157. self.noise = "plats/medplat1.wav";
  158. self.noise1 = "plats/medplat2.wav";
  159. }
  160. self.mangle = self.angles;
  161. self.angles = '0 0 0';
  162. self.classname = "plat";
  163. self.solid = SOLID_BSP;
  164. self.movetype = MOVETYPE_PUSH;
  165. setorigin (self, self.origin);
  166. setmodel (self, self.model);
  167. setsize (self, self.mins , self.maxs);
  168. self.blocked = plat_crush;
  169. if (!self.speed)
  170. self.speed = 150;
  171. // pos1 is the top position, pos2 is the bottom
  172. self.pos1 = self.origin;
  173. self.pos2 = self.origin;
  174. if (self.height)
  175. self.pos2_z = self.origin_z - self.height;
  176. else
  177. self.pos2_z = self.origin_z - self.size_z + 8;
  178. self.use = plat_trigger_use;
  179. plat_spawn_inside_trigger (); // the "start moving" trigger
  180. if (self.targetname)
  181. {
  182. self.state = STATE_UP;
  183. self.use = plat_use;
  184. }
  185. else
  186. {
  187. setorigin (self, self.pos2);
  188. self.state = STATE_BOTTOM;
  189. }
  190. };
  191. //============================================================================
  192. void() train_next;
  193. void() func_train_find;
  194. void() train_blocked =
  195. {
  196. if (time < self.attack_finished)
  197. return;
  198. self.attack_finished = time + 0.5;
  199. other.deathtype = "squish";
  200. T_Damage (other, self, self, self.dmg);
  201. };
  202. void() train_use =
  203. {
  204. if (self.think != func_train_find)
  205. return; // already activated
  206. train_next();
  207. };
  208. void() train_wait =
  209. {
  210. if (self.wait)
  211. {
  212. self.nextthink = self.ltime + self.wait;
  213. sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self.noise, 1, ATTN_NORM);
  214. }
  215. else
  216. self.nextthink = self.ltime + 0.1;
  217. self.think = train_next;
  218. };
  219. void() train_next =
  220. {
  221. local entity targ;
  222. targ = find (world, targetname, self.target);
  223. self.target = targ.target;
  224. if (!self.target)
  225. objerror ("train_next: no next target");
  226. if (targ.wait)
  227. self.wait = targ.wait;
  228. else
  229. self.wait = 0;
  230. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  231. SUB_CalcMove (targ.origin - self.mins, self.speed, train_wait);
  232. };
  233. void() func_train_find =
  234. {
  235. local entity targ;
  236. targ = find (world, targetname, self.target);
  237. self.target = targ.target;
  238. setorigin (self, targ.origin - self.mins);
  239. if (!self.targetname)
  240. { // not triggered, so start immediately
  241. self.nextthink = self.ltime + 0.1;
  242. self.think = train_next;
  243. }
  244. };
  245. /*QUAKED func_train (0 .5 .8) ?
  246. Trains are moving platforms that players can ride.
  247. The targets origin specifies the min point of the train at each corner.
  248. The train spawns at the first target it is pointing at.
  249. If the train is the target of a button or trigger, it will not begin moving until activated.
  250. speed default 100
  251. dmg default 2
  252. sounds
  253. 1) ratchet metal
  254. */
  255. void() func_train =
  256. {
  257. if (!self.speed)
  258. self.speed = 100;
  259. if (!self.target)
  260. objerror ("func_train without a target");
  261. if (!self.dmg)
  262. self.dmg = 2;
  263. if (self.sounds == 0)
  264. {
  265. self.noise = ("misc/null.wav");
  266. precache_sound ("misc/null.wav");
  267. self.noise1 = ("misc/null.wav");
  268. precache_sound ("misc/null.wav");
  269. }
  270. if (self.sounds == 1)
  271. {
  272. self.noise = ("plats/train2.wav");
  273. precache_sound ("plats/train2.wav");
  274. self.noise1 = ("plats/train1.wav");
  275. precache_sound ("plats/train1.wav");
  276. }
  277. self.cnt = 1;
  278. self.solid = SOLID_BSP;
  279. self.movetype = MOVETYPE_PUSH;
  280. self.blocked = train_blocked;
  281. self.use = train_use;
  282. self.classname = "train";
  283. setmodel (self, self.model);
  284. setsize (self, self.mins , self.maxs);
  285. setorigin (self, self.origin);
  286. // start trains on the second frame, to make sure their targets have had
  287. // a chance to spawn
  288. self.nextthink = self.ltime + 0.1;
  289. self.think = func_train_find;
  290. };
  291. /*QUAKED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8)
  292. This is used for the final bos
  293. */
  294. void() misc_teleporttrain =
  295. {
  296. if (!self.speed)
  297. self.speed = 100;
  298. if (!self.target)
  299. objerror ("func_train without a target");
  300. self.cnt = 1;
  301. self.solid = SOLID_NOT;
  302. self.movetype = MOVETYPE_PUSH;
  303. self.blocked = train_blocked;
  304. self.use = train_use;
  305. self.avelocity = '100 200 300';
  306. self.noise = ("misc/null.wav");
  307. precache_sound ("misc/null.wav");
  308. self.noise1 = ("misc/null.wav");
  309. precache_sound ("misc/null.wav");
  310. precache_model2 ("progs/teleport.mdl");
  311. setmodel (self, "progs/teleport.mdl");
  312. setsize (self, self.mins , self.maxs);
  313. setorigin (self, self.origin);
  314. // start trains on the second frame, to make sure their targets have had
  315. // a chance to spawn
  316. self.nextthink = self.ltime + 0.1;
  317. self.think = func_train_find;
  318. };