p_map.c 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418
  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-2004 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. * Movement, collision handling.
  31. * Shooting and aiming.
  32. *
  33. *-----------------------------------------------------------------------------*/
  34. #include "doomstat.h"
  35. #include "r_main.h"
  36. #include "p_mobj.h"
  37. #include "p_maputl.h"
  38. #include "p_map.h"
  39. #include "p_setup.h"
  40. #include "p_spec.h"
  41. #include "s_sound.h"
  42. #include "sounds.h"
  43. #include "p_inter.h"
  44. #include "m_random.h"
  45. #include "m_bbox.h"
  46. #include "lprintf.h"
  47. #include "m_argv.h"
  48. #include "g_game.h"
  49. #include "g_overflow.h"
  50. #include "hu_tracers.h"
  51. #include "e6y.h"//e6y
  52. static mobj_t *tmthing;
  53. static fixed_t tmx;
  54. static fixed_t tmy;
  55. static int pe_x; // Pain Elemental position for Lost Soul checks // phares
  56. static int pe_y; // Pain Elemental position for Lost Soul checks // phares
  57. static int ls_x; // Lost Soul position for Lost Soul checks // phares
  58. static int ls_y; // Lost Soul position for Lost Soul checks // phares
  59. //
  60. // SECTOR HEIGHT CHANGING
  61. // After modifying a sectors floor or ceiling height,
  62. // call this routine to adjust the positions
  63. // of all things that touch the sector.
  64. //
  65. // If anything doesn't fit anymore, true will be returned.
  66. // If crunch is true, they will take damage
  67. // as they are being crushed.
  68. // If Crunch is false, you should set the sector height back
  69. // the way it was and call P_ChangeSector again
  70. // to undo the changes.
  71. //
  72. static dboolean crushchange, nofit;
  73. // If "floatok" true, move would be ok
  74. // if within "tmfloorz - tmceilingz".
  75. dboolean floatok;
  76. /* killough 11/98: if "felldown" true, object was pushed down ledge */
  77. dboolean felldown;
  78. // The tm* items are used to hold information globally, usually for
  79. // line or object intersection checking
  80. fixed_t tmbbox[4]; // bounding box for line intersection checks
  81. fixed_t tmfloorz; // floor you'd hit if free to fall
  82. fixed_t tmceilingz; // ceiling of sector you're in
  83. fixed_t tmdropoffz; // dropoff on other side of line you're crossing
  84. // keep track of the line that lowers the ceiling,
  85. // so missiles don't explode against sky hack walls
  86. line_t *ceilingline;
  87. line_t *blockline; /* killough 8/11/98: blocking linedef */
  88. line_t *floorline; /* killough 8/1/98: Highest touched floor */
  89. static int tmunstuck; /* killough 8/1/98: whether to allow unsticking */
  90. // keep track of special lines as they are hit,
  91. // but don't process them until the move is proven valid
  92. // 1/11/98 killough: removed limit on special lines crossed
  93. line_t **spechit; // new code -- killough
  94. static int spechit_max; // killough
  95. int numspechit;
  96. // Temporary holder for thing_sectorlist threads
  97. msecnode_t* sector_list = NULL; // phares 3/16/98
  98. //
  99. // TELEPORT MOVE
  100. //
  101. //
  102. // PIT_StompThing
  103. //
  104. static dboolean telefrag; /* killough 8/9/98: whether to telefrag at exit */
  105. dboolean PIT_StompThing (mobj_t* thing)
  106. {
  107. fixed_t blockdist;
  108. // phares 9/10/98: moved this self-check to start of routine
  109. // don't clip against self
  110. if (thing == tmthing)
  111. return true;
  112. if (!(thing->flags & MF_SHOOTABLE)) // Can't shoot it? Can't stomp it!
  113. return true;
  114. blockdist = thing->radius + tmthing->radius;
  115. if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist)
  116. return true; // didn't hit it
  117. // monsters don't stomp things except on boss level
  118. if (!telefrag) // killough 8/9/98: make consistent across all levels
  119. return false;
  120. P_DamageMobj (thing, tmthing, tmthing, 10000); // Stomp!
  121. return true;
  122. }
  123. /*
  124. * killough 8/28/98:
  125. *
  126. * P_GetFriction()
  127. *
  128. * Returns the friction associated with a particular mobj.
  129. */
  130. int P_GetFriction(const mobj_t *mo, int *frictionfactor)
  131. {
  132. int friction = ORIG_FRICTION;
  133. int movefactor = ORIG_FRICTION_FACTOR;
  134. const msecnode_t *m;
  135. const sector_t *sec;
  136. /* Assign the friction value to objects on the floor, non-floating,
  137. * and clipped. Normally the object's friction value is kept at
  138. * ORIG_FRICTION and this thinker changes it for icy or muddy floors.
  139. *
  140. * When the object is straddling sectors with the same
  141. * floorheight that have different frictions, use the lowest
  142. * friction value (muddy has precedence over icy).
  143. */
  144. if (mo->flags & MF_FLY)
  145. {
  146. friction = FRICTION_FLY;
  147. }
  148. else
  149. {
  150. if (!(mo->flags & (MF_NOCLIP|MF_NOGRAVITY))
  151. && (mbf_features || (mo->player && !compatibility)) &&
  152. variable_friction)
  153. for (m = mo->touching_sectorlist; m; m = m->m_tnext)
  154. if ((sec = m->m_sector)->special & FRICTION_MASK &&
  155. (sec->friction < friction || friction == ORIG_FRICTION) &&
  156. (mo->z <= sec->floorheight ||
  157. (sec->heightsec != -1 &&
  158. mo->z <= sectors[sec->heightsec].floorheight &&
  159. mbf_features)))
  160. friction = sec->friction, movefactor = sec->movefactor;
  161. }
  162. if (frictionfactor)
  163. *frictionfactor = movefactor;
  164. return friction;
  165. }
  166. /* phares 3/19/98
  167. * P_GetMoveFactor() returns the value by which the x,y
  168. * movements are multiplied to add to player movement.
  169. *
  170. * killough 8/28/98: rewritten
  171. */
  172. int P_GetMoveFactor(mobj_t *mo, int *frictionp)
  173. {
  174. int movefactor, friction;
  175. //e6y
  176. if (!mbf_features && !prboom_comp[PC_PRBOOM_FRICTION].state)
  177. {
  178. int momentum;
  179. movefactor = ORIG_FRICTION_FACTOR;
  180. if (!compatibility && variable_friction &&
  181. !(mo->flags & (MF_NOGRAVITY | MF_NOCLIP)))
  182. {
  183. friction = mo->friction;
  184. if (friction == ORIG_FRICTION) // normal floor
  185. ;
  186. else if (friction > ORIG_FRICTION) // ice
  187. {
  188. movefactor = mo->movefactor;
  189. ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset
  190. }
  191. else // sludge
  192. {
  193. // phares 3/11/98: you start off slowly, then increase as
  194. // you get better footing
  195. momentum = (P_AproxDistance(mo->momx,mo->momy));
  196. movefactor = mo->movefactor;
  197. if (momentum > MORE_FRICTION_MOMENTUM<<2)
  198. movefactor <<= 3;
  199. else if (momentum > MORE_FRICTION_MOMENTUM<<1)
  200. movefactor <<= 2;
  201. else if (momentum > MORE_FRICTION_MOMENTUM)
  202. movefactor <<= 1;
  203. ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset
  204. }
  205. } // ^
  206. return(movefactor); // |
  207. }
  208. // If the floor is icy or muddy, it's harder to get moving. This is where
  209. // the different friction factors are applied to 'trying to move'. In
  210. // p_mobj.c, the friction factors are applied as you coast and slow down.
  211. if ((friction = P_GetFriction(mo, &movefactor)) < ORIG_FRICTION)
  212. {
  213. // phares 3/11/98: you start off slowly, then increase as
  214. // you get better footing
  215. int momentum = P_AproxDistance(mo->momx,mo->momy);
  216. if (momentum > MORE_FRICTION_MOMENTUM<<2)
  217. movefactor <<= 3;
  218. else if (momentum > MORE_FRICTION_MOMENTUM<<1)
  219. movefactor <<= 2;
  220. else if (momentum > MORE_FRICTION_MOMENTUM)
  221. movefactor <<= 1;
  222. }
  223. if (frictionp)
  224. *frictionp = friction;
  225. return movefactor;
  226. }
  227. //
  228. // P_TeleportMove
  229. //
  230. dboolean P_TeleportMove (mobj_t* thing,fixed_t x,fixed_t y, dboolean boss)
  231. {
  232. int xl;
  233. int xh;
  234. int yl;
  235. int yh;
  236. int bx;
  237. int by;
  238. subsector_t* newsubsec;
  239. /* killough 8/9/98: make telefragging more consistent, preserve compatibility */
  240. telefrag = thing->player ||
  241. (!comp[comp_telefrag] ? boss : (gamemap==30));
  242. // kill anything occupying the position
  243. tmthing = thing;
  244. tmx = x;
  245. tmy = y;
  246. tmbbox[BOXTOP] = y + tmthing->radius;
  247. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  248. tmbbox[BOXRIGHT] = x + tmthing->radius;
  249. tmbbox[BOXLEFT] = x - tmthing->radius;
  250. newsubsec = R_PointInSubsector (x,y);
  251. ceilingline = NULL;
  252. // The base floor/ceiling is from the subsector
  253. // that contains the point.
  254. // Any contacted lines the step closer together
  255. // will adjust them.
  256. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  257. tmceilingz = newsubsec->sector->ceilingheight;
  258. validcount++;
  259. numspechit = 0;
  260. // stomp on any things contacted
  261. xl = P_GetSafeBlockX(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS);
  262. xh = P_GetSafeBlockX(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS);
  263. yl = P_GetSafeBlockY(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS);
  264. yh = P_GetSafeBlockY(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS);
  265. for (bx=xl ; bx<=xh ; bx++)
  266. for (by=yl ; by<=yh ; by++)
  267. if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  268. return false;
  269. // the move is ok,
  270. // so unlink from the old position & link into the new position
  271. P_UnsetThingPosition (thing);
  272. thing->floorz = tmfloorz;
  273. thing->ceilingz = tmceilingz;
  274. thing->dropoffz = tmdropoffz; // killough 11/98
  275. thing->x = x;
  276. thing->y = y;
  277. P_SetThingPosition (thing);
  278. thing->PrevX = x;
  279. thing->PrevY = y;
  280. thing->PrevZ = thing->floorz;
  281. return true;
  282. }
  283. //
  284. // MOVEMENT ITERATOR FUNCTIONS
  285. //
  286. // // phares
  287. // PIT_CrossLine // |
  288. // Checks to see if a PE->LS trajectory line crosses a blocking // V
  289. // line. Returns false if it does.
  290. //
  291. // tmbbox holds the bounding box of the trajectory. If that box
  292. // does not touch the bounding box of the line in question,
  293. // then the trajectory is not blocked. If the PE is on one side
  294. // of the line and the LS is on the other side, then the
  295. // trajectory is blocked.
  296. //
  297. // Currently this assumes an infinite line, which is not quite
  298. // correct. A more correct solution would be to check for an
  299. // intersection of the trajectory and the line, but that takes
  300. // longer and probably really isn't worth the effort.
  301. //
  302. static // killough 3/26/98: make static
  303. dboolean PIT_CrossLine (line_t* ld)
  304. {
  305. if (!(ld->flags & ML_TWOSIDED) ||
  306. (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS)))
  307. if (!(tmbbox[BOXLEFT] > ld->bbox[BOXRIGHT] ||
  308. tmbbox[BOXRIGHT] < ld->bbox[BOXLEFT] ||
  309. tmbbox[BOXTOP] < ld->bbox[BOXBOTTOM] ||
  310. tmbbox[BOXBOTTOM] > ld->bbox[BOXTOP]))
  311. if (P_PointOnLineSide(pe_x,pe_y,ld) != P_PointOnLineSide(ls_x,ls_y,ld))
  312. return(false); // line blocks trajectory // ^
  313. return(true); // line doesn't block trajectory // |
  314. } // phares
  315. /* killough 8/1/98: used to test intersection between thing and line
  316. * assuming NO movement occurs -- used to avoid sticky situations.
  317. */
  318. static int untouched(line_t *ld)
  319. {
  320. fixed_t x, y, tmbbox[4];
  321. return
  322. (tmbbox[BOXRIGHT] = (x=tmthing->x)+tmthing->radius) <= ld->bbox[BOXLEFT] ||
  323. (tmbbox[BOXLEFT] = x-tmthing->radius) >= ld->bbox[BOXRIGHT] ||
  324. (tmbbox[BOXTOP] = (y=tmthing->y)+tmthing->radius) <= ld->bbox[BOXBOTTOM] ||
  325. (tmbbox[BOXBOTTOM] = y-tmthing->radius) >= ld->bbox[BOXTOP] ||
  326. P_BoxOnLineSide(tmbbox, ld) != -1;
  327. }
  328. //
  329. // PIT_CheckLine
  330. // Adjusts tmfloorz and tmceilingz as lines are contacted
  331. //
  332. static // killough 3/26/98: make static
  333. dboolean PIT_CheckLine (line_t* ld)
  334. {
  335. if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  336. || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  337. || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  338. || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
  339. return true; // didn't hit it
  340. if (P_BoxOnLineSide(tmbbox, ld) != -1)
  341. return true; // didn't hit it
  342. // A line has been hit
  343. // The moving thing's destination position will cross the given line.
  344. // If this should not be allowed, return false.
  345. // If the line is special, keep track of it
  346. // to process later if the move is proven ok.
  347. // NOTE: specials are NOT sorted by order,
  348. // so two special lines that are only 8 pixels apart
  349. // could be crossed in either order.
  350. // killough 7/24/98: allow player to move out of 1s wall, to prevent sticking
  351. if (!ld->backsector) // one sided line
  352. {
  353. blockline = ld;
  354. return tmunstuck && !untouched(ld) &&
  355. FixedMul(tmx-tmthing->x,ld->dy) > FixedMul(tmy-tmthing->y,ld->dx);
  356. }
  357. // killough 8/10/98: allow bouncing objects to pass through as missiles
  358. if (!(tmthing->flags & (MF_MISSILE | MF_BOUNCES)))
  359. {
  360. if (ld->flags & ML_BLOCKING) // explicitly blocking everything
  361. return tmunstuck && !untouched(ld); // killough 8/1/98: allow escape
  362. // killough 8/9/98: monster-blockers don't affect friends
  363. if (!(tmthing->flags & MF_FRIEND || tmthing->player)
  364. && ld->flags & ML_BLOCKMONSTERS)
  365. return false; // block monsters only
  366. }
  367. // set openrange, opentop, openbottom
  368. // these define a 'window' from one sector to another across this line
  369. P_LineOpening (ld);
  370. // adjust floor & ceiling heights
  371. if (opentop < tmceilingz)
  372. {
  373. tmceilingz = opentop;
  374. ceilingline = ld;
  375. blockline = ld;
  376. }
  377. if (openbottom > tmfloorz)
  378. {
  379. tmfloorz = openbottom;
  380. floorline = ld; // killough 8/1/98: remember floor linedef
  381. blockline = ld;
  382. }
  383. if (lowfloor < tmdropoffz)
  384. tmdropoffz = lowfloor;
  385. // if contacted a special line, add it to the list
  386. CheckLinesCrossTracer(ld);//e6y
  387. if (ld->special)
  388. {
  389. // 1/11/98 killough: remove limit on lines hit, by array doubling
  390. if (numspechit >= spechit_max) {
  391. spechit_max = spechit_max ? spechit_max*2 : 8;
  392. spechit = realloc(spechit,sizeof *spechit*spechit_max); // killough
  393. }
  394. spechit[numspechit++] = ld;
  395. // e6y: Spechits overrun emulation code
  396. if (numspechit > 8 && demo_compatibility)
  397. {
  398. static spechit_overrun_param_t spechit_overrun_param = {
  399. NULL, // line_t *line;
  400. &spechit, // line_t **spechit;
  401. &numspechit, // int *numspechit;
  402. tmbbox, // fixed_t *tmbbox[4];
  403. &tmfloorz, // fixed_t *tmfloorz;
  404. &tmceilingz, // fixed_t *tmceilingz;
  405. &crushchange, // dboolean *crushchange;
  406. &nofit, // dboolean *nofit;
  407. };
  408. spechit_overrun_param.line = ld;
  409. SpechitOverrun(&spechit_overrun_param);
  410. }
  411. }
  412. return true;
  413. }
  414. //
  415. // PIT_CheckThing
  416. //
  417. static dboolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static
  418. {
  419. fixed_t blockdist;
  420. int damage;
  421. // killough 11/98: add touchy things
  422. if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE|MF_TOUCHY)))
  423. return true;
  424. blockdist = thing->radius + tmthing->radius;
  425. if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist)
  426. return true; // didn't hit it
  427. // killough 11/98:
  428. //
  429. // This test has less information content (it's almost always false), so it
  430. // should not be moved up to first, as it adds more overhead than it removes.
  431. // don't clip against self
  432. if (thing == tmthing)
  433. return true;
  434. /* killough 11/98:
  435. *
  436. * TOUCHY flag, for mines or other objects which die on contact with solids.
  437. * If a solid object of a different type comes in contact with a touchy
  438. * thing, and the touchy thing is not the sole one moving relative to fixed
  439. * surroundings such as walls, then the touchy thing dies immediately.
  440. */
  441. if (thing->flags & MF_TOUCHY && // touchy object
  442. tmthing->flags & MF_SOLID && // solid object touches it
  443. thing->health > 0 && // touchy object is alive
  444. (thing->intflags & MIF_ARMED || // Thing is an armed mine
  445. sentient(thing)) && // ... or a sentient thing
  446. (thing->type != tmthing->type || // only different species
  447. thing->type == MT_PLAYER) && // ... or different players
  448. thing->z + thing->height >= tmthing->z && // touches vertically
  449. tmthing->z + tmthing->height >= thing->z &&
  450. (thing->type ^ MT_PAIN) | // PEs and lost souls
  451. (tmthing->type ^ MT_SKULL) && // are considered same
  452. (thing->type ^ MT_SKULL) | // (but Barons & Knights
  453. (tmthing->type ^ MT_PAIN)) // are intentionally not)
  454. {
  455. P_DamageMobj(thing, NULL, NULL, thing->health); // kill object
  456. return true;
  457. }
  458. // check for skulls slamming into things
  459. if (tmthing->flags & MF_SKULLFLY)
  460. {
  461. // A flying skull is smacking something.
  462. // Determine damage amount, and the skull comes to a dead stop.
  463. int damage = ((P_Random(pr_skullfly)%8)+1)*tmthing->info->damage;
  464. P_DamageMobj (thing, tmthing, tmthing, damage);
  465. tmthing->flags &= ~MF_SKULLFLY;
  466. tmthing->momx = tmthing->momy = tmthing->momz = 0;
  467. P_SetMobjState (tmthing, tmthing->info->spawnstate);
  468. return false; // stop moving
  469. }
  470. // missiles can hit other things
  471. // killough 8/10/98: bouncing non-solid things can hit other things too
  472. if (tmthing->flags & MF_MISSILE || (tmthing->flags & MF_BOUNCES &&
  473. !(tmthing->flags & MF_SOLID)))
  474. {
  475. // see if it went over / under
  476. if (tmthing->z > thing->z + thing->height)
  477. return true; // overhead
  478. if (tmthing->z+tmthing->height < thing->z)
  479. return true; // underneath
  480. if (tmthing->target && (tmthing->target->type == thing->type ||
  481. (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
  482. (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT)))
  483. {
  484. if (thing == tmthing->target)
  485. return true; // Don't hit same species as originator.
  486. else
  487. // e6y: Dehacked support - monsters infight
  488. if (thing->type != MT_PLAYER && !monsters_infight) // Explode, but do no damage.
  489. return false; // Let players missile other players.
  490. }
  491. // killough 8/10/98: if moving thing is not a missile, no damage
  492. // is inflicted, and momentum is reduced if object hit is solid.
  493. if (!(tmthing->flags & MF_MISSILE)) {
  494. if (!(thing->flags & MF_SOLID)) {
  495. return true;
  496. } else {
  497. tmthing->momx = -tmthing->momx;
  498. tmthing->momy = -tmthing->momy;
  499. if (!(tmthing->flags & MF_NOGRAVITY))
  500. {
  501. tmthing->momx >>= 2;
  502. tmthing->momy >>= 2;
  503. }
  504. return false;
  505. }
  506. }
  507. if (!(thing->flags & MF_SHOOTABLE))
  508. return !(thing->flags & MF_SOLID); // didn't do any damage
  509. // damage / explode
  510. damage = ((P_Random(pr_damage)%8)+1)*tmthing->info->damage;
  511. P_DamageMobj (thing, tmthing, tmthing->target, damage);
  512. // don't traverse any more
  513. return false;
  514. }
  515. // check for special pickup
  516. if (thing->flags & MF_SPECIAL)
  517. {
  518. uint_64_t solid = thing->flags & MF_SOLID;
  519. if (tmthing->flags & MF_PICKUP)
  520. P_TouchSpecialThing(thing, tmthing); // can remove thing
  521. return !solid;
  522. }
  523. // RjY
  524. // comperr_hangsolid, an attempt to handle blocking hanging bodies
  525. // A solid hanging body will allow sufficiently small things underneath it.
  526. if (comperr(comperr_hangsolid) &&
  527. !((~thing->flags) & (MF_SOLID | MF_SPAWNCEILING)) // solid and hanging
  528. // invert everything, then both bits should be clear
  529. && tmthing->z + tmthing->height <= thing->z) // head height <= base
  530. // top of thing trying to move under the body <= bottom of body
  531. {
  532. tmceilingz = thing->z; // pretend ceiling height is at body's base
  533. return true;
  534. }
  535. // killough 3/16/98: Allow non-solid moving objects to move through solid
  536. // ones, by allowing the moving thing (tmthing) to move if it's non-solid,
  537. // despite another solid thing being in the way.
  538. // killough 4/11/98: Treat no-clipping things as not blocking
  539. // ...but not in demo_compatibility mode
  540. // e6y
  541. // Correction of wrong return value with demo_compatibility.
  542. // There is no more synch on http://www.doomworld.com/sda/dwdemo/w303-115.zip
  543. // (with correction in setMobjInfoValue)
  544. if (demo_compatibility && !prboom_comp[PC_TREAT_NO_CLIPPING_THINGS_AS_NOT_BLOCKING].state)
  545. return !(thing->flags & MF_SOLID);
  546. else
  547. return !((thing->flags & MF_SOLID && !(thing->flags & MF_NOCLIP))
  548. && (tmthing->flags & MF_SOLID || demo_compatibility));
  549. // return !(thing->flags & MF_SOLID); // old code -- killough
  550. }
  551. // This routine checks for Lost Souls trying to be spawned // phares
  552. // across 1-sided lines, impassible lines, or "monsters can't // |
  553. // cross" lines. Draw an imaginary line between the PE // V
  554. // and the new Lost Soul spawn spot. If that line crosses
  555. // a 'blocking' line, then disallow the spawn. Only search
  556. // lines in the blocks of the blockmap where the bounding box
  557. // of the trajectory line resides. Then check bounding box
  558. // of the trajectory vs. the bounding box of each blocking
  559. // line to see if the trajectory and the blocking line cross.
  560. // Then check the PE and LS to see if they're on different
  561. // sides of the blocking line. If so, return true, otherwise
  562. // false.
  563. dboolean Check_Sides(mobj_t* actor, int x, int y)
  564. {
  565. int bx,by,xl,xh,yl,yh;
  566. pe_x = actor->x;
  567. pe_y = actor->y;
  568. ls_x = x;
  569. ls_y = y;
  570. // Here is the bounding box of the trajectory
  571. tmbbox[BOXLEFT] = pe_x < x ? pe_x : x;
  572. tmbbox[BOXRIGHT] = pe_x > x ? pe_x : x;
  573. tmbbox[BOXTOP] = pe_y > y ? pe_y : y;
  574. tmbbox[BOXBOTTOM] = pe_y < y ? pe_y : y;
  575. // Determine which blocks to look in for blocking lines
  576. xl = P_GetSafeBlockX(tmbbox[BOXLEFT] - bmaporgx);
  577. xh = P_GetSafeBlockX(tmbbox[BOXRIGHT] - bmaporgx);
  578. yl = P_GetSafeBlockY(tmbbox[BOXBOTTOM] - bmaporgy);
  579. yh = P_GetSafeBlockY(tmbbox[BOXTOP] - bmaporgy);
  580. // xl->xh, yl->yh determine the mapblock set to search
  581. validcount++; // prevents checking same line twice
  582. for (bx = xl ; bx <= xh ; bx++)
  583. for (by = yl ; by <= yh ; by++)
  584. if (!P_BlockLinesIterator(bx,by,PIT_CrossLine))
  585. return true; // ^
  586. return(false); // |
  587. } // phares
  588. //
  589. // MOVEMENT CLIPPING
  590. //
  591. //
  592. // P_CheckPosition
  593. // This is purely informative, nothing is modified
  594. // (except things picked up).
  595. //
  596. // in:
  597. // a mobj_t (can be valid or invalid)
  598. // a position to be checked
  599. // (doesn't need to be related to the mobj_t->x,y)
  600. //
  601. // during:
  602. // special things are touched if MF_PICKUP
  603. // early out on solid lines?
  604. //
  605. // out:
  606. // newsubsec
  607. // floorz
  608. // ceilingz
  609. // tmdropoffz
  610. // the lowest point contacted
  611. // (monsters won't move to a dropoff)
  612. // speciallines[]
  613. // numspeciallines
  614. //
  615. dboolean P_CheckPosition (mobj_t* thing,fixed_t x,fixed_t y)
  616. {
  617. int xl;
  618. int xh;
  619. int yl;
  620. int yh;
  621. int bx;
  622. int by;
  623. subsector_t* newsubsec;
  624. tmthing = thing;
  625. tmx = x;
  626. tmy = y;
  627. tmbbox[BOXTOP] = y + tmthing->radius;
  628. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  629. tmbbox[BOXRIGHT] = x + tmthing->radius;
  630. tmbbox[BOXLEFT] = x - tmthing->radius;
  631. newsubsec = R_PointInSubsector (x,y);
  632. floorline = blockline = ceilingline = NULL; // killough 8/1/98
  633. // Whether object can get out of a sticky situation:
  634. tmunstuck = thing->player && /* only players */
  635. thing->player->mo == thing && /* not voodoo dolls */
  636. mbf_features; /* not under old demos */
  637. // The base floor / ceiling is from the subsector
  638. // that contains the point.
  639. // Any contacted lines the step closer together
  640. // will adjust them.
  641. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  642. tmceilingz = newsubsec->sector->ceilingheight;
  643. validcount++;
  644. numspechit = 0;
  645. if ( tmthing->flags & MF_NOCLIP )
  646. return true;
  647. // Check things first, possibly picking things up.
  648. // The bounding box is extended by MAXRADIUS
  649. // because mobj_ts are grouped into mapblocks
  650. // based on their origin point, and can overlap
  651. // into adjacent blocks by up to MAXRADIUS units.
  652. xl = P_GetSafeBlockX(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS);
  653. xh = P_GetSafeBlockX(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS);
  654. yl = P_GetSafeBlockY(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS);
  655. yh = P_GetSafeBlockY(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS);
  656. for (bx=xl ; bx<=xh ; bx++)
  657. for (by=yl ; by<=yh ; by++)
  658. if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  659. return false;
  660. // check lines
  661. xl = P_GetSafeBlockX(tmbbox[BOXLEFT] - bmaporgx);
  662. xh = P_GetSafeBlockX(tmbbox[BOXRIGHT] - bmaporgx);
  663. yl = P_GetSafeBlockY(tmbbox[BOXBOTTOM] - bmaporgy);
  664. yh = P_GetSafeBlockY(tmbbox[BOXTOP] - bmaporgy);
  665. for (bx=xl ; bx<=xh ; bx++)
  666. for (by=yl ; by<=yh ; by++)
  667. if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  668. return false; // doesn't fit
  669. ClearLinesCrossTracer();//e6y
  670. return true;
  671. }
  672. //
  673. // P_TryMove
  674. // Attempt to move to a new position,
  675. // crossing special lines unless MF_TELEPORT is set.
  676. //
  677. dboolean P_TryMove(mobj_t* thing,fixed_t x,fixed_t y,
  678. dboolean dropoff) // killough 3/15/98: allow dropoff as option
  679. {
  680. fixed_t oldx;
  681. fixed_t oldy;
  682. felldown = floatok = false; // killough 11/98
  683. if (!P_CheckPosition (thing, x, y))
  684. return false; // solid wall or thing
  685. if ( !(thing->flags & MF_NOCLIP) )
  686. {
  687. if (thing->flags & MF_FLY)
  688. {
  689. // When flying, slide up or down blocking lines until the actor
  690. // is not blocked.
  691. if (thing->z+thing->height > tmceilingz)
  692. {
  693. thing->momz = -8*FRACUNIT;
  694. return false;
  695. }
  696. else if (thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
  697. {
  698. thing->momz = 8*FRACUNIT;
  699. return false;
  700. }
  701. }
  702. // killough 7/26/98: reformatted slightly
  703. // killough 8/1/98: Possibly allow escape if otherwise stuck
  704. if (tmceilingz - tmfloorz < thing->height || // doesn't fit
  705. // mobj must lower to fit
  706. (floatok = true, !(thing->flags & MF_TELEPORT) &&
  707. tmceilingz - thing->z < thing->height && !(thing->flags & MF_FLY)) ||
  708. // too big a step up
  709. (!(thing->flags & MF_TELEPORT) &&
  710. tmfloorz - thing->z > 24*FRACUNIT))
  711. return tmunstuck
  712. && !(ceilingline && untouched(ceilingline))
  713. && !( floorline && untouched( floorline));
  714. /* killough 3/15/98: Allow certain objects to drop off
  715. * killough 7/24/98, 8/1/98:
  716. * Prevent monsters from getting stuck hanging off ledges
  717. * killough 10/98: Allow dropoffs in controlled circumstances
  718. * killough 11/98: Improve symmetry of clipping on stairs
  719. */
  720. if (!(thing->flags & (MF_DROPOFF|MF_FLOAT))) {
  721. if (comp[comp_dropoff])
  722. {
  723. // e6y
  724. // Fix demosync bug in mbf compatibility mode
  725. // There is no more desync on v2-2822.lmp/vrack2.wad
  726. // -force_no_dropoff command-line switch is for mbf_compatibility demos
  727. // recorded with prboom 2.2.2 - 2.4.7
  728. // Links:
  729. // http://competn.doom2.net/pub/sda/t-z/v2-2822.zip
  730. // http://www.doomworld.com/idgames/index.php?id=11138
  731. if ((compatibility || !dropoff
  732. || (!prboom_comp[PC_NO_DROPOFF].state && mbf_features && compatibility_level <= prboom_2_compatibility))
  733. && (tmfloorz - tmdropoffz > 24*FRACUNIT))
  734. return false; // don't stand over a dropoff
  735. }
  736. else
  737. if (!dropoff || (dropoff==2 && // large jump down (e.g. dogs)
  738. (tmfloorz-tmdropoffz > 128*FRACUNIT ||
  739. !thing->target || thing->target->z >tmdropoffz)))
  740. {
  741. if (!monkeys || !mbf_features ?
  742. tmfloorz - tmdropoffz > 24*FRACUNIT :
  743. thing->floorz - tmfloorz > 24*FRACUNIT ||
  744. thing->dropoffz - tmdropoffz > 24*FRACUNIT)
  745. return false;
  746. }
  747. else { /* dropoff allowed -- check for whether it fell more than 24 */
  748. felldown = !(thing->flags & MF_NOGRAVITY) &&
  749. thing->z - tmfloorz > 24*FRACUNIT;
  750. }
  751. }
  752. if (thing->flags & MF_BOUNCES && // killough 8/13/98
  753. !(thing->flags & (MF_MISSILE|MF_NOGRAVITY)) &&
  754. !sentient(thing) && tmfloorz - thing->z > 16*FRACUNIT)
  755. return false; // too big a step up for bouncers under gravity
  756. // killough 11/98: prevent falling objects from going up too many steps
  757. if (thing->intflags & MIF_FALLING && tmfloorz - thing->z >
  758. FixedMul(thing->momx,thing->momx)+FixedMul(thing->momy,thing->momy))
  759. return false;
  760. }
  761. // the move is ok,
  762. // so unlink from the old position and link into the new position
  763. P_UnsetThingPosition (thing);
  764. oldx = thing->x;
  765. oldy = thing->y;
  766. thing->floorz = tmfloorz;
  767. thing->ceilingz = tmceilingz;
  768. thing->dropoffz = tmdropoffz; // killough 11/98: keep track of dropoffs
  769. thing->x = x;
  770. thing->y = y;
  771. P_SetThingPosition (thing);
  772. // if any special lines were hit, do the effect
  773. if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  774. while (numspechit--)
  775. if (spechit[numspechit]->special) // see if the line was crossed
  776. {
  777. int oldside;
  778. if ((oldside = P_PointOnLineSide(oldx, oldy, spechit[numspechit])) !=
  779. P_PointOnLineSide(thing->x, thing->y, spechit[numspechit]))
  780. P_CrossSpecialLine(spechit[numspechit], oldside, thing);
  781. }
  782. return true;
  783. }
  784. /*
  785. * killough 9/12/98:
  786. *
  787. * Apply "torque" to objects hanging off of ledges, so that they
  788. * fall off. It's not really torque, since Doom has no concept of
  789. * rotation, but it's a convincing effect which avoids anomalies
  790. * such as lifeless objects hanging more than halfway off of ledges,
  791. * and allows objects to roll off of the edges of moving lifts, or
  792. * to slide up and then back down stairs, or to fall into a ditch.
  793. * If more than one linedef is contacted, the effects are cumulative,
  794. * so balancing is possible.
  795. */
  796. static dboolean PIT_ApplyTorque(line_t *ld)
  797. {
  798. if (ld->backsector && // If thing touches two-sided pivot linedef
  799. tmbbox[BOXRIGHT] > ld->bbox[BOXLEFT] &&
  800. tmbbox[BOXLEFT] < ld->bbox[BOXRIGHT] &&
  801. tmbbox[BOXTOP] > ld->bbox[BOXBOTTOM] &&
  802. tmbbox[BOXBOTTOM] < ld->bbox[BOXTOP] &&
  803. P_BoxOnLineSide(tmbbox, ld) == -1)
  804. {
  805. mobj_t *mo = tmthing;
  806. fixed_t dist = // lever arm
  807. + (ld->dx >> FRACBITS) * (mo->y >> FRACBITS)
  808. - (ld->dy >> FRACBITS) * (mo->x >> FRACBITS)
  809. - (ld->dx >> FRACBITS) * (ld->v1->y >> FRACBITS)
  810. + (ld->dy >> FRACBITS) * (ld->v1->x >> FRACBITS);
  811. if (dist < 0 ? // dropoff direction
  812. ld->frontsector->floorheight < mo->z &&
  813. ld->backsector->floorheight >= mo->z :
  814. ld->backsector->floorheight < mo->z &&
  815. ld->frontsector->floorheight >= mo->z)
  816. {
  817. /* At this point, we know that the object straddles a two-sided
  818. * linedef, and that the object's center of mass is above-ground.
  819. */
  820. fixed_t x = D_abs(ld->dx), y = D_abs(ld->dy);
  821. if (y > x)
  822. {
  823. fixed_t t = x;
  824. x = y;
  825. y = t;
  826. }
  827. y = finesine[(tantoangle[FixedDiv(y,x)>>DBITS] +
  828. ANG90) >> ANGLETOFINESHIFT];
  829. /* Momentum is proportional to distance between the
  830. * object's center of mass and the pivot linedef.
  831. *
  832. * It is scaled by 2^(OVERDRIVE - gear). When gear is
  833. * increased, the momentum gradually decreases to 0 for
  834. * the same amount of pseudotorque, so that oscillations
  835. * are prevented, yet it has a chance to reach equilibrium.
  836. */
  837. dist = FixedDiv(FixedMul(dist, (mo->gear < OVERDRIVE) ?
  838. y << -(mo->gear - OVERDRIVE) :
  839. y >> +(mo->gear - OVERDRIVE)), x);
  840. /* Apply momentum away from the pivot linedef. */
  841. x = FixedMul(ld->dy, dist);
  842. y = FixedMul(ld->dx, dist);
  843. /* Avoid moving too fast all of a sudden (step into "overdrive") */
  844. dist = FixedMul(x,x) + FixedMul(y,y);
  845. while (dist > FRACUNIT*4 && mo->gear < MAXGEAR)
  846. ++mo->gear, x >>= 1, y >>= 1, dist >>= 1;
  847. mo->momx -= x;
  848. mo->momy += y;
  849. }
  850. }
  851. return true;
  852. }
  853. /*
  854. * killough 9/12/98
  855. *
  856. * Applies "torque" to objects, based on all contacted linedefs
  857. */
  858. void P_ApplyTorque(mobj_t *mo)
  859. {
  860. int xl = P_GetSafeBlockX((tmbbox[BOXLEFT] =
  861. mo->x - mo->radius) - bmaporgx);
  862. int xh = P_GetSafeBlockX((tmbbox[BOXRIGHT] =
  863. mo->x + mo->radius) - bmaporgx);
  864. int yl = P_GetSafeBlockY((tmbbox[BOXBOTTOM] =
  865. mo->y - mo->radius) - bmaporgy);
  866. int yh = P_GetSafeBlockY((tmbbox[BOXTOP] =
  867. mo->y + mo->radius) - bmaporgy);
  868. int bx,by,flags = mo->intflags; //Remember the current state, for gear-change
  869. tmthing = mo;
  870. validcount++; /* prevents checking same line twice */
  871. for (bx = xl ; bx <= xh ; bx++)
  872. for (by = yl ; by <= yh ; by++)
  873. P_BlockLinesIterator(bx, by, PIT_ApplyTorque);
  874. /* If any momentum, mark object as 'falling' using engine-internal flags */
  875. if (mo->momx | mo->momy)
  876. mo->intflags |= MIF_FALLING;
  877. else // Clear the engine-internal flag indicating falling object.
  878. mo->intflags &= ~MIF_FALLING;
  879. /* If the object has been moving, step up the gear.
  880. * This helps reach equilibrium and avoid oscillations.
  881. *
  882. * Doom has no concept of potential energy, much less
  883. * of rotation, so we have to creatively simulate these
  884. * systems somehow :)
  885. */
  886. if (!((mo->intflags | flags) & MIF_FALLING)) // If not falling for a while,
  887. mo->gear = 0; // Reset it to full strength
  888. else
  889. if (mo->gear < MAXGEAR) // Else if not at max gear,
  890. mo->gear++; // move up a gear
  891. }
  892. //
  893. // P_ThingHeightClip
  894. // Takes a valid thing and adjusts the thing->floorz,
  895. // thing->ceilingz, and possibly thing->z.
  896. // This is called for all nearby monsters
  897. // whenever a sector changes height.
  898. // If the thing doesn't fit,
  899. // the z will be set to the lowest value
  900. // and false will be returned.
  901. //
  902. dboolean P_ThingHeightClip (mobj_t* thing)
  903. {
  904. dboolean onfloor;
  905. onfloor = (thing->z == thing->floorz);
  906. P_CheckPosition (thing, thing->x, thing->y);
  907. /* what about stranding a monster partially off an edge?
  908. * killough 11/98: Answer: see below (upset balance if hanging off ledge)
  909. */
  910. thing->floorz = tmfloorz;
  911. thing->ceilingz = tmceilingz;
  912. thing->dropoffz = tmdropoffz; /* killough 11/98: remember dropoffs */
  913. if (onfloor)
  914. {
  915. // walking monsters rise and fall with the floor
  916. thing->z = thing->floorz;
  917. /* killough 11/98: Possibly upset balance of objects hanging off ledges */
  918. if (thing->intflags & MIF_FALLING && thing->gear >= MAXGEAR)
  919. thing->gear = 0;
  920. }
  921. else
  922. {
  923. // don't adjust a floating monster unless forced to
  924. if (thing->z+thing->height > thing->ceilingz)
  925. thing->z = thing->ceilingz - thing->height;
  926. }
  927. return thing->ceilingz - thing->floorz >= thing->height;
  928. }
  929. //
  930. // SLIDE MOVE
  931. // Allows the player to slide along any angled walls.
  932. //
  933. /* killough 8/2/98: make variables static */
  934. static fixed_t bestslidefrac;
  935. static line_t* bestslideline;
  936. static mobj_t* slidemo;
  937. static fixed_t tmxmove;
  938. static fixed_t tmymove;
  939. //
  940. // P_HitSlideLine
  941. // Adjusts the xmove / ymove
  942. // so that the next move will slide along the wall.
  943. // If the floor is icy, then you can bounce off a wall. // phares
  944. //
  945. void P_HitSlideLine (line_t* ld)
  946. {
  947. int side;
  948. angle_t lineangle;
  949. angle_t moveangle;
  950. angle_t deltaangle;
  951. fixed_t movelen;
  952. fixed_t newlen;
  953. dboolean icyfloor; // is floor icy? // phares
  954. // |
  955. // Under icy conditions, if the angle of approach to the wall // V
  956. // is more than 45 degrees, then you'll bounce and lose half
  957. // your momentum. If less than 45 degrees, you'll slide along
  958. // the wall. 45 is arbitrary and is believable.
  959. // Check for the special cases of horz or vert walls.
  960. /* killough 10/98: only bounce if hit hard (prevents wobbling)
  961. * cph - DEMOSYNC - should only affect players in Boom demos? */
  962. //e6y
  963. if (mbf_features || prboom_comp[PC_PRBOOM_FRICTION].state)
  964. {
  965. icyfloor =
  966. P_AproxDistance(tmxmove, tmymove) > 4*FRACUNIT &&
  967. variable_friction && // killough 8/28/98: calc friction on demand
  968. slidemo->z <= slidemo->floorz &&
  969. P_GetFriction(slidemo, NULL) > ORIG_FRICTION;
  970. }
  971. else
  972. {
  973. extern dboolean onground;
  974. icyfloor = !compatibility &&
  975. variable_friction &&
  976. slidemo->player &&
  977. onground &&
  978. slidemo->friction > ORIG_FRICTION;
  979. }
  980. if (ld->slopetype == ST_HORIZONTAL)
  981. {
  982. if (icyfloor && (D_abs(tmymove) > D_abs(tmxmove)))
  983. {
  984. tmxmove /= 2; // absorb half the momentum
  985. tmymove = -tmymove/2;
  986. S_StartSound(slidemo,sfx_oof); // oooff!
  987. }
  988. else
  989. tmymove = 0; // no more movement in the Y direction
  990. return;
  991. }
  992. if (ld->slopetype == ST_VERTICAL)
  993. {
  994. if (icyfloor && (D_abs(tmxmove) > D_abs(tmymove)))
  995. {
  996. tmxmove = -tmxmove/2; // absorb half the momentum
  997. tmymove /= 2;
  998. S_StartSound(slidemo,sfx_oof); // oooff! // ^
  999. } // |
  1000. else // phares
  1001. tmxmove = 0; // no more movement in the X direction
  1002. return;
  1003. }
  1004. // The wall is angled. Bounce if the angle of approach is // phares
  1005. // less than 45 degrees. // phares
  1006. side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  1007. lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  1008. if (side == 1)
  1009. lineangle += ANG180;
  1010. moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  1011. // killough 3/2/98:
  1012. // The moveangle+=10 breaks v1.9 demo compatibility in
  1013. // some demos, so it needs demo_compatibility switch.
  1014. if (!demo_compatibility)
  1015. moveangle += 10; // prevents sudden path reversal due to // phares
  1016. // rounding error // |
  1017. deltaangle = moveangle-lineangle; // V
  1018. movelen = P_AproxDistance (tmxmove, tmymove);
  1019. if (icyfloor && (deltaangle > ANG45) && (deltaangle < ANG90+ANG45))
  1020. {
  1021. moveangle = lineangle - deltaangle;
  1022. movelen /= 2; // absorb
  1023. S_StartSound(slidemo,sfx_oof); // oooff!
  1024. moveangle >>= ANGLETOFINESHIFT;
  1025. tmxmove = FixedMul (movelen, finecosine[moveangle]);
  1026. tmymove = FixedMul (movelen, finesine[moveangle]);
  1027. } // ^
  1028. else // |
  1029. { // phares
  1030. if (deltaangle > ANG180)
  1031. deltaangle += ANG180;
  1032. // I_Error ("SlideLine: ang>ANG180");
  1033. lineangle >>= ANGLETOFINESHIFT;
  1034. deltaangle >>= ANGLETOFINESHIFT;
  1035. newlen = FixedMul (movelen, finecosine[deltaangle]);
  1036. tmxmove = FixedMul (newlen, finecosine[lineangle]);
  1037. tmymove = FixedMul (newlen, finesine[lineangle]);
  1038. } // phares
  1039. }
  1040. //
  1041. // PTR_SlideTraverse
  1042. //
  1043. dboolean PTR_SlideTraverse (intercept_t* in)
  1044. {
  1045. line_t* li;
  1046. if (!in->isaline)
  1047. I_Error ("PTR_SlideTraverse: not a line?");
  1048. li = in->d.line;
  1049. if ( ! (li->flags & ML_TWOSIDED) )
  1050. {
  1051. if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  1052. return true; // don't hit the back side
  1053. goto isblocking;
  1054. }
  1055. // set openrange, opentop, openbottom.
  1056. // These define a 'window' from one sector to another across a line
  1057. P_LineOpening (li);
  1058. if (openrange < slidemo->height)
  1059. goto isblocking; // doesn't fit
  1060. if (opentop - slidemo->z < slidemo->height)
  1061. goto isblocking; // mobj is too high
  1062. if (openbottom - slidemo->z > 24*FRACUNIT )
  1063. goto isblocking; // too big a step up
  1064. // this line doesn't block movement
  1065. return true;
  1066. // the line does block movement,
  1067. // see if it is closer than best so far
  1068. isblocking:
  1069. if (in->frac < bestslidefrac)
  1070. {
  1071. bestslidefrac = in->frac;
  1072. bestslideline = li;
  1073. }
  1074. return false; // stop
  1075. }
  1076. //
  1077. // P_SlideMove
  1078. // The momx / momy move is bad, so try to slide
  1079. // along a wall.
  1080. // Find the first line hit, move flush to it,
  1081. // and slide along it
  1082. //
  1083. // This is a kludgy mess.
  1084. //
  1085. // killough 11/98: reformatted
  1086. void P_SlideMove(mobj_t *mo)
  1087. {
  1088. int hitcount = 3;
  1089. slidemo = mo; // the object that's sliding
  1090. do
  1091. {
  1092. fixed_t leadx, leady, trailx, traily;
  1093. if (!--hitcount)
  1094. goto stairstep; // don't loop forever
  1095. // trace along the three leading corners
  1096. if (mo->momx > 0)
  1097. leadx = mo->x + mo->radius, trailx = mo->x - mo->radius;
  1098. else
  1099. leadx = mo->x - mo->radius, trailx = mo->x + mo->radius;
  1100. if (mo->momy > 0)
  1101. leady = mo->y + mo->radius, traily = mo->y - mo->radius;
  1102. else
  1103. leady = mo->y - mo->radius, traily = mo->y + mo->radius;
  1104. bestslidefrac = FRACUNIT+1;
  1105. P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy,
  1106. PT_ADDLINES, PTR_SlideTraverse);
  1107. P_PathTraverse(trailx, leady, trailx+mo->momx, leady+mo->momy,
  1108. PT_ADDLINES, PTR_SlideTraverse);
  1109. P_PathTraverse(leadx, traily, leadx+mo->momx, traily+mo->momy,
  1110. PT_ADDLINES, PTR_SlideTraverse);
  1111. // move up to the wall
  1112. if (bestslidefrac == FRACUNIT+1)
  1113. {
  1114. // the move must have hit the middle, so stairstep
  1115. stairstep:
  1116. /* killough 3/15/98: Allow objects to drop off ledges
  1117. *
  1118. * phares 5/4/98: kill momentum if you can't move at all
  1119. * This eliminates player bobbing if pressed against a wall
  1120. * while on ice.
  1121. *
  1122. * killough 10/98: keep buggy code around for old Boom demos
  1123. *
  1124. * cph 2000/09//23: buggy code was only in Boom v2.01
  1125. */
  1126. if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true))
  1127. if (!P_TryMove(mo, mo->x + mo->momx, mo->y, true))
  1128. if (compatibility_level == boom_201_compatibility)
  1129. mo->momx = mo->momy = 0;
  1130. break;
  1131. }
  1132. // fudge a bit to make sure it doesn't hit
  1133. if ((bestslidefrac -= 0x800) > 0)
  1134. {
  1135. fixed_t newx = FixedMul(mo->momx, bestslidefrac);
  1136. fixed_t newy = FixedMul(mo->momy, bestslidefrac);
  1137. // killough 3/15/98: Allow objects to drop off ledges
  1138. if (!P_TryMove(mo, mo->x+newx, mo->y+newy, true))
  1139. goto stairstep;
  1140. }
  1141. // Now continue along the wall.
  1142. // First calculate remainder.
  1143. bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
  1144. if (bestslidefrac > FRACUNIT)
  1145. bestslidefrac = FRACUNIT;
  1146. if (bestslidefrac <= 0)
  1147. break;
  1148. tmxmove = FixedMul(mo->momx, bestslidefrac);
  1149. tmymove = FixedMul(mo->momy, bestslidefrac);
  1150. P_HitSlideLine(bestslideline); // clip the moves
  1151. mo->momx = tmxmove;
  1152. mo->momy = tmymove;
  1153. /* killough 10/98: affect the bobbing the same way (but not voodoo dolls)
  1154. * cph - DEMOSYNC? */
  1155. if (mo->player && mo->player->mo == mo)
  1156. {
  1157. if (D_abs(mo->player->momx) > D_abs(tmxmove))
  1158. mo->player->momx = tmxmove;
  1159. if (D_abs(mo->player->momy) > D_abs(tmymove))
  1160. mo->player->momy = tmymove;
  1161. }
  1162. } // killough 3/15/98: Allow objects to drop off ledges:
  1163. while (!P_TryMove(mo, mo->x+tmxmove, mo->y+tmymove, true));
  1164. }
  1165. //
  1166. // P_LineAttack
  1167. //
  1168. mobj_t* linetarget; // who got hit (or NULL)
  1169. mobj_t* crosshair_target;
  1170. static mobj_t* shootthing;
  1171. /* killough 8/2/98: for more intelligent autoaiming */
  1172. static uint_64_t aim_flags_mask;
  1173. // Height if not aiming up or down
  1174. fixed_t shootz;
  1175. int la_damage;
  1176. fixed_t attackrange;
  1177. static fixed_t aimslope;
  1178. // slopes to top and bottom of target
  1179. // killough 4/20/98: make static instead of using ones in p_sight.c
  1180. static fixed_t topslope;
  1181. static fixed_t bottomslope;
  1182. //
  1183. // PTR_AimTraverse
  1184. // Sets linetaget and aimslope when a target is aimed at.
  1185. //
  1186. dboolean PTR_AimTraverse (intercept_t* in)
  1187. {
  1188. line_t* li;
  1189. mobj_t* th;
  1190. fixed_t slope;
  1191. fixed_t thingtopslope;
  1192. fixed_t thingbottomslope;
  1193. fixed_t dist;
  1194. if (in->isaline)
  1195. {
  1196. li = in->d.line;
  1197. if ( !(li->flags & ML_TWOSIDED) )
  1198. return false; // stop
  1199. // Crosses a two sided line.
  1200. // A two sided line will restrict
  1201. // the possible target ranges.
  1202. P_LineOpening (li);
  1203. if (openbottom >= opentop)
  1204. return false; // stop
  1205. dist = FixedMul (attackrange, in->frac);
  1206. // e6y: emulation of missed back side on two-sided lines.
  1207. // backsector can be NULL if overrun_missedbackside_emulate is 1
  1208. if (!li->backsector || li->frontsector->floorheight != li->backsector->floorheight)
  1209. {
  1210. slope = FixedDiv (openbottom - shootz , dist);
  1211. if (slope > bottomslope)
  1212. bottomslope = slope;
  1213. }
  1214. // e6y: emulation of missed back side on two-sided lines.
  1215. if (!li->backsector || li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1216. {
  1217. slope = FixedDiv (opentop - shootz , dist);
  1218. if (slope < topslope)
  1219. topslope = slope;
  1220. }
  1221. if (topslope <= bottomslope)
  1222. return false; // stop
  1223. return true; // shot continues
  1224. }
  1225. // shoot a thing
  1226. th = in->d.thing;
  1227. if (th == shootthing)
  1228. return true; // can't shoot self
  1229. if (!(th->flags&MF_SHOOTABLE))
  1230. return true; // corpse or something
  1231. /* killough 7/19/98, 8/2/98:
  1232. * friends don't aim at friends (except players), at least not first
  1233. */
  1234. if (th->flags & shootthing->flags & aim_flags_mask && !th->player)
  1235. return true;
  1236. // check angles to see if the thing can be aimed at
  1237. dist = FixedMul (attackrange, in->frac);
  1238. thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1239. if (thingtopslope < bottomslope)
  1240. return true; // shot over the thing
  1241. thingbottomslope = FixedDiv (th->z - shootz, dist);
  1242. if (thingbottomslope > topslope)
  1243. return true; // shot under the thing
  1244. // this thing can be hit!
  1245. if (thingtopslope > topslope)
  1246. thingtopslope = topslope;
  1247. if (thingbottomslope < bottomslope)
  1248. thingbottomslope = bottomslope;
  1249. aimslope = (thingtopslope+thingbottomslope)/2;
  1250. linetarget = th;
  1251. return false; // don't go any farther
  1252. }
  1253. //
  1254. // PTR_ShootTraverse
  1255. //
  1256. dboolean PTR_ShootTraverse (intercept_t* in)
  1257. {
  1258. fixed_t x;
  1259. fixed_t y;
  1260. fixed_t z;
  1261. fixed_t frac;
  1262. mobj_t* th;
  1263. fixed_t slope;
  1264. fixed_t dist;
  1265. fixed_t thingtopslope;
  1266. fixed_t thingbottomslope;
  1267. if (in->isaline)
  1268. {
  1269. line_t *li = in->d.line;
  1270. if (li->special)
  1271. P_ShootSpecialLine (shootthing, li);
  1272. if (li->flags & ML_TWOSIDED)
  1273. { // crosses a two sided (really 2s) line
  1274. P_LineOpening (li);
  1275. dist = FixedMul(attackrange, in->frac);
  1276. // killough 11/98: simplify
  1277. // e6y: emulation of missed back side on two-sided lines.
  1278. // backsector can be NULL if overrun_missedbackside_emulate is 1
  1279. if (!li->backsector)
  1280. {
  1281. if ((slope = FixedDiv(openbottom - shootz , dist)) <= aimslope &&
  1282. (slope = FixedDiv(opentop - shootz , dist)) >= aimslope)
  1283. return true; // shot continues
  1284. }
  1285. else
  1286. if ((li->frontsector->floorheight==li->backsector->floorheight ||
  1287. (slope = FixedDiv(openbottom - shootz , dist)) <= aimslope) &&
  1288. (li->frontsector->ceilingheight==li->backsector->ceilingheight ||
  1289. (slope = FixedDiv (opentop - shootz , dist)) >= aimslope))
  1290. return true; // shot continues
  1291. }
  1292. // hit line
  1293. // position a bit closer
  1294. frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  1295. x = trace.x + FixedMul (trace.dx, frac);
  1296. y = trace.y + FixedMul (trace.dy, frac);
  1297. z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1298. if (li->frontsector->ceilingpic == skyflatnum)
  1299. {
  1300. // don't shoot the sky!
  1301. if (z > li->frontsector->ceilingheight)
  1302. return false;
  1303. // it's a sky hack wall
  1304. if (li->backsector && li->backsector->ceilingpic == skyflatnum)
  1305. // fix bullet-eaters -- killough:
  1306. // WARNING: Almost all demos will lose sync without this
  1307. // demo_compatibility flag check!!! killough 1/18/98
  1308. if (demo_compatibility || li->backsector->ceilingheight < z)
  1309. return false;
  1310. }
  1311. // Spawn bullet puffs.
  1312. P_SpawnPuff (x,y,z);
  1313. // don't go any farther
  1314. return false;
  1315. }
  1316. // shoot a thing
  1317. th = in->d.thing;
  1318. if (th == shootthing)
  1319. return true; // can't shoot self
  1320. if (!(th->flags&MF_SHOOTABLE))
  1321. return true; // corpse or something
  1322. // check angles to see if the thing can be aimed at
  1323. dist = FixedMul (attackrange, in->frac);
  1324. thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1325. if (thingtopslope < aimslope)
  1326. return true; // shot over the thing
  1327. thingbottomslope = FixedDiv (th->z - shootz, dist);
  1328. if (thingbottomslope > aimslope)
  1329. return true; // shot under the thing
  1330. // hit thing
  1331. // position a bit closer
  1332. frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  1333. x = trace.x + FixedMul (trace.dx, frac);
  1334. y = trace.y + FixedMul (trace.dy, frac);
  1335. z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1336. // Spawn bullet puffs or blod spots,
  1337. // depending on target type.
  1338. if (in->d.thing->flags & MF_NOBLOOD)
  1339. P_SpawnPuff (x,y,z);
  1340. else
  1341. P_SpawnBlood (x,y,z, la_damage);
  1342. if (la_damage)
  1343. P_DamageMobj (th, shootthing, shootthing, la_damage);
  1344. // don't go any farther
  1345. return false;
  1346. }
  1347. //
  1348. // P_AimLineAttack
  1349. //
  1350. fixed_t P_AimLineAttack(mobj_t* t1,angle_t angle,fixed_t distance, uint_64_t mask)
  1351. {
  1352. fixed_t x2;
  1353. fixed_t y2;
  1354. t1 = P_SubstNullMobj(t1);
  1355. angle >>= ANGLETOFINESHIFT;
  1356. shootthing = t1;
  1357. x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1358. y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1359. shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1360. // can't shoot outside view angles
  1361. topslope = 100*FRACUNIT/160;
  1362. bottomslope = -100*FRACUNIT/160;
  1363. attackrange = distance;
  1364. linetarget = NULL;
  1365. /* killough 8/2/98: prevent friends from aiming at friends */
  1366. aim_flags_mask = mask;
  1367. P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_AimTraverse);
  1368. if (linetarget)
  1369. return aimslope;
  1370. return 0;
  1371. }
  1372. //
  1373. // P_LineAttack
  1374. // If damage == 0, it is just a test trace
  1375. // that will leave linetarget set.
  1376. //
  1377. void P_LineAttack
  1378. (mobj_t* t1,
  1379. angle_t angle,
  1380. fixed_t distance,
  1381. fixed_t slope,
  1382. int damage)
  1383. {
  1384. fixed_t x2;
  1385. fixed_t y2;
  1386. angle >>= ANGLETOFINESHIFT;
  1387. shootthing = t1;
  1388. la_damage = damage;
  1389. x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1390. y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1391. shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1392. attackrange = distance;
  1393. aimslope = slope;
  1394. P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_ShootTraverse);
  1395. }
  1396. //
  1397. // USE LINES
  1398. //
  1399. mobj_t* usething;
  1400. int xUseSuccess; // not accurate, but useful enough
  1401. dboolean PTR_UseTraverse (intercept_t* in)
  1402. {
  1403. int side;
  1404. if (!in->d.line->special)
  1405. {
  1406. P_LineOpening (in->d.line);
  1407. if (openrange <= 0)
  1408. {
  1409. S_StartSound (usething, sfx_noway);
  1410. // can't use through a wall
  1411. return false;
  1412. }
  1413. // not a special line, but keep checking
  1414. return true;
  1415. }
  1416. side = 0;
  1417. if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1418. side = 1;
  1419. // return false; // don't use back side
  1420. if (P_UseSpecialLine(usething, in->d.line, side) && usething->player)
  1421. xUseSuccess = 1;
  1422. //WAS can't use for than one special line in a row
  1423. //jff 3/21/98 NOW multiple use allowed with enabling line flag
  1424. return (!demo_compatibility && ((in->d.line->flags&ML_PASSUSE) || comperr(comperr_passuse)))?//e6y
  1425. true : false;
  1426. }
  1427. // Returns false if a "oof" sound should be made because of a blocking
  1428. // linedef. Makes 2s middles which are impassable, as well as 2s uppers
  1429. // and lowers which block the player, cause the sound effect when the
  1430. // player tries to activate them. Specials are excluded, although it is
  1431. // assumed that all special linedefs within reach have been considered
  1432. // and rejected already (see P_UseLines).
  1433. //
  1434. // by Lee Killough
  1435. //
  1436. dboolean PTR_NoWayTraverse(intercept_t* in)
  1437. {
  1438. line_t *ld = in->d.line;
  1439. // This linedef
  1440. return ld->special || !( // Ignore specials
  1441. ld->flags & ML_BLOCKING || ( // Always blocking
  1442. P_LineOpening(ld), // Find openings
  1443. openrange <= 0 || // No opening
  1444. openbottom > usething->z+24*FRACUNIT || // Too high it blocks
  1445. opentop < usething->z+usething->height // Too low it blocks
  1446. )
  1447. );
  1448. }
  1449. //
  1450. // P_UseLines
  1451. // Looks for special lines in front of the player to activate.
  1452. //
  1453. void P_UseLines (player_t* player)
  1454. {
  1455. int angle;
  1456. fixed_t x1;
  1457. fixed_t y1;
  1458. fixed_t x2;
  1459. fixed_t y2;
  1460. usething = player->mo;
  1461. angle = player->mo->angle >> ANGLETOFINESHIFT;
  1462. x1 = player->mo->x;
  1463. y1 = player->mo->y;
  1464. x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1465. y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1466. // old code:
  1467. //
  1468. // P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1469. //
  1470. // This added test makes the "oof" sound work on 2s lines -- killough:
  1471. if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ))
  1472. if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse ))
  1473. S_StartSound (usething, sfx_noway);
  1474. }
  1475. //
  1476. // RADIUS ATTACK
  1477. //
  1478. //e6y static
  1479. mobj_t *bombsource, *bombspot;
  1480. //e6y static
  1481. int bombdamage;
  1482. //
  1483. // PIT_RadiusAttack
  1484. // "bombsource" is the creature
  1485. // that caused the explosion at "bombspot".
  1486. //
  1487. dboolean PIT_RadiusAttack (mobj_t* thing)
  1488. {
  1489. fixed_t dx;
  1490. fixed_t dy;
  1491. fixed_t dist;
  1492. /* killough 8/20/98: allow bouncers to take damage
  1493. * (missile bouncers are already excluded with MF_NOBLOCKMAP)
  1494. */
  1495. if (!(thing->flags & (MF_SHOOTABLE | MF_BOUNCES)))
  1496. return true;
  1497. // Boss spider and cyborg
  1498. // take no damage from concussion.
  1499. // killough 8/10/98: allow grenades to hurt anyone, unless
  1500. // fired by Cyberdemons, in which case it won't hurt Cybers.
  1501. if (bombspot->flags & MF_BOUNCES ?
  1502. thing->type == MT_CYBORG && bombsource->type == MT_CYBORG :
  1503. thing->type == MT_CYBORG || thing->type == MT_SPIDER)
  1504. return true;
  1505. dx = D_abs(thing->x - bombspot->x);
  1506. dy = D_abs(thing->y - bombspot->y);
  1507. dist = dx>dy ? dx : dy;
  1508. dist = (dist - thing->radius) >> FRACBITS;
  1509. if (dist < 0)
  1510. dist = 0;
  1511. if (dist >= bombdamage)
  1512. return true; // out of range
  1513. if ( P_CheckSight (thing, bombspot) )
  1514. {
  1515. // must be in direct path
  1516. P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
  1517. }
  1518. return true;
  1519. }
  1520. //
  1521. // P_RadiusAttack
  1522. // Source is the creature that caused the explosion at spot.
  1523. //
  1524. void P_RadiusAttack(mobj_t* spot,mobj_t* source,int damage)
  1525. {
  1526. int x;
  1527. int y;
  1528. int xl;
  1529. int xh;
  1530. int yl;
  1531. int yh;
  1532. fixed_t dist;
  1533. dist = (damage+MAXRADIUS)<<FRACBITS;
  1534. yh = P_GetSafeBlockY(spot->y + dist - bmaporgy);
  1535. yl = P_GetSafeBlockY(spot->y - dist - bmaporgy);
  1536. xh = P_GetSafeBlockX(spot->x + dist - bmaporgx);
  1537. xl = P_GetSafeBlockX(spot->x - dist - bmaporgx);
  1538. bombspot = spot;
  1539. bombsource = source;
  1540. bombdamage = damage;
  1541. for (y=yl ; y<=yh ; y++)
  1542. for (x=xl ; x<=xh ; x++)
  1543. P_BlockThingsIterator (x, y, PIT_RadiusAttack );
  1544. }
  1545. //
  1546. // PIT_ChangeSector
  1547. //
  1548. dboolean PIT_ChangeSector (mobj_t* thing)
  1549. {
  1550. mobj_t* mo;
  1551. if (P_ThingHeightClip (thing))
  1552. return true; // keep checking
  1553. // crunch bodies to giblets
  1554. if (thing->health <= 0)
  1555. {
  1556. P_SetMobjState (thing, S_GIBS);
  1557. if (compatibility_level != doom_12_compatibility)
  1558. {
  1559. thing->flags &= ~MF_SOLID;
  1560. }
  1561. thing->height = 0;
  1562. thing->radius = 0;
  1563. return true; // keep checking
  1564. }
  1565. // crunch dropped items
  1566. if (thing->flags & MF_DROPPED)
  1567. {
  1568. P_RemoveMobj (thing);
  1569. // keep checking
  1570. return true;
  1571. }
  1572. /* killough 11/98: kill touchy things immediately */
  1573. if (thing->flags & MF_TOUCHY &&
  1574. (thing->intflags & MIF_ARMED || sentient(thing)))
  1575. {
  1576. P_DamageMobj(thing, NULL, NULL, thing->health); // kill object
  1577. return true; // keep checking
  1578. }
  1579. if (! (thing->flags & MF_SHOOTABLE) )
  1580. {
  1581. // assume it is bloody gibs or something
  1582. return true;
  1583. }
  1584. nofit = true;
  1585. if (crushchange && !(leveltime&3)) {
  1586. int t;
  1587. P_DamageMobj(thing,NULL,NULL,10);
  1588. // spray blood in a random direction
  1589. mo = P_SpawnMobj (thing->x,
  1590. thing->y,
  1591. thing->z + thing->height/2, MT_BLOOD);
  1592. /* killough 8/10/98: remove dependence on order of evaluation */
  1593. t = P_Random(pr_crush);
  1594. mo->momx = (t - P_Random (pr_crush))<<12;
  1595. t = P_Random(pr_crush);
  1596. mo->momy = (t - P_Random (pr_crush))<<12;
  1597. }
  1598. // keep checking (crush other things)
  1599. return true;
  1600. }
  1601. //
  1602. // P_ChangeSector
  1603. //
  1604. dboolean P_ChangeSector(sector_t* sector,dboolean crunch)
  1605. {
  1606. int x;
  1607. int y;
  1608. nofit = false;
  1609. crushchange = crunch;
  1610. // ARRGGHHH!!!!
  1611. // This is horrendously slow!!!
  1612. // killough 3/14/98
  1613. // re-check heights for all things near the moving sector
  1614. for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  1615. for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  1616. P_BlockThingsIterator (x, y, PIT_ChangeSector);
  1617. return nofit;
  1618. }
  1619. //
  1620. // P_CheckSector
  1621. // jff 3/19/98 added to just check monsters on the periphery
  1622. // of a moving sector instead of all in bounding box of the
  1623. // sector. Both more accurate and faster.
  1624. //
  1625. dboolean P_CheckSector(sector_t* sector,dboolean crunch)
  1626. {
  1627. msecnode_t *n;
  1628. if (comp[comp_floors]) /* use the old routine for old demos though */
  1629. return P_ChangeSector(sector,crunch);
  1630. nofit = false;
  1631. crushchange = crunch;
  1632. // killough 4/4/98: scan list front-to-back until empty or exhausted,
  1633. // restarting from beginning after each thing is processed. Avoids
  1634. // crashes, and is sure to examine all things in the sector, and only
  1635. // the things which are in the sector, until a steady-state is reached.
  1636. // Things can arbitrarily be inserted and removed and it won't mess up.
  1637. //
  1638. // killough 4/7/98: simplified to avoid using complicated counter
  1639. // Mark all things invalid
  1640. for (n=sector->touching_thinglist; n; n=n->m_snext)
  1641. n->visited = false;
  1642. do
  1643. for (n=sector->touching_thinglist; n; n=n->m_snext) // go through list
  1644. if (!n->visited) // unprocessed thing found
  1645. {
  1646. n->visited = true; // mark thing as processed
  1647. if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these
  1648. PIT_ChangeSector(n->m_thing); // process it
  1649. break; // exit and start over
  1650. }
  1651. while (n); // repeat from scratch until all things left are marked valid
  1652. return nofit;
  1653. }
  1654. #define USE_BLOCK_MEMORY_ALLOCATOR
  1655. #ifdef USE_BLOCK_MEMORY_ALLOCATOR
  1656. // CPhipps -
  1657. // Use block memory allocator here
  1658. #include "z_bmalloc.h"
  1659. IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone, sizeof(msecnode_t), PU_LEVEL, 256, "SecNodes");
  1660. //
  1661. // P_FreeSecNodeList
  1662. //
  1663. void P_FreeSecNodeList(void)
  1664. {
  1665. DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
  1666. NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
  1667. }
  1668. inline static msecnode_t* P_GetSecnode(void)
  1669. {
  1670. return (msecnode_t*)Z_BMalloc(&secnodezone);
  1671. }
  1672. // P_PutSecnode() returns a node to the freelist.
  1673. inline static void P_PutSecnode(msecnode_t* node)
  1674. {
  1675. Z_BFree(&secnodezone, node);
  1676. }
  1677. #else // USE_BLOCK_MEMORY_ALLOCATOR
  1678. // phares 3/21/98
  1679. //
  1680. // Maintain a freelist of msecnode_t's to reduce memory allocs and frees.
  1681. msecnode_t *headsecnode = NULL;
  1682. //
  1683. // P_FreeSecNodeList
  1684. //
  1685. void P_FreeSecNodeList(void)
  1686. {
  1687. headsecnode = NULL; // this is all thats needed to fix the bug
  1688. }
  1689. //
  1690. // P_GetSecnode
  1691. //
  1692. // Retrieves a node from the freelist. The calling routine should make sure it
  1693. // sets all fields properly.
  1694. //
  1695. // killough 11/98: reformatted
  1696. //
  1697. static msecnode_t *P_GetSecnode(void)
  1698. {
  1699. msecnode_t *node;
  1700. return headsecnode ?
  1701. node = headsecnode, headsecnode = node->m_snext, node :
  1702. (msecnode_t *)(Z_Malloc(sizeof *node, PU_LEVEL, NULL));
  1703. }
  1704. //
  1705. // P_PutSecnode
  1706. //
  1707. // Returns a node to the freelist.
  1708. //
  1709. static void P_PutSecnode(msecnode_t *node)
  1710. {
  1711. node->m_snext = headsecnode;
  1712. headsecnode = node;
  1713. }
  1714. #endif // USE_BLOCK_MEMORY_ALLOCATOR
  1715. // phares 3/16/98
  1716. //
  1717. // P_AddSecnode() searches the current list to see if this sector is
  1718. // already there. If not, it adds a sector node at the head of the list of
  1719. // sectors this object appears in. This is called when creating a list of
  1720. // nodes that will get linked in later. Returns a pointer to the new node.
  1721. msecnode_t* P_AddSecnode(sector_t* s, mobj_t* thing, msecnode_t* nextnode)
  1722. {
  1723. msecnode_t* node;
  1724. node = nextnode;
  1725. while (node)
  1726. {
  1727. if (node->m_sector == s) // Already have a node for this sector?
  1728. {
  1729. node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
  1730. return(nextnode);
  1731. }
  1732. node = node->m_tnext;
  1733. }
  1734. // Couldn't find an existing node for this sector. Add one at the head
  1735. // of the list.
  1736. node = P_GetSecnode();
  1737. // killough 4/4/98, 4/7/98: mark new nodes unvisited.
  1738. node->visited = 0;
  1739. node->m_sector = s; // sector
  1740. node->m_thing = thing; // mobj
  1741. node->m_tprev = NULL; // prev node on Thing thread
  1742. node->m_tnext = nextnode; // next node on Thing thread
  1743. if (nextnode)
  1744. nextnode->m_tprev = node; // set back link on Thing
  1745. // Add new node at head of sector thread starting at s->touching_thinglist
  1746. node->m_sprev = NULL; // prev node on sector thread
  1747. node->m_snext = s->touching_thinglist; // next node on sector thread
  1748. if (s->touching_thinglist)
  1749. node->m_snext->m_sprev = node;
  1750. s->touching_thinglist = node;
  1751. return(node);
  1752. }
  1753. // P_DelSecnode() deletes a sector node from the list of
  1754. // sectors this object appears in. Returns a pointer to the next node
  1755. // on the linked list, or NULL.
  1756. msecnode_t* P_DelSecnode(msecnode_t* node)
  1757. {
  1758. msecnode_t* tp; // prev node on thing thread
  1759. msecnode_t* tn; // next node on thing thread
  1760. msecnode_t* sp; // prev node on sector thread
  1761. msecnode_t* sn; // next node on sector thread
  1762. if (node)
  1763. {
  1764. // Unlink from the Thing thread. The Thing thread begins at
  1765. // sector_list and not from mobj_t->touching_sectorlist.
  1766. tp = node->m_tprev;
  1767. tn = node->m_tnext;
  1768. if (tp)
  1769. tp->m_tnext = tn;
  1770. if (tn)
  1771. tn->m_tprev = tp;
  1772. // Unlink from the sector thread. This thread begins at
  1773. // sector_t->touching_thinglist.
  1774. sp = node->m_sprev;
  1775. sn = node->m_snext;
  1776. if (sp)
  1777. sp->m_snext = sn;
  1778. else
  1779. node->m_sector->touching_thinglist = sn;
  1780. if (sn)
  1781. sn->m_sprev = sp;
  1782. // Return this node to the freelist
  1783. P_PutSecnode(node);
  1784. return(tn);
  1785. }
  1786. return(NULL);
  1787. } // phares 3/13/98
  1788. // Delete an entire sector list
  1789. void P_DelSeclist(msecnode_t* node)
  1790. {
  1791. while (node)
  1792. node = P_DelSecnode(node);
  1793. }
  1794. // phares 3/14/98
  1795. //
  1796. // PIT_GetSectors
  1797. // Locates all the sectors the object is in by looking at the lines that
  1798. // cross through it. You have already decided that the object is allowed
  1799. // at this location, so don't bother with checking impassable or
  1800. // blocking lines.
  1801. dboolean PIT_GetSectors(line_t* ld)
  1802. {
  1803. if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] ||
  1804. tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] ||
  1805. tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] ||
  1806. tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
  1807. return true;
  1808. if (P_BoxOnLineSide(tmbbox, ld) != -1)
  1809. return true;
  1810. // This line crosses through the object.
  1811. // Collect the sector(s) from the line and add to the
  1812. // sector_list you're examining. If the Thing ends up being
  1813. // allowed to move to this position, then the sector_list
  1814. // will be attached to the Thing's mobj_t at touching_sectorlist.
  1815. sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list);
  1816. /* Don't assume all lines are 2-sided, since some Things
  1817. * like MT_TFOG are allowed regardless of whether their radius takes
  1818. * them beyond an impassable linedef.
  1819. *
  1820. * killough 3/27/98, 4/4/98:
  1821. * Use sidedefs instead of 2s flag to determine two-sidedness.
  1822. * killough 8/1/98: avoid duplicate if same sector on both sides
  1823. * cph - DEMOSYNC? */
  1824. if (ld->backsector && ld->backsector != ld->frontsector)
  1825. sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list);
  1826. return true;
  1827. }
  1828. // phares 3/14/98
  1829. //
  1830. // P_CreateSecNodeList alters/creates the sector_list that shows what sectors
  1831. // the object resides in.
  1832. void P_CreateSecNodeList(mobj_t* thing,fixed_t x,fixed_t y)
  1833. {
  1834. int xl;
  1835. int xh;
  1836. int yl;
  1837. int yh;
  1838. int bx;
  1839. int by;
  1840. msecnode_t* node;
  1841. mobj_t* saved_tmthing = tmthing; /* cph - see comment at func end */
  1842. fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */
  1843. // First, clear out the existing m_thing fields. As each node is
  1844. // added or verified as needed, m_thing will be set properly. When
  1845. // finished, delete all nodes where m_thing is still NULL. These
  1846. // represent the sectors the Thing has vacated.
  1847. node = sector_list;
  1848. while (node)
  1849. {
  1850. node->m_thing = NULL;
  1851. node = node->m_tnext;
  1852. }
  1853. tmthing = thing;
  1854. tmx = x;
  1855. tmy = y;
  1856. tmbbox[BOXTOP] = y + tmthing->radius;
  1857. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  1858. tmbbox[BOXRIGHT] = x + tmthing->radius;
  1859. tmbbox[BOXLEFT] = x - tmthing->radius;
  1860. validcount++; // used to make sure we only process a line once
  1861. xl = P_GetSafeBlockX(tmbbox[BOXLEFT] - bmaporgx);
  1862. xh = P_GetSafeBlockX(tmbbox[BOXRIGHT] - bmaporgx);
  1863. yl = P_GetSafeBlockY(tmbbox[BOXBOTTOM] - bmaporgy);
  1864. yh = P_GetSafeBlockY(tmbbox[BOXTOP] - bmaporgy);
  1865. for (bx=xl ; bx<=xh ; bx++)
  1866. for (by=yl ; by<=yh ; by++)
  1867. P_BlockLinesIterator(bx,by,PIT_GetSectors);
  1868. // Add the sector of the (x,y) point to sector_list.
  1869. sector_list = P_AddSecnode(thing->subsector->sector,thing,sector_list);
  1870. // Now delete any nodes that won't be used. These are the ones where
  1871. // m_thing is still NULL.
  1872. node = sector_list;
  1873. while (node)
  1874. {
  1875. if (node->m_thing == NULL)
  1876. {
  1877. if (node == sector_list)
  1878. sector_list = node->m_tnext;
  1879. node = P_DelSecnode(node);
  1880. }
  1881. else
  1882. node = node->m_tnext;
  1883. }
  1884. /* cph -
  1885. * This is the strife we get into for using global variables. tmthing
  1886. * is being used by several different functions calling
  1887. * P_BlockThingIterator, including functions that can be called *from*
  1888. * P_BlockThingIterator. Using a global tmthing is not reentrant.
  1889. * OTOH for Boom/MBF demos we have to preserve the buggy behavior.
  1890. * Fun. We restore its previous value unless we're in a Boom/MBF demo.
  1891. */
  1892. if (!prboom_comp[PC_FORCE_LXDOOM_DEMO_COMPATIBILITY].state)
  1893. if ((compatibility_level < boom_compatibility_compatibility) ||
  1894. (compatibility_level >= prboom_3_compatibility))
  1895. tmthing = saved_tmthing;
  1896. /* And, duh, the same for tmx/y - cph 2002/09/22
  1897. * And for tmbbox - cph 2003/08/10 */
  1898. if ((compatibility_level < boom_compatibility_compatibility) /* ||
  1899. (compatibility_level >= prboom_4_compatibility) */) {
  1900. tmx = saved_tmx, tmy = saved_tmy;
  1901. if (tmthing) {
  1902. tmbbox[BOXTOP] = tmy + tmthing->radius;
  1903. tmbbox[BOXBOTTOM] = tmy - tmthing->radius;
  1904. tmbbox[BOXRIGHT] = tmx + tmthing->radius;
  1905. tmbbox[BOXLEFT] = tmx - tmthing->radius;
  1906. }
  1907. }
  1908. }
  1909. /* cphipps 2004/08/30 -
  1910. * Must clear tmthing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */
  1911. void P_MapStart(void) {
  1912. if (tmthing) I_Error("P_MapStart: tmthing set!");
  1913. }
  1914. void P_MapEnd(void) {
  1915. tmthing = NULL;
  1916. }