newplats.qc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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. // newplats.qc
  16. // pmack
  17. // september 1996
  18. // TYPES
  19. float DN_N_WAIT = 1;
  20. float PLT_TOGGLE = 2;
  21. float ELEVATOR = 4;
  22. float START_AT_TOP = 8;
  23. float PLAT2 = 16;
  24. float PLAT2_BOTTOM = 32;
  25. var float elvButnDir = 0;
  26. // ==================================
  27. // down N and wait code
  28. // ==================================
  29. void() dn_and_wait_go_up;
  30. void() dn_and_wait_go_down;
  31. void() dn_and_wait_crush;
  32. void() dn_and_wait_hit_top =
  33. {
  34. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  35. self.state = STATE_TOP;
  36. };
  37. void() dn_and_wait_hit_bottom =
  38. {
  39. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  40. self.state = STATE_BOTTOM;
  41. self.think = dn_and_wait_go_up;
  42. self.nextthink = self.ltime + self.health;
  43. };
  44. void() dn_and_wait_go_down =
  45. {
  46. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  47. self.state = STATE_DOWN;
  48. SUB_CalcMove (self.pos2, self.speed, dn_and_wait_hit_bottom);
  49. };
  50. void() dn_and_wait_go_up =
  51. {
  52. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  53. self.state = STATE_UP;
  54. SUB_CalcMove (self.pos1, self.speed, dn_and_wait_hit_top);
  55. };
  56. void() dn_and_wait_crush =
  57. {
  58. T_Damage (other, self, self, 1);
  59. if (self.state == STATE_UP)
  60. dn_and_wait_go_down ();
  61. else if (self.state == STATE_DOWN)
  62. dn_and_wait_go_up ();
  63. else
  64. objerror ("plat_new_crush: bad self.state\n");
  65. };
  66. void() dn_and_wait_use =
  67. {
  68. if (self.state != STATE_TOP)
  69. return;
  70. dn_and_wait_go_down ();
  71. };
  72. // ==================================
  73. // toggle type code
  74. // ==================================
  75. void() toggle_go_up;
  76. void() toggle_go_down;
  77. void() toggle_crush;
  78. void() toggle_hit_top =
  79. {
  80. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  81. self.state = STATE_TOP;
  82. };
  83. void() toggle_hit_bottom =
  84. {
  85. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  86. self.state = STATE_BOTTOM;
  87. };
  88. void() toggle_go_down =
  89. {
  90. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  91. self.state = STATE_DOWN;
  92. SUB_CalcMove (self.pos2, self.speed, toggle_hit_bottom);
  93. };
  94. void() toggle_go_up =
  95. {
  96. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  97. self.state = STATE_UP;
  98. SUB_CalcMove (self.pos1, self.speed, toggle_hit_top);
  99. };
  100. void() toggle_crush =
  101. {
  102. T_Damage (other, self, self, 1);
  103. if (self.state == STATE_UP)
  104. toggle_go_down ();
  105. else if (self.state == STATE_DOWN)
  106. toggle_go_up ();
  107. else
  108. objerror ("plat_new_crush: bad self.state\n");
  109. };
  110. void() toggle_use =
  111. {
  112. if (self.state == STATE_TOP)
  113. toggle_go_down ();
  114. else if(self.state == STATE_BOTTOM)
  115. toggle_go_up ();
  116. };
  117. // ==================================
  118. // elvtr type code
  119. // ==================================
  120. void() elvtr_crush;
  121. void() elvtr_stop =
  122. {
  123. self.elevatorOnFloor = self.elevatorToFloor;
  124. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  125. self.state = STATE_BOTTOM;
  126. self.elevatorLastUse = time;
  127. };
  128. void() elvtr_go =
  129. {
  130. self.elevatorDestination = self.pos2;
  131. self.elevatorDestination_z = self.pos2_z +
  132. (self.height * self.elevatorToFloor);
  133. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  134. self.state = STATE_UP;
  135. SUB_CalcMove (self.elevatorDestination, self.speed, elvtr_stop);
  136. self.elevatorLastUse = time;
  137. };
  138. void() elvtr_crush =
  139. {
  140. // T_Damage (other, self, self, 1);
  141. self.elevatorToFloor = self.elevatorOnFloor;
  142. elvtr_go ();
  143. };
  144. // ===============
  145. // elevator use function
  146. // self = plat, other = elevator button, other.enemy = player
  147. // ===============
  148. void() elvtr_use =
  149. {
  150. local float tempDist, elvPos, btnPos;
  151. if ( (self.elevatorLastUse + 2) > time)
  152. return;
  153. self.elevatorLastUse = time;
  154. if (elvButnDir == 0)
  155. return;
  156. elvPos = (self.absmin_z + self.absmax_z) * 0.5;
  157. btnPos = (other.absmin_z + other.absmax_z) * 0.5;
  158. if (elvPos > btnPos)
  159. {
  160. tempDist = (elvPos - btnPos) / self.height;
  161. tempDist = ceil ( tempDist);
  162. self.elevatorToFloor = self.elevatorOnFloor - tempDist;
  163. elvtr_go ();
  164. return;
  165. }
  166. else
  167. {
  168. tempDist = btnPos - elvPos;
  169. if (tempDist > self.height)
  170. {
  171. tempDist = tempDist / self.height;
  172. tempDist = floor ( tempDist );
  173. self.elevatorToFloor = self.elevatorOnFloor + tempDist;
  174. elvtr_go ();
  175. return;
  176. }
  177. }
  178. if (elvButnDir == -1)
  179. {
  180. if(self.elevatorOnFloor > 0)
  181. {
  182. self.elevatorToFloor = self.elevatorOnFloor - 1;
  183. elvtr_go ();
  184. }
  185. }
  186. else if(elvButnDir == 1)
  187. {
  188. if(self.elevatorOnFloor < (self.cnt - 1))
  189. {
  190. self.elevatorToFloor = self.elevatorOnFloor + 1;
  191. elvtr_go ();
  192. }
  193. }
  194. };
  195. // ==================================
  196. // PLAT2 type code
  197. // ==================================
  198. void() plat2_center_touch;
  199. void() plat2_go_up;
  200. void() plat2_go_down;
  201. void() plat2_crush;
  202. void() plat2_spawn_inside_trigger =
  203. {
  204. local entity trigger;
  205. local vector tmin, tmax;
  206. //
  207. // middle trigger
  208. //
  209. trigger = spawn();
  210. trigger.touch = plat2_center_touch;
  211. trigger.movetype = MOVETYPE_NONE;
  212. trigger.solid = SOLID_TRIGGER;
  213. trigger.enemy = self;
  214. tmin = self.mins + '25 25 0';
  215. tmax = self.maxs - '25 25 -8';
  216. tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
  217. if (self.spawnflags & PLAT_LOW_TRIGGER)
  218. tmax_z = tmin_z + 8;
  219. if (self.size_x <= 50)
  220. {
  221. tmin_x = (self.mins_x + self.maxs_x) / 2;
  222. tmax_x = tmin_x + 1;
  223. }
  224. if (self.size_y <= 50)
  225. {
  226. tmin_y = (self.mins_y + self.maxs_y) / 2;
  227. tmax_y = tmin_y + 1;
  228. }
  229. setsize (trigger, tmin, tmax);
  230. };
  231. void() plat2_hit_top =
  232. {
  233. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  234. self.state = STATE_TOP;
  235. self.plat2LastMove = time;
  236. if(self.plat2Called == 1)
  237. {
  238. self.think = plat2_go_down;
  239. self.nextthink = self.ltime + 1.5;
  240. self.plat2Called = 0;
  241. self.plat2LastMove = 0; // allow immediate move
  242. }
  243. else if(!(self.spawnflags & START_AT_TOP))
  244. {
  245. self.think = plat2_go_down;
  246. self.nextthink = self.ltime + self.delay;
  247. self.plat2Called = 0;
  248. }
  249. };
  250. void() plat2_hit_bottom =
  251. {
  252. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  253. self.state = STATE_BOTTOM;
  254. self.plat2LastMove = time;
  255. if(self.plat2Called == 1)
  256. {
  257. self.think = plat2_go_up;
  258. self.nextthink = self.ltime + 1.5;
  259. self.plat2Called = 0;
  260. self.plat2LastMove = 0; // allow immediate move
  261. }
  262. else if(self.spawnflags & START_AT_TOP)
  263. {
  264. self.think = plat2_go_up;
  265. self.nextthink = self.ltime + self.delay;
  266. self.plat2Called = 0;
  267. }
  268. };
  269. void() plat2_go_down =
  270. {
  271. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  272. self.state = STATE_DOWN;
  273. SUB_CalcMove (self.pos2, self.speed, plat2_hit_bottom);
  274. };
  275. void() plat2_go_up =
  276. {
  277. sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  278. self.state = STATE_UP;
  279. SUB_CalcMove (self.pos1, self.speed, plat2_hit_top);
  280. };
  281. void() plat2_use =
  282. {
  283. if(self.state > 4)
  284. self.state = self.state - 10;
  285. self.use = SUB_Null;
  286. };
  287. void() plat2_center_touch =
  288. {
  289. local float otherState;
  290. local vector platPosition;
  291. if (other.classname != "player")
  292. return;
  293. if (other.health <= 0)
  294. return;
  295. // at this point, self is the trigger. self.enemy is the plat.
  296. // this changes self to be the plat, other is the player.
  297. self = self.enemy;
  298. if ((self.plat2LastMove + 2) > time)
  299. return;
  300. if (self.state > 4) // disabled.
  301. return;
  302. if (self.plat2GoTo > STATE_BOTTOM)
  303. {
  304. if (self.plat2GoTime < time)
  305. {
  306. if (self.plat2GoTo == STATE_UP)
  307. plat2_go_up();
  308. else
  309. plat2_go_down();
  310. self.plat2GoTo = 0;
  311. }
  312. return;
  313. }
  314. if (self.state > STATE_BOTTOM) // STATE_UP or STATE_DOWN
  315. return;
  316. platPosition = (self.absmax + self.absmin) * 0.5;
  317. if (self.state == STATE_TOP)
  318. {
  319. otherState = STATE_TOP;
  320. if ( platPosition_z > other.origin_z )
  321. otherState = STATE_BOTTOM;
  322. }
  323. else
  324. {
  325. otherState = STATE_BOTTOM;
  326. if ( (other.origin_z - platPosition_z) > self.height)
  327. otherState = STATE_TOP;
  328. }
  329. if (self.state == otherState)
  330. {
  331. self.plat2Called = 0;
  332. self.plat2GoTime = time + 0.5;
  333. }
  334. else
  335. {
  336. self.plat2GoTime = time + 0.1;
  337. self.plat2Called = 1;
  338. }
  339. if (self.state == STATE_BOTTOM)
  340. self.plat2GoTo = STATE_UP;
  341. else if(self.state == STATE_TOP)
  342. self.plat2GoTo = STATE_DOWN;
  343. };
  344. void() plat2_crush =
  345. {
  346. T_Damage (other, self, self, 1);
  347. if (self.state == STATE_UP)
  348. plat2_go_down ();
  349. else if (self.state == STATE_DOWN)
  350. plat2_go_up ();
  351. else
  352. objerror ("plat2_crush: bad self.state\n");
  353. };
  354. // ==================================
  355. // Common Plat Code
  356. // ==================================
  357. /*QUAKED func_new_plat (0 .5 .8) ? DN_N_WAIT PLT_TOGGLE ELEVATOR START_AT_TOP PLAT2 P2_BOTTOM
  358. --------------
  359. DN_N_WAIT is a plat that starts at the top and when triggered, goes down, waits, then comes back up.
  360. health - number of seconds to wait (default 5)
  361. --------------
  362. PLT_TOGGLE is a plat that will change between the top and bottom each time it is triggered.
  363. --------------
  364. ELEVATOR is an elevator plat. You can have as many levels as you want but they must be all the same distance away. Use elevator button entity as the trigger.
  365. cnt is the number of floors
  366. height is the distance between floors
  367. START_AT_TOP is an optional flag for elevators. It just tells the elevator that it's position is the top floor. (Default is the bottom floor) USE THIS ONLY WITH ELEVATORS!
  368. --------------
  369. PLAT2 is a fixed version of the original plat. If you want the plat to start at the bottom and move to the top on demand, use a negative height. That will tell Quake to lower the plat at spawn time. Always place this plat type in the top position when making the map. This will ensure correct lighting, hopefully. If a plat2 is the target of a trigger, it will be disabled until it has been triggered. Delay is the wait before the plat returns to original position.
  370. If you don't want to bother figuring out the height, don't put a
  371. value in the height
  372. delay default 3
  373. speed default 150
  374. cnt default 2
  375. P2_BOTTOM is an optional switch to have an auto-sized plat2 start at the bottom.
  376. --------------
  377. Plats are always drawn in the extended position, so they will light correctly.
  378. 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.
  379. If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height.
  380. Set "sounds" to one of the following:
  381. 1) base fast
  382. 2) chain slow
  383. */
  384. void() func_new_plat =
  385. {
  386. //local entity t;
  387. local float negativeHeight;
  388. negativeHeight = 0;
  389. if (!self.t_length)
  390. self.t_length = 80;
  391. if (!self.t_width)
  392. self.t_width = 10;
  393. if (self.sounds == 0)
  394. self.sounds = 2;
  395. // FIX THIS TO LOAD A GENERIC PLAT SOUND
  396. if (self.sounds == 1)
  397. {
  398. precache_sound ("plats/plat1.wav");
  399. precache_sound ("plats/plat2.wav");
  400. self.noise = "plats/plat1.wav";
  401. self.noise1 = "plats/plat2.wav";
  402. }
  403. if (self.sounds == 2)
  404. {
  405. precache_sound ("plats/medplat1.wav");
  406. precache_sound ("plats/medplat2.wav");
  407. self.noise = "plats/medplat1.wav";
  408. self.noise1 = "plats/medplat2.wav";
  409. }
  410. self.mangle = self.angles;
  411. self.angles = '0 0 0';
  412. self.classname = "plat";
  413. self.solid = SOLID_BSP;
  414. self.movetype = MOVETYPE_PUSH;
  415. setorigin (self, self.origin);
  416. setmodel (self, self.model);
  417. setsize (self, self.mins , self.maxs);
  418. if (!self.speed)
  419. self.speed = 150;
  420. // pos1 is the top position, pos2 is the bottom
  421. self.pos1 = self.origin;
  422. self.pos2 = self.origin;
  423. if (self.height < 0)
  424. {
  425. negativeHeight = 1;
  426. self.height = 0 - self.height;
  427. }
  428. if (self.height)
  429. self.pos2_z = self.origin_z - self.height;
  430. else
  431. {
  432. negativeHeight = 1;
  433. self.height = self.size_z - 8;
  434. self.pos2_z = self.origin_z - self.height;
  435. }
  436. if (self.spawnflags & DN_N_WAIT)
  437. {
  438. self.use = dn_and_wait_use;
  439. self.blocked = dn_and_wait_crush;
  440. if (negativeHeight == 1)
  441. {
  442. self.state = STATE_BOTTOM;
  443. setorigin (self, self.pos2);
  444. }
  445. else
  446. self.state = STATE_TOP;
  447. if (!self.health)
  448. self.health = 5;
  449. }
  450. else if (self.spawnflags & PLT_TOGGLE)
  451. {
  452. self.use = toggle_use;
  453. self.blocked = toggle_crush;
  454. if (negativeHeight == 1)
  455. {
  456. setorigin (self, self.pos2);
  457. self.state = STATE_BOTTOM;
  458. }
  459. else
  460. {
  461. self.state = STATE_TOP;
  462. }
  463. }
  464. else if (self.spawnflags & ELEVATOR)
  465. {
  466. self.elevatorOnFloor = 0;
  467. self.elevatorToFloor = 0;
  468. self.elevatorLastUse = 0;
  469. if (self.spawnflags & START_AT_TOP)
  470. {
  471. self.pos1 = self.origin;
  472. self.pos2 = self.origin;
  473. self.pos2_z = self.origin_z - (self.height * (self.cnt - 1));
  474. self.elevatorOnFloor = self.cnt - 1;
  475. }
  476. else
  477. {
  478. self.pos1 = self.origin;
  479. self.pos2 = self.origin;
  480. self.pos1_z = self.origin_z + (self.height * (self.cnt - 1));
  481. self.elevatorOnFloor = 0;
  482. }
  483. self.use = elvtr_use;
  484. self.blocked = elvtr_crush;
  485. }
  486. else if (self.spawnflags & PLAT2)
  487. {
  488. plat2_spawn_inside_trigger (); // the "start moving" trigger
  489. self.plat2Called = 0;
  490. self.plat2LastMove = 0;
  491. self.plat2GoTo = 0;
  492. self.plat2GoTime = 0;
  493. self.blocked = plat2_crush;
  494. if (!self.delay)
  495. self.delay = 3;
  496. if (negativeHeight == 1)
  497. {
  498. self.state = STATE_BOTTOM;
  499. // make sure START_AT_TOP isn't set. We need that...
  500. self.spawnflags = PLAT2;
  501. setorigin (self, self.pos2);
  502. }
  503. else
  504. {
  505. // default position is top.
  506. self.spawnflags = self.spawnflags | START_AT_TOP;
  507. self.state = STATE_TOP;
  508. }
  509. if (self.targetname)
  510. {
  511. self.use = plat2_use;
  512. self.state = self.state + 10;
  513. }
  514. }
  515. };