p_floor.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2000 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * General plane mover and floor mover action routines
  31. * Floor motion, pure changer types, raising stairs. donuts, elevators
  32. *
  33. *-----------------------------------------------------------------------------*/
  34. #include "doomstat.h"
  35. #include "r_main.h"
  36. #include "p_map.h"
  37. #include "p_spec.h"
  38. #include "p_tick.h"
  39. #include "s_sound.h"
  40. #include "sounds.h"
  41. ///////////////////////////////////////////////////////////////////////
  42. //
  43. // Plane (floor or ceiling), Floor motion and Elevator action routines
  44. //
  45. ///////////////////////////////////////////////////////////////////////
  46. //
  47. // T_MovePlane()
  48. //
  49. // Move a plane (floor or ceiling) and check for crushing. Called
  50. // every tick by all actions that move floors or ceilings.
  51. //
  52. // Passed the sector to move a plane in, the speed to move it at,
  53. // the dest height it is to achieve, whether it crushes obstacles,
  54. // whether it moves a floor or ceiling, and the direction up or down
  55. // to move.
  56. //
  57. // Returns a result_e:
  58. // ok - plane moved normally, has not achieved destination yet
  59. // pastdest - plane moved normally and is now at destination height
  60. // crushed - plane encountered an obstacle, is holding until removed
  61. //
  62. result_e T_MovePlane
  63. ( sector_t* sector,
  64. fixed_t speed,
  65. fixed_t dest,
  66. boolean crush,
  67. int floorOrCeiling,
  68. int direction )
  69. {
  70. boolean flag;
  71. fixed_t lastpos;
  72. fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings
  73. // from moving thru each other
  74. switch(floorOrCeiling)
  75. {
  76. case 0:
  77. // Moving a floor
  78. switch(direction)
  79. {
  80. case -1:
  81. // Moving a floor down
  82. if (sector->floorheight - speed < dest)
  83. {
  84. lastpos = sector->floorheight;
  85. sector->floorheight = dest;
  86. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  87. if (flag == true)
  88. {
  89. sector->floorheight =lastpos;
  90. P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  91. }
  92. return pastdest;
  93. }
  94. else
  95. {
  96. lastpos = sector->floorheight;
  97. sector->floorheight -= speed;
  98. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  99. /* cph - make more compatible with original Doom, by
  100. * reintroducing this code. This means floors can't lower
  101. * if objects are stuck in the ceiling */
  102. if ((flag == true) && comp[comp_floors]) {
  103. sector->floorheight = lastpos;
  104. P_ChangeSector(sector,crush);
  105. return crushed;
  106. }
  107. }
  108. break;
  109. case 1:
  110. // Moving a floor up
  111. // jff 02/04/98 keep floor from moving thru ceilings
  112. // jff 2/22/98 weaken check to demo_compatibility
  113. destheight = (comp[comp_floors] || dest<sector->ceilingheight)?
  114. dest : sector->ceilingheight;
  115. if (sector->floorheight + speed > destheight)
  116. {
  117. lastpos = sector->floorheight;
  118. sector->floorheight = destheight;
  119. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  120. if (flag == true)
  121. {
  122. sector->floorheight = lastpos;
  123. P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  124. }
  125. return pastdest;
  126. }
  127. else
  128. {
  129. // crushing is possible
  130. lastpos = sector->floorheight;
  131. sector->floorheight += speed;
  132. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  133. if (flag == true)
  134. {
  135. /* jff 1/25/98 fix floor crusher */
  136. if (comp[comp_floors]) {
  137. if (crush == true)
  138. return crushed;
  139. }
  140. sector->floorheight = lastpos;
  141. P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  142. return crushed;
  143. }
  144. }
  145. break;
  146. }
  147. break;
  148. case 1:
  149. // moving a ceiling
  150. switch(direction)
  151. {
  152. case -1:
  153. // moving a ceiling down
  154. // jff 02/04/98 keep ceiling from moving thru floors
  155. // jff 2/22/98 weaken check to demo_compatibility
  156. destheight = (comp[comp_floors] || dest>sector->floorheight)?
  157. dest : sector->floorheight;
  158. if (sector->ceilingheight - speed < destheight)
  159. {
  160. lastpos = sector->ceilingheight;
  161. sector->ceilingheight = destheight;
  162. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  163. if (flag == true)
  164. {
  165. sector->ceilingheight = lastpos;
  166. P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  167. }
  168. return pastdest;
  169. }
  170. else
  171. {
  172. // crushing is possible
  173. lastpos = sector->ceilingheight;
  174. sector->ceilingheight -= speed;
  175. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  176. if (flag == true)
  177. {
  178. if (crush == true)
  179. return crushed;
  180. sector->ceilingheight = lastpos;
  181. P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  182. return crushed;
  183. }
  184. }
  185. break;
  186. case 1:
  187. // moving a ceiling up
  188. if (sector->ceilingheight + speed > dest)
  189. {
  190. lastpos = sector->ceilingheight;
  191. sector->ceilingheight = dest;
  192. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  193. if (flag == true)
  194. {
  195. sector->ceilingheight = lastpos;
  196. P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  197. }
  198. return pastdest;
  199. }
  200. else
  201. {
  202. lastpos = sector->ceilingheight;
  203. sector->ceilingheight += speed;
  204. flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
  205. }
  206. break;
  207. }
  208. break;
  209. }
  210. return ok;
  211. }
  212. //
  213. // T_MoveFloor()
  214. //
  215. // Move a floor to it's destination (up or down).
  216. // Called once per tick for each moving floor.
  217. //
  218. // Passed a floormove_t structure that contains all pertinent info about the
  219. // move. See P_SPEC.H for fields.
  220. // No return.
  221. //
  222. // jff 02/08/98 all cases with labels beginning with gen added to support
  223. // generalized line type behaviors.
  224. void T_MoveFloor(floormove_t* floor)
  225. {
  226. result_e res;
  227. res = T_MovePlane // move the floor
  228. (
  229. floor->sector,
  230. floor->speed,
  231. floor->floordestheight,
  232. floor->crush,
  233. 0,
  234. floor->direction
  235. );
  236. if (!(leveltime&7)) // make the floormove sound
  237. S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov);
  238. if (res == pastdest) // if destination height is reached
  239. {
  240. if (floor->direction == 1) // going up
  241. {
  242. switch(floor->type) // handle texture/type changes
  243. {
  244. case donutRaise:
  245. floor->sector->special = floor->newspecial;
  246. floor->sector->floorpic = floor->texture;
  247. break;
  248. case genFloorChgT:
  249. case genFloorChg0:
  250. floor->sector->special = floor->newspecial;
  251. //jff add to fix bug in special transfers from changes
  252. floor->sector->oldspecial = floor->oldspecial;
  253. //fall thru
  254. case genFloorChg:
  255. floor->sector->floorpic = floor->texture;
  256. break;
  257. default:
  258. break;
  259. }
  260. }
  261. else if (floor->direction == -1) // going down
  262. {
  263. switch(floor->type) // handle texture/type changes
  264. {
  265. case lowerAndChange:
  266. floor->sector->special = floor->newspecial;
  267. //jff add to fix bug in special transfers from changes
  268. floor->sector->oldspecial = floor->oldspecial;
  269. floor->sector->floorpic = floor->texture;
  270. break;
  271. case genFloorChgT:
  272. case genFloorChg0:
  273. floor->sector->special = floor->newspecial;
  274. //jff add to fix bug in special transfers from changes
  275. floor->sector->oldspecial = floor->oldspecial;
  276. //fall thru
  277. case genFloorChg:
  278. floor->sector->floorpic = floor->texture;
  279. break;
  280. default:
  281. break;
  282. }
  283. }
  284. floor->sector->floordata = NULL; //jff 2/22/98
  285. P_RemoveThinker(&floor->thinker);//remove this floor from list of movers
  286. //jff 2/26/98 implement stair retrigger lockout while still building
  287. // note this only applies to the retriggerable generalized stairs
  288. if (floor->sector->stairlock==-2) // if this sector is stairlocked
  289. {
  290. sector_t *sec = floor->sector;
  291. sec->stairlock=-1; // thinker done, promote lock to -1
  292. while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2)
  293. sec = &sectors[sec->prevsec]; // search for a non-done thinker
  294. if (sec->prevsec==-1) // if all thinkers previous are done
  295. {
  296. sec = floor->sector; // search forward
  297. while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2)
  298. sec = &sectors[sec->nextsec];
  299. if (sec->nextsec==-1) // if all thinkers ahead are done too
  300. {
  301. while (sec->prevsec!=-1) // clear all locks
  302. {
  303. sec->stairlock = 0;
  304. sec = &sectors[sec->prevsec];
  305. }
  306. sec->stairlock = 0;
  307. }
  308. }
  309. }
  310. // make floor stop sound
  311. S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop);
  312. }
  313. }
  314. //
  315. // T_MoveElevator()
  316. //
  317. // Move an elevator to it's destination (up or down)
  318. // Called once per tick for each moving floor.
  319. //
  320. // Passed an elevator_t structure that contains all pertinent info about the
  321. // move. See P_SPEC.H for fields.
  322. // No return.
  323. //
  324. // jff 02/22/98 added to support parallel floor/ceiling motion
  325. //
  326. void T_MoveElevator(elevator_t* elevator)
  327. {
  328. result_e res;
  329. if (elevator->direction<0) // moving down
  330. {
  331. res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
  332. (
  333. elevator->sector,
  334. elevator->speed,
  335. elevator->ceilingdestheight,
  336. 0,
  337. 1, // move floor
  338. elevator->direction
  339. );
  340. if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked
  341. T_MovePlane
  342. (
  343. elevator->sector,
  344. elevator->speed,
  345. elevator->floordestheight,
  346. 0,
  347. 0, // move ceiling
  348. elevator->direction
  349. );
  350. }
  351. else // up
  352. {
  353. res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
  354. (
  355. elevator->sector,
  356. elevator->speed,
  357. elevator->floordestheight,
  358. 0,
  359. 0, // move ceiling
  360. elevator->direction
  361. );
  362. if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked
  363. T_MovePlane
  364. (
  365. elevator->sector,
  366. elevator->speed,
  367. elevator->ceilingdestheight,
  368. 0,
  369. 1, // move floor
  370. elevator->direction
  371. );
  372. }
  373. // make floor move sound
  374. if (!(leveltime&7))
  375. S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov);
  376. if (res == pastdest) // if destination height acheived
  377. {
  378. elevator->sector->floordata = NULL; //jff 2/22/98
  379. elevator->sector->ceilingdata = NULL; //jff 2/22/98
  380. P_RemoveThinker(&elevator->thinker); // remove elevator from actives
  381. // make floor stop sound
  382. S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop);
  383. }
  384. }
  385. ///////////////////////////////////////////////////////////////////////
  386. //
  387. // Floor motion linedef handlers
  388. //
  389. ///////////////////////////////////////////////////////////////////////
  390. //
  391. // EV_DoFloor()
  392. //
  393. // Handle regular and extended floor types
  394. //
  395. // Passed the line that activated the floor and the type of floor motion
  396. // Returns true if a thinker was created.
  397. //
  398. int EV_DoFloor
  399. ( line_t* line,
  400. floor_e floortype )
  401. {
  402. int secnum;
  403. int rtn;
  404. int i;
  405. sector_t* sec;
  406. floormove_t* floor;
  407. secnum = -1;
  408. rtn = 0;
  409. // move all floors with the same tag as the linedef
  410. while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
  411. {
  412. sec = &sectors[secnum];
  413. // Don't start a second thinker on the same floor
  414. if (P_SectorActive(floor_special,sec)) //jff 2/23/98
  415. continue;
  416. // new floor thinker
  417. rtn = 1;
  418. floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
  419. memset(floor, 0, sizeof(*floor));
  420. P_AddThinker (&floor->thinker);
  421. sec->floordata = floor; //jff 2/22/98
  422. floor->thinker.function = T_MoveFloor;
  423. floor->type = floortype;
  424. floor->crush = false;
  425. // setup the thinker according to the linedef type
  426. switch(floortype)
  427. {
  428. case lowerFloor:
  429. floor->direction = -1;
  430. floor->sector = sec;
  431. floor->speed = FLOORSPEED;
  432. floor->floordestheight = P_FindHighestFloorSurrounding(sec);
  433. break;
  434. //jff 02/03/30 support lowering floor by 24 absolute
  435. case lowerFloor24:
  436. floor->direction = -1;
  437. floor->sector = sec;
  438. floor->speed = FLOORSPEED;
  439. floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
  440. break;
  441. //jff 02/03/30 support lowering floor by 32 absolute (fast)
  442. case lowerFloor32Turbo:
  443. floor->direction = -1;
  444. floor->sector = sec;
  445. floor->speed = FLOORSPEED*4;
  446. floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT;
  447. break;
  448. case lowerFloorToLowest:
  449. floor->direction = -1;
  450. floor->sector = sec;
  451. floor->speed = FLOORSPEED;
  452. floor->floordestheight = P_FindLowestFloorSurrounding(sec);
  453. break;
  454. //jff 02/03/30 support lowering floor to next lowest floor
  455. case lowerFloorToNearest:
  456. floor->direction = -1;
  457. floor->sector = sec;
  458. floor->speed = FLOORSPEED;
  459. floor->floordestheight =
  460. P_FindNextLowestFloor(sec,floor->sector->floorheight);
  461. break;
  462. case turboLower:
  463. floor->direction = -1;
  464. floor->sector = sec;
  465. floor->speed = FLOORSPEED * 4;
  466. floor->floordestheight = P_FindHighestFloorSurrounding(sec);
  467. if (floor->floordestheight != sec->floorheight)
  468. floor->floordestheight += 8*FRACUNIT;
  469. break;
  470. case raiseFloorCrush:
  471. floor->crush = true;
  472. case raiseFloor:
  473. floor->direction = 1;
  474. floor->sector = sec;
  475. floor->speed = FLOORSPEED;
  476. floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
  477. if (floor->floordestheight > sec->ceilingheight)
  478. floor->floordestheight = sec->ceilingheight;
  479. floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush);
  480. break;
  481. case raiseFloorTurbo:
  482. floor->direction = 1;
  483. floor->sector = sec;
  484. floor->speed = FLOORSPEED*4;
  485. floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
  486. break;
  487. case raiseFloorToNearest:
  488. floor->direction = 1;
  489. floor->sector = sec;
  490. floor->speed = FLOORSPEED;
  491. floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
  492. break;
  493. case raiseFloor24:
  494. floor->direction = 1;
  495. floor->sector = sec;
  496. floor->speed = FLOORSPEED;
  497. floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
  498. break;
  499. // jff 2/03/30 support straight raise by 32 (fast)
  500. case raiseFloor32Turbo:
  501. floor->direction = 1;
  502. floor->sector = sec;
  503. floor->speed = FLOORSPEED*4;
  504. floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT;
  505. break;
  506. case raiseFloor512:
  507. floor->direction = 1;
  508. floor->sector = sec;
  509. floor->speed = FLOORSPEED;
  510. floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT;
  511. break;
  512. case raiseFloor24AndChange:
  513. floor->direction = 1;
  514. floor->sector = sec;
  515. floor->speed = FLOORSPEED;
  516. floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
  517. sec->floorpic = line->frontsector->floorpic;
  518. sec->special = line->frontsector->special;
  519. //jff 3/14/98 transfer both old and new special
  520. sec->oldspecial = line->frontsector->oldspecial;
  521. break;
  522. case raiseToTexture:
  523. {
  524. int minsize = INT_MAX;
  525. side_t* side;
  526. /* jff 3/13/98 no ovf */
  527. if (!comp[comp_model]) minsize = 32000<<FRACBITS;
  528. floor->direction = 1;
  529. floor->sector = sec;
  530. floor->speed = FLOORSPEED;
  531. for (i = 0; i < sec->linecount; i++)
  532. {
  533. if (twoSided (secnum, i) )
  534. {
  535. side = getSide(secnum,i,0);
  536. // jff 8/14/98 don't scan texture 0, its not real
  537. if (side->bottomtexture > 0 ||
  538. (comp[comp_model] && !side->bottomtexture))
  539. if (textureheight[side->bottomtexture] < minsize)
  540. minsize = textureheight[side->bottomtexture];
  541. side = getSide(secnum,i,1);
  542. // jff 8/14/98 don't scan texture 0, its not real
  543. if (side->bottomtexture > 0 ||
  544. (comp[comp_model] && !side->bottomtexture))
  545. if (textureheight[side->bottomtexture] < minsize)
  546. minsize = textureheight[side->bottomtexture];
  547. }
  548. }
  549. if (comp[comp_model])
  550. floor->floordestheight = floor->sector->floorheight + minsize;
  551. else
  552. {
  553. floor->floordestheight =
  554. (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS);
  555. if (floor->floordestheight>32000)
  556. floor->floordestheight = 32000; //jff 3/13/98 do not
  557. floor->floordestheight<<=FRACBITS; // allow height overflow
  558. }
  559. }
  560. break;
  561. case lowerAndChange:
  562. floor->direction = -1;
  563. floor->sector = sec;
  564. floor->speed = FLOORSPEED;
  565. floor->floordestheight = P_FindLowestFloorSurrounding(sec);
  566. floor->texture = sec->floorpic;
  567. // jff 1/24/98 make sure floor->newspecial gets initialized
  568. // in case no surrounding sector is at floordestheight
  569. // --> should not affect compatibility <--
  570. floor->newspecial = sec->special;
  571. //jff 3/14/98 transfer both old and new special
  572. floor->oldspecial = sec->oldspecial;
  573. //jff 5/23/98 use model subroutine to unify fixes and handling
  574. sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors);
  575. if (sec)
  576. {
  577. floor->texture = sec->floorpic;
  578. floor->newspecial = sec->special;
  579. //jff 3/14/98 transfer both old and new special
  580. floor->oldspecial = sec->oldspecial;
  581. }
  582. break;
  583. default:
  584. break;
  585. }
  586. }
  587. return rtn;
  588. }
  589. //
  590. // EV_DoChange()
  591. //
  592. // Handle pure change types. These change floor texture and sector type
  593. // by trigger or numeric model without moving the floor.
  594. //
  595. // The linedef causing the change and the type of change is passed
  596. // Returns true if any sector changes
  597. //
  598. // jff 3/15/98 added to better support generalized sector types
  599. //
  600. int EV_DoChange
  601. ( line_t* line,
  602. change_e changetype )
  603. {
  604. int secnum;
  605. int rtn;
  606. sector_t* sec;
  607. sector_t* secm;
  608. secnum = -1;
  609. rtn = 0;
  610. // change all sectors with the same tag as the linedef
  611. while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
  612. {
  613. sec = &sectors[secnum];
  614. rtn = 1;
  615. // handle trigger or numeric change type
  616. switch(changetype)
  617. {
  618. case trigChangeOnly:
  619. sec->floorpic = line->frontsector->floorpic;
  620. sec->special = line->frontsector->special;
  621. sec->oldspecial = line->frontsector->oldspecial;
  622. break;
  623. case numChangeOnly:
  624. secm = P_FindModelFloorSector(sec->floorheight,secnum);
  625. if (secm) // if no model, no change
  626. {
  627. sec->floorpic = secm->floorpic;
  628. sec->special = secm->special;
  629. sec->oldspecial = secm->oldspecial;
  630. }
  631. break;
  632. default:
  633. break;
  634. }
  635. }
  636. return rtn;
  637. }
  638. /*
  639. * EV_BuildStairs()
  640. *
  641. * Handles staircase building. A sequence of sectors chosen by algorithm
  642. * rise at a speed indicated to a height that increases by the stepsize
  643. * each step.
  644. *
  645. * Passed the linedef triggering the stairs and the type of stair rise
  646. * Returns true if any thinkers are created
  647. *
  648. * cph 2001/09/21 - compatibility nightmares again
  649. * There are three different ways this function has, during its history, stepped
  650. * through all the stairs to be triggered by the single switch
  651. * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve
  652. * the index of the previous sector found, so instead it would restart its
  653. * linear search from the last sector of the previous staircase
  654. * - MBF/PrBoom with comp_stairs fail to emulate this, because their
  655. * P_FindSectorFromLineTag is a chained hash table implementation. Instead they
  656. * start following the hash chain from the last sector of the previous
  657. * staircase, which will (probably) have the wrong tag, so they miss any further
  658. * stairs
  659. * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right
  660. */
  661. static inline int P_FindSectorFromLineTagWithLowerBound
  662. (line_t* l, int start, int min)
  663. {
  664. /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag
  665. * as needed */
  666. do {
  667. start = P_FindSectorFromLineTag(l,start);
  668. } while (start >= 0 && start <= min);
  669. return start;
  670. }
  671. int EV_BuildStairs
  672. ( line_t* line,
  673. stair_e type )
  674. {
  675. /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate
  676. * outer loop index makes the logic much cleared, and local variables moved
  677. * into the inner blocks helps too */
  678. int ssec = -1;
  679. int minssec = -1;
  680. int rtn = 0;
  681. // start a stair at each sector tagged the same as the linedef
  682. while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0)
  683. {
  684. int secnum = ssec;
  685. sector_t* sec = &sectors[secnum];
  686. // don't start a stair if the first step's floor is already moving
  687. if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98
  688. floormove_t* floor;
  689. int texture, height;
  690. fixed_t stairsize;
  691. fixed_t speed;
  692. int ok;
  693. // create new floor thinker for first step
  694. rtn = 1;
  695. floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
  696. memset(floor, 0, sizeof(*floor));
  697. P_AddThinker (&floor->thinker);
  698. sec->floordata = floor;
  699. floor->thinker.function = T_MoveFloor;
  700. floor->direction = 1;
  701. floor->sector = sec;
  702. floor->type = buildStair; //jff 3/31/98 do not leave uninited
  703. // set up the speed and stepsize according to the stairs type
  704. switch(type)
  705. {
  706. default: // killough -- prevent compiler warning
  707. case build8:
  708. speed = FLOORSPEED/4;
  709. stairsize = 8*FRACUNIT;
  710. if (!demo_compatibility)
  711. floor->crush = false; //jff 2/27/98 fix uninitialized crush field
  712. break;
  713. case turbo16:
  714. speed = FLOORSPEED*4;
  715. stairsize = 16*FRACUNIT;
  716. if (!demo_compatibility)
  717. floor->crush = true; //jff 2/27/98 fix uninitialized crush field
  718. break;
  719. }
  720. floor->speed = speed;
  721. height = sec->floorheight + stairsize;
  722. floor->floordestheight = height;
  723. texture = sec->floorpic;
  724. // Find next sector to raise
  725. // 1. Find 2-sided line with same sector side[0] (lowest numbered)
  726. // 2. Other side is the next sector to raise
  727. // 3. Unless already moving, or different texture, then stop building
  728. do
  729. {
  730. int i;
  731. ok = 0;
  732. for (i = 0;i < sec->linecount;i++)
  733. {
  734. sector_t* tsec = (sec->lines[i])->frontsector;
  735. int newsecnum;
  736. if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
  737. continue;
  738. newsecnum = tsec-sectors;
  739. if (secnum != newsecnum)
  740. continue;
  741. tsec = (sec->lines[i])->backsector;
  742. if (!tsec) continue; //jff 5/7/98 if no backside, continue
  743. newsecnum = tsec - sectors;
  744. // if sector's floor is different texture, look for another
  745. if (tsec->floorpic != texture)
  746. continue;
  747. /* jff 6/19/98 prevent double stepsize
  748. * killough 10/98: intentionally left this way [MBF comment]
  749. * cph 2001/02/06: stair bug fix should be controlled by comp_stairs,
  750. * except if we're emulating MBF which perversly reverted the fix
  751. */
  752. if (comp[comp_stairs] || (compatibility_level == mbf_compatibility))
  753. height += stairsize; // jff 6/28/98 change demo compatibility
  754. // if sector's floor already moving, look for another
  755. if (P_SectorActive(floor_special,tsec)) //jff 2/22/98
  756. continue;
  757. /* cph - see comment above - do this iff we didn't do so above */
  758. if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility))
  759. height += stairsize;
  760. sec = tsec;
  761. secnum = newsecnum;
  762. // create and initialize a thinker for the next step
  763. floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
  764. memset(floor, 0, sizeof(*floor));
  765. P_AddThinker (&floor->thinker);
  766. sec->floordata = floor; //jff 2/22/98
  767. floor->thinker.function = T_MoveFloor;
  768. floor->direction = 1;
  769. floor->sector = sec;
  770. floor->speed = speed;
  771. floor->floordestheight = height;
  772. floor->type = buildStair; //jff 3/31/98 do not leave uninited
  773. //jff 2/27/98 fix uninitialized crush field
  774. if (!demo_compatibility)
  775. floor->crush = type==build8? false : true;
  776. ok = 1;
  777. break;
  778. }
  779. } while(ok); // continue until no next step is found
  780. }
  781. /* killough 10/98: compatibility option */
  782. if (comp[comp_stairs]) {
  783. /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic
  784. * reversed since we now have a separate outer loop index.
  785. * DEMOSYNC - what about boom_compatibility_compatibility?
  786. */
  787. if ((compatibility_level >= mbf_compatibility) && (compatibility_level <
  788. prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */
  789. else {
  790. /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear
  791. * search from the last secnum, so we set that as a minimum value and do
  792. * a fresh tag search
  793. */
  794. ssec = -1; minssec = secnum;
  795. }
  796. }
  797. }
  798. return rtn;
  799. }
  800. //
  801. // EV_DoDonut()
  802. //
  803. // Handle donut function: lower pillar, raise surrounding pool, both to height,
  804. // texture and type of the sector surrounding the pool.
  805. //
  806. // Passed the linedef that triggered the donut
  807. // Returns whether a thinker was created
  808. //
  809. int EV_DoDonut(line_t* line)
  810. {
  811. sector_t* s1;
  812. sector_t* s2;
  813. sector_t* s3;
  814. int secnum;
  815. int rtn;
  816. int i;
  817. floormove_t* floor;
  818. secnum = -1;
  819. rtn = 0;
  820. // do function on all sectors with same tag as linedef
  821. while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
  822. {
  823. s1 = &sectors[secnum]; // s1 is pillar's sector
  824. // do not start the donut if the pillar is already moving
  825. if (P_SectorActive(floor_special,s1)) //jff 2/22/98
  826. continue;
  827. s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector
  828. if (!s2) continue; // note lowest numbered line around
  829. // pillar must be two-sided
  830. /* do not start the donut if the pool is already moving
  831. * cph - DEMOSYNC - was !compatibility */
  832. if (!comp[comp_floors] && P_SectorActive(floor_special,s2))
  833. continue; //jff 5/7/98
  834. // find a two sided line around the pool whose other side isn't the pillar
  835. for (i = 0;i < s2->linecount;i++)
  836. {
  837. //jff 3/29/98 use true two-sidedness, not the flag
  838. // killough 4/5/98: changed demo_compatibility to compatibility
  839. if (comp[comp_model])
  840. {
  841. if ((!s2->lines[i]->flags & ML_TWOSIDED) ||
  842. (s2->lines[i]->backsector == s1))
  843. continue;
  844. }
  845. else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1)
  846. continue;
  847. rtn = 1; //jff 1/26/98 no donut action - no switch change on return
  848. s3 = s2->lines[i]->backsector; // s3 is model sector for changes
  849. // Spawn rising slime
  850. floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
  851. memset(floor, 0, sizeof(*floor));
  852. P_AddThinker (&floor->thinker);
  853. s2->floordata = floor; //jff 2/22/98
  854. floor->thinker.function = T_MoveFloor;
  855. floor->type = donutRaise;
  856. floor->crush = false;
  857. floor->direction = 1;
  858. floor->sector = s2;
  859. floor->speed = FLOORSPEED / 2;
  860. floor->texture = s3->floorpic;
  861. floor->newspecial = 0;
  862. floor->floordestheight = s3->floorheight;
  863. // Spawn lowering donut-hole pillar
  864. floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
  865. memset(floor, 0, sizeof(*floor));
  866. P_AddThinker (&floor->thinker);
  867. s1->floordata = floor; //jff 2/22/98
  868. floor->thinker.function = T_MoveFloor;
  869. floor->type = lowerFloor;
  870. floor->crush = false;
  871. floor->direction = -1;
  872. floor->sector = s1;
  873. floor->speed = FLOORSPEED / 2;
  874. floor->floordestheight = s3->floorheight;
  875. break;
  876. }
  877. }
  878. return rtn;
  879. }
  880. //
  881. // EV_DoElevator
  882. //
  883. // Handle elevator linedef types
  884. //
  885. // Passed the linedef that triggered the elevator and the elevator action
  886. //
  887. // jff 2/22/98 new type to move floor and ceiling in parallel
  888. //
  889. int EV_DoElevator
  890. ( line_t* line,
  891. elevator_e elevtype )
  892. {
  893. int secnum;
  894. int rtn;
  895. sector_t* sec;
  896. elevator_t* elevator;
  897. secnum = -1;
  898. rtn = 0;
  899. // act on all sectors with the same tag as the triggering linedef
  900. while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
  901. {
  902. sec = &sectors[secnum];
  903. // If either floor or ceiling is already activated, skip it
  904. if (sec->floordata || sec->ceilingdata) //jff 2/22/98
  905. continue;
  906. // create and initialize new elevator thinker
  907. rtn = 1;
  908. elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0);
  909. memset(elevator, 0, sizeof(*elevator));
  910. P_AddThinker (&elevator->thinker);
  911. sec->floordata = elevator; //jff 2/22/98
  912. sec->ceilingdata = elevator; //jff 2/22/98
  913. elevator->thinker.function = T_MoveElevator;
  914. elevator->type = elevtype;
  915. // set up the fields according to the type of elevator action
  916. switch(elevtype)
  917. {
  918. // elevator down to next floor
  919. case elevateDown:
  920. elevator->direction = -1;
  921. elevator->sector = sec;
  922. elevator->speed = ELEVATORSPEED;
  923. elevator->floordestheight =
  924. P_FindNextLowestFloor(sec,sec->floorheight);
  925. elevator->ceilingdestheight =
  926. elevator->floordestheight + sec->ceilingheight - sec->floorheight;
  927. break;
  928. // elevator up to next floor
  929. case elevateUp:
  930. elevator->direction = 1;
  931. elevator->sector = sec;
  932. elevator->speed = ELEVATORSPEED;
  933. elevator->floordestheight =
  934. P_FindNextHighestFloor(sec,sec->floorheight);
  935. elevator->ceilingdestheight =
  936. elevator->floordestheight + sec->ceilingheight - sec->floorheight;
  937. break;
  938. // elevator to floor height of activating switch's front sector
  939. case elevateCurrent:
  940. elevator->sector = sec;
  941. elevator->speed = ELEVATORSPEED;
  942. elevator->floordestheight = line->frontsector->floorheight;
  943. elevator->ceilingdestheight =
  944. elevator->floordestheight + sec->ceilingheight - sec->floorheight;
  945. elevator->direction =
  946. elevator->floordestheight>sec->floorheight? 1 : -1;
  947. break;
  948. default:
  949. break;
  950. }
  951. }
  952. return rtn;
  953. }