P_MAP.C 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639
  1. // P_map.c
  2. #include "DoomDef.h"
  3. #include "P_local.h"
  4. #include "soundst.h"
  5. /*
  6. ===============================================================================
  7. NOTES:
  8. ===============================================================================
  9. */
  10. /*
  11. ===============================================================================
  12. mobj_t NOTES
  13. mobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound.
  14. The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn. The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible. The sprite and frame values are allmost allways set from state_t structures. The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file. The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped). This is the default origin position for patch_ts grabbed with lumpy.exe. A walking creature will have its z equal to the floor it is standing on.
  15. The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
  16. The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation.
  17. Every mobj_t is linked into a single sector based on it's origin coordinates.
  18. The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector. The sector links are only used by the rendering code, the play simulation does not care about them at all.
  19. Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap. If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile). Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained.
  20. A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set. Links should only be modified by the P_[Un]SetThingPosition () functions. Do not change the MF_NO? flags while a thing is valid.
  21. ===============================================================================
  22. */
  23. fixed_t tmbbox[4];
  24. mobj_t *tmthing;
  25. int tmflags;
  26. fixed_t tmx, tmy;
  27. boolean floatok; // if true, move would be ok if
  28. // within tmfloorz - tmceilingz
  29. fixed_t tmfloorz, tmceilingz, tmdropoffz;
  30. // keep track of the line that lowers the ceiling, so missiles don't explode
  31. // against sky hack walls
  32. line_t *ceilingline;
  33. // keep track of special lines as they are hit, but don't process them
  34. // until the move is proven valid
  35. #define MAXSPECIALCROSS 8
  36. line_t *spechit[MAXSPECIALCROSS];
  37. int numspechit;
  38. mobj_t *onmobj; //generic global onmobj...used for landing on pods/players
  39. /*
  40. ===============================================================================
  41. TELEPORT MOVE
  42. ===============================================================================
  43. */
  44. /*
  45. ==================
  46. =
  47. = PIT_StompThing
  48. =
  49. ==================
  50. */
  51. boolean PIT_StompThing (mobj_t *thing)
  52. {
  53. fixed_t blockdist;
  54. if (!(thing->flags & MF_SHOOTABLE) )
  55. return true;
  56. blockdist = thing->radius + tmthing->radius;
  57. if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
  58. return true; // didn't hit it
  59. if (thing == tmthing)
  60. return true; // don't clip against self
  61. if(!(tmthing->flags2&MF2_TELESTOMP))
  62. { // Not allowed to stomp things
  63. return(false);
  64. }
  65. P_DamageMobj (thing, tmthing, tmthing, 10000);
  66. return true;
  67. }
  68. /*
  69. ===================
  70. =
  71. = P_TeleportMove
  72. =
  73. ===================
  74. */
  75. boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
  76. {
  77. int xl,xh,yl,yh,bx,by;
  78. subsector_t *newsubsec;
  79. //
  80. // kill anything occupying the position
  81. //
  82. tmthing = thing;
  83. tmflags = thing->flags;
  84. tmx = x;
  85. tmy = y;
  86. tmbbox[BOXTOP] = y + tmthing->radius;
  87. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  88. tmbbox[BOXRIGHT] = x + tmthing->radius;
  89. tmbbox[BOXLEFT] = x - tmthing->radius;
  90. newsubsec = R_PointInSubsector (x,y);
  91. ceilingline = NULL;
  92. //
  93. // the base floor / ceiling is from the subsector that contains the
  94. // point. Any contacted lines the step closer together will adjust them
  95. //
  96. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  97. tmceilingz = newsubsec->sector->ceilingheight;
  98. validcount++;
  99. numspechit = 0;
  100. //
  101. // stomp on any things contacted
  102. //
  103. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  104. xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  105. yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  106. yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  107. for (bx=xl ; bx<=xh ; bx++)
  108. for (by=yl ; by<=yh ; by++)
  109. if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  110. return false;
  111. //
  112. // the move is ok, so link the thing into its new position
  113. //
  114. P_UnsetThingPosition (thing);
  115. thing->floorz = tmfloorz;
  116. thing->ceilingz = tmceilingz;
  117. thing->x = x;
  118. thing->y = y;
  119. P_SetThingPosition (thing);
  120. return true;
  121. }
  122. /*
  123. ===============================================================================
  124. MOVEMENT ITERATOR FUNCTIONS
  125. ===============================================================================
  126. */
  127. /*
  128. ==================
  129. =
  130. = PIT_CheckLine
  131. =
  132. = Adjusts tmfloorz and tmceilingz as lines are contacted
  133. ==================
  134. */
  135. boolean PIT_CheckLine(line_t *ld)
  136. {
  137. if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  138. || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  139. || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  140. || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
  141. {
  142. return(true);
  143. }
  144. if(P_BoxOnLineSide(tmbbox, ld) != -1)
  145. {
  146. return(true);
  147. }
  148. // a line has been hit
  149. /*
  150. =
  151. = The moving thing's destination position will cross the given line.
  152. = If this should not be allowed, return false.
  153. = If the line is special, keep track of it to process later if the move
  154. = is proven ok. NOTE: specials are NOT sorted by order, so two special lines
  155. = that are only 8 pixels apart could be crossed in either order.
  156. */
  157. if(!ld->backsector)
  158. { // One sided line
  159. if(tmthing->flags&MF_MISSILE)
  160. { // Missiles can trigger impact specials
  161. if(ld->special)
  162. {
  163. spechit[numspechit] = ld;
  164. numspechit++;
  165. }
  166. }
  167. return false;
  168. }
  169. if(!(tmthing->flags&MF_MISSILE))
  170. {
  171. if(ld->flags&ML_BLOCKING)
  172. { // Explicitly blocking everything
  173. return(false);
  174. }
  175. if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS
  176. && tmthing->type != MT_POD)
  177. { // Block monsters only
  178. return(false);
  179. }
  180. }
  181. P_LineOpening(ld); // set openrange, opentop, openbottom
  182. // adjust floor / ceiling heights
  183. if(opentop < tmceilingz)
  184. {
  185. tmceilingz = opentop;
  186. ceilingline = ld;
  187. }
  188. if(openbottom > tmfloorz)
  189. {
  190. tmfloorz = openbottom;
  191. }
  192. if(lowfloor < tmdropoffz)
  193. {
  194. tmdropoffz = lowfloor;
  195. }
  196. if(ld->special)
  197. { // Contacted a special line, add it to the list
  198. spechit[numspechit] = ld;
  199. numspechit++;
  200. }
  201. return(true);
  202. }
  203. //---------------------------------------------------------------------------
  204. //
  205. // FUNC PIT_CheckThing
  206. //
  207. //---------------------------------------------------------------------------
  208. boolean PIT_CheckThing(mobj_t *thing)
  209. {
  210. fixed_t blockdist;
  211. boolean solid;
  212. int damage;
  213. if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  214. { // Can't hit thing
  215. return(true);
  216. }
  217. blockdist = thing->radius+tmthing->radius;
  218. if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  219. { // Didn't hit thing
  220. return(true);
  221. }
  222. if(thing == tmthing)
  223. { // Don't clip against self
  224. return(true);
  225. }
  226. if(tmthing->flags2&MF2_PASSMOBJ)
  227. { // check if a mobj passed over/under another object
  228. if((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD)
  229. && (thing->type == MT_IMP || thing->type == MT_WIZARD))
  230. { // don't let imps/wizards fly over other imps/wizards
  231. return false;
  232. }
  233. if(tmthing->z > thing->z+thing->height
  234. && !(thing->flags&MF_SPECIAL))
  235. {
  236. return(true);
  237. }
  238. else if(tmthing->z+tmthing->height < thing->z
  239. && !(thing->flags&MF_SPECIAL))
  240. { // under thing
  241. return(true);
  242. }
  243. }
  244. // Check for skulls slamming into things
  245. if(tmthing->flags&MF_SKULLFLY)
  246. {
  247. damage = ((P_Random()%8)+1)*tmthing->damage;
  248. P_DamageMobj(thing, tmthing, tmthing, damage);
  249. tmthing->flags &= ~MF_SKULLFLY;
  250. tmthing->momx = tmthing->momy = tmthing->momz = 0;
  251. P_SetMobjState(tmthing, tmthing->info->seestate);
  252. return(false);
  253. }
  254. // Check for missile
  255. if(tmthing->flags&MF_MISSILE)
  256. {
  257. // Check for passing through a ghost
  258. if((thing->flags&MF_SHADOW) && (tmthing->flags2&MF2_THRUGHOST))
  259. {
  260. return(true);
  261. }
  262. // Check if it went over / under
  263. if(tmthing->z > thing->z+thing->height)
  264. { // Over thing
  265. return(true);
  266. }
  267. if(tmthing->z+tmthing->height < thing->z)
  268. { // Under thing
  269. return(true);
  270. }
  271. if(tmthing->target && tmthing->target->type == thing->type)
  272. { // Don't hit same species as originator
  273. if(thing == tmthing->target)
  274. { // Don't missile self
  275. return(true);
  276. }
  277. if(thing->type != MT_PLAYER)
  278. { // Hit same species as originator, explode, no damage
  279. return(false);
  280. }
  281. }
  282. if(!(thing->flags&MF_SHOOTABLE))
  283. { // Didn't do any damage
  284. return!(thing->flags&MF_SOLID);
  285. }
  286. if(tmthing->flags2&MF2_RIP)
  287. {
  288. if(!(thing->flags&MF_NOBLOOD))
  289. { // Ok to spawn some blood
  290. P_RipperBlood(tmthing);
  291. }
  292. S_StartSound(tmthing, sfx_ripslop);
  293. damage = ((P_Random()&3)+2)*tmthing->damage;
  294. P_DamageMobj(thing, tmthing, tmthing->target, damage);
  295. if(thing->flags2&MF2_PUSHABLE
  296. && !(tmthing->flags2&MF2_CANNOTPUSH))
  297. { // Push thing
  298. thing->momx += tmthing->momx>>2;
  299. thing->momy += tmthing->momy>>2;
  300. }
  301. numspechit = 0;
  302. return(true);
  303. }
  304. // Do damage
  305. damage = ((P_Random()%8)+1)*tmthing->damage;
  306. if(damage)
  307. {
  308. if(!(thing->flags&MF_NOBLOOD) && P_Random() < 192)
  309. {
  310. P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
  311. }
  312. P_DamageMobj(thing, tmthing, tmthing->target, damage);
  313. }
  314. return(false);
  315. }
  316. if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
  317. { // Push thing
  318. thing->momx += tmthing->momx>>2;
  319. thing->momy += tmthing->momy>>2;
  320. }
  321. // Check for special thing
  322. if(thing->flags&MF_SPECIAL)
  323. {
  324. solid = thing->flags&MF_SOLID;
  325. if(tmflags&MF_PICKUP)
  326. { // Can be picked up by tmthing
  327. P_TouchSpecialThing(thing, tmthing); // Can remove thing
  328. }
  329. return(!solid);
  330. }
  331. return(!(thing->flags&MF_SOLID));
  332. }
  333. //---------------------------------------------------------------------------
  334. //
  335. // PIT_CheckOnmobjZ
  336. //
  337. //---------------------------------------------------------------------------
  338. boolean PIT_CheckOnmobjZ(mobj_t *thing)
  339. {
  340. fixed_t blockdist;
  341. if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  342. { // Can't hit thing
  343. return(true);
  344. }
  345. blockdist = thing->radius+tmthing->radius;
  346. if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  347. { // Didn't hit thing
  348. return(true);
  349. }
  350. if(thing == tmthing)
  351. { // Don't clip against self
  352. return(true);
  353. }
  354. if(tmthing->z > thing->z+thing->height)
  355. {
  356. return(true);
  357. }
  358. else if(tmthing->z+tmthing->height < thing->z)
  359. { // under thing
  360. return(true);
  361. }
  362. if(thing->flags&MF_SOLID)
  363. {
  364. onmobj = thing;
  365. }
  366. return(!(thing->flags&MF_SOLID));
  367. }
  368. /*
  369. ===============================================================================
  370. MOVEMENT CLIPPING
  371. ===============================================================================
  372. */
  373. //----------------------------------------------------------------------------
  374. //
  375. // FUNC P_TestMobjLocation
  376. //
  377. // Returns true if the mobj is not blocked by anything at its current
  378. // location, otherwise returns false.
  379. //
  380. //----------------------------------------------------------------------------
  381. boolean P_TestMobjLocation(mobj_t *mobj)
  382. {
  383. int flags;
  384. flags = mobj->flags;
  385. mobj->flags &= ~MF_PICKUP;
  386. if(P_CheckPosition(mobj, mobj->x, mobj->y))
  387. { // XY is ok, now check Z
  388. mobj->flags = flags;
  389. if((mobj->z < mobj->floorz)
  390. || (mobj->z+mobj->height > mobj->ceilingz))
  391. { // Bad Z
  392. return(false);
  393. }
  394. return(true);
  395. }
  396. mobj->flags = flags;
  397. return(false);
  398. }
  399. /*
  400. ==================
  401. =
  402. = P_CheckPosition
  403. =
  404. = This is purely informative, nothing is modified (except things picked up)
  405. in:
  406. a mobj_t (can be valid or invalid)
  407. a position to be checked (doesn't need to be related to the mobj_t->x,y)
  408. during:
  409. special things are touched if MF_PICKUP
  410. early out on solid lines?
  411. out:
  412. newsubsec
  413. floorz
  414. ceilingz
  415. tmdropoffz the lowest point contacted (monsters won't move to a dropoff)
  416. speciallines[]
  417. numspeciallines
  418. ==================
  419. */
  420. boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
  421. {
  422. int xl,xh,yl,yh,bx,by;
  423. subsector_t *newsubsec;
  424. tmthing = thing;
  425. tmflags = thing->flags;
  426. tmx = x;
  427. tmy = y;
  428. tmbbox[BOXTOP] = y + tmthing->radius;
  429. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  430. tmbbox[BOXRIGHT] = x + tmthing->radius;
  431. tmbbox[BOXLEFT] = x - tmthing->radius;
  432. newsubsec = R_PointInSubsector (x,y);
  433. ceilingline = NULL;
  434. //
  435. // the base floor / ceiling is from the subsector that contains the
  436. // point. Any contacted lines the step closer together will adjust them
  437. //
  438. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  439. tmceilingz = newsubsec->sector->ceilingheight;
  440. validcount++;
  441. numspechit = 0;
  442. if ( tmflags & MF_NOCLIP )
  443. return true;
  444. //
  445. // check things first, possibly picking things up
  446. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  447. // into mapblocks based on their origin point, and can overlap into adjacent
  448. // blocks by up to MAXRADIUS units
  449. //
  450. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  451. xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  452. yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  453. yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  454. for (bx=xl ; bx<=xh ; bx++)
  455. for (by=yl ; by<=yh ; by++)
  456. if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  457. return false;
  458. //
  459. // check lines
  460. //
  461. xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
  462. xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
  463. yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
  464. yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
  465. for (bx=xl ; bx<=xh ; bx++)
  466. for (by=yl ; by<=yh ; by++)
  467. if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  468. return false;
  469. return true;
  470. }
  471. //=============================================================================
  472. //
  473. // P_CheckOnmobj(mobj_t *thing)
  474. //
  475. // Checks if the new Z position is legal
  476. //=============================================================================
  477. mobj_t *P_CheckOnmobj(mobj_t *thing)
  478. {
  479. int xl,xh,yl,yh,bx,by;
  480. subsector_t *newsubsec;
  481. fixed_t x;
  482. fixed_t y;
  483. mobj_t oldmo;
  484. x = thing->x;
  485. y = thing->y;
  486. tmthing = thing;
  487. tmflags = thing->flags;
  488. oldmo = *thing; // save the old mobj before the fake zmovement
  489. P_FakeZMovement(tmthing);
  490. tmx = x;
  491. tmy = y;
  492. tmbbox[BOXTOP] = y + tmthing->radius;
  493. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  494. tmbbox[BOXRIGHT] = x + tmthing->radius;
  495. tmbbox[BOXLEFT] = x - tmthing->radius;
  496. newsubsec = R_PointInSubsector (x,y);
  497. ceilingline = NULL;
  498. //
  499. // the base floor / ceiling is from the subsector that contains the
  500. // point. Any contacted lines the step closer together will adjust them
  501. //
  502. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  503. tmceilingz = newsubsec->sector->ceilingheight;
  504. validcount++;
  505. numspechit = 0;
  506. if ( tmflags & MF_NOCLIP )
  507. return NULL;
  508. //
  509. // check things first, possibly picking things up
  510. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  511. // into mapblocks based on their origin point, and can overlap into adjacent
  512. // blocks by up to MAXRADIUS units
  513. //
  514. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  515. xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  516. yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  517. yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  518. for (bx=xl ; bx<=xh ; bx++)
  519. for (by=yl ; by<=yh ; by++)
  520. if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
  521. {
  522. *tmthing = oldmo;
  523. return onmobj;
  524. }
  525. *tmthing = oldmo;
  526. return NULL;
  527. }
  528. //=============================================================================
  529. //
  530. // P_FakeZMovement
  531. //
  532. // Fake the zmovement so that we can check if a move is legal
  533. //=============================================================================
  534. void P_FakeZMovement(mobj_t *mo)
  535. {
  536. int dist;
  537. int delta;
  538. //
  539. // adjust height
  540. //
  541. mo->z += mo->momz;
  542. if(mo->flags&MF_FLOAT && mo->target)
  543. { // float down towards target if too close
  544. if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
  545. {
  546. dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
  547. delta =( mo->target->z+(mo->height>>1))-mo->z;
  548. if (delta < 0 && dist < -(delta*3))
  549. mo->z -= FLOATSPEED;
  550. else if (delta > 0 && dist < (delta*3))
  551. mo->z += FLOATSPEED;
  552. }
  553. }
  554. if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
  555. && leveltime&2)
  556. {
  557. mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
  558. }
  559. //
  560. // clip movement
  561. //
  562. if(mo->z <= mo->floorz)
  563. { // Hit the floor
  564. mo->z = mo->floorz;
  565. if(mo->momz < 0)
  566. {
  567. mo->momz = 0;
  568. }
  569. if(mo->flags&MF_SKULLFLY)
  570. { // The skull slammed into something
  571. mo->momz = -mo->momz;
  572. }
  573. if(mo->info->crashstate && (mo->flags&MF_CORPSE))
  574. {
  575. return;
  576. }
  577. }
  578. else if(mo->flags2&MF2_LOGRAV)
  579. {
  580. if(mo->momz == 0)
  581. mo->momz = -(GRAVITY>>3)*2;
  582. else
  583. mo->momz -= GRAVITY>>3;
  584. }
  585. else if (! (mo->flags & MF_NOGRAVITY) )
  586. {
  587. if (mo->momz == 0)
  588. mo->momz = -GRAVITY*2;
  589. else
  590. mo->momz -= GRAVITY;
  591. }
  592. if (mo->z + mo->height > mo->ceilingz)
  593. { // hit the ceiling
  594. if (mo->momz > 0)
  595. mo->momz = 0;
  596. mo->z = mo->ceilingz - mo->height;
  597. if (mo->flags & MF_SKULLFLY)
  598. { // the skull slammed into something
  599. mo->momz = -mo->momz;
  600. }
  601. }
  602. }
  603. //==========================================================================
  604. //
  605. // CheckMissileImpact
  606. //
  607. //==========================================================================
  608. void CheckMissileImpact(mobj_t *mobj)
  609. {
  610. int i;
  611. if(!numspechit || !(mobj->flags&MF_MISSILE) || !mobj->target)
  612. {
  613. return;
  614. }
  615. if(!mobj->target->player)
  616. {
  617. return;
  618. }
  619. for(i = numspechit-1; i >= 0; i--)
  620. {
  621. P_ShootSpecialLine(mobj->target, spechit[i]);
  622. }
  623. }
  624. /*
  625. ===================
  626. =
  627. = P_TryMove
  628. =
  629. = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
  630. = is set
  631. =
  632. ===================
  633. */
  634. boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y)
  635. {
  636. fixed_t oldx, oldy;
  637. int side, oldside;
  638. line_t *ld;
  639. floatok = false;
  640. if(!P_CheckPosition(thing, x, y))
  641. { // Solid wall or thing
  642. CheckMissileImpact(thing);
  643. return false;
  644. }
  645. if(!(thing->flags&MF_NOCLIP))
  646. {
  647. if(tmceilingz-tmfloorz < thing->height)
  648. { // Doesn't fit
  649. CheckMissileImpact(thing);
  650. return false;
  651. }
  652. floatok = true;
  653. if(!(thing->flags&MF_TELEPORT)
  654. && tmceilingz-thing->z < thing->height
  655. && !(thing->flags2&MF2_FLY))
  656. { // mobj must lower itself to fit
  657. CheckMissileImpact(thing);
  658. return false;
  659. }
  660. if(thing->flags2&MF2_FLY)
  661. {
  662. if(thing->z+thing->height > tmceilingz)
  663. {
  664. thing->momz = -8*FRACUNIT;
  665. return false;
  666. }
  667. else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
  668. {
  669. thing->momz = 8*FRACUNIT;
  670. return false;
  671. }
  672. }
  673. if(!(thing->flags&MF_TELEPORT)
  674. // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
  675. && thing->type != MT_MNTRFX2
  676. && tmfloorz-thing->z > 24*FRACUNIT)
  677. { // Too big a step up
  678. CheckMissileImpact(thing);
  679. return false;
  680. }
  681. if((thing->flags&MF_MISSILE) && tmfloorz > thing->z)
  682. {
  683. CheckMissileImpact(thing);
  684. }
  685. if(!(thing->flags&(MF_DROPOFF|MF_FLOAT))
  686. && tmfloorz-tmdropoffz > 24*FRACUNIT)
  687. { // Can't move over a dropoff
  688. return false;
  689. }
  690. }
  691. //
  692. // the move is ok, so link the thing into its new position
  693. //
  694. P_UnsetThingPosition (thing);
  695. oldx = thing->x;
  696. oldy = thing->y;
  697. thing->floorz = tmfloorz;
  698. thing->ceilingz = tmceilingz;
  699. thing->x = x;
  700. thing->y = y;
  701. P_SetThingPosition (thing);
  702. if(thing->flags2&MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID)
  703. {
  704. thing->flags2 |= MF2_FEETARECLIPPED;
  705. }
  706. else if(thing->flags2&MF2_FEETARECLIPPED)
  707. {
  708. thing->flags2 &= ~MF2_FEETARECLIPPED;
  709. }
  710. //
  711. // if any special lines were hit, do the effect
  712. //
  713. if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  714. while (numspechit--)
  715. {
  716. // see if the line was crossed
  717. ld = spechit[numspechit];
  718. side = P_PointOnLineSide (thing->x, thing->y, ld);
  719. oldside = P_PointOnLineSide (oldx, oldy, ld);
  720. if (side != oldside)
  721. {
  722. if (ld->special)
  723. P_CrossSpecialLine (ld-lines, oldside, thing);
  724. }
  725. }
  726. return true;
  727. }
  728. /*
  729. ==================
  730. =
  731. = P_ThingHeightClip
  732. =
  733. = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
  734. = anf possibly thing->z
  735. =
  736. = This is called for all nearby monsters whenever a sector changes height
  737. =
  738. = If the thing doesn't fit, the z will be set to the lowest value and
  739. = false will be returned
  740. ==================
  741. */
  742. boolean P_ThingHeightClip (mobj_t *thing)
  743. {
  744. boolean onfloor;
  745. onfloor = (thing->z == thing->floorz);
  746. P_CheckPosition (thing, thing->x, thing->y);
  747. // what about stranding a monster partially off an edge?
  748. thing->floorz = tmfloorz;
  749. thing->ceilingz = tmceilingz;
  750. if (onfloor)
  751. // walking monsters rise and fall with the floor
  752. thing->z = thing->floorz;
  753. else
  754. { // don't adjust a floating monster unless forced to
  755. if (thing->z+thing->height > thing->ceilingz)
  756. thing->z = thing->ceilingz - thing->height;
  757. }
  758. if (thing->ceilingz - thing->floorz < thing->height)
  759. return false;
  760. return true;
  761. }
  762. /*
  763. ==============================================================================
  764. SLIDE MOVE
  765. Allows the player to slide along any angled walls
  766. ==============================================================================
  767. */
  768. fixed_t bestslidefrac, secondslidefrac;
  769. line_t *bestslideline, *secondslideline;
  770. mobj_t *slidemo;
  771. fixed_t tmxmove, tmymove;
  772. /*
  773. ==================
  774. =
  775. = P_HitSlideLine
  776. =
  777. = Adjusts the xmove / ymove so that the next move will slide along the wall
  778. ==================
  779. */
  780. void P_HitSlideLine (line_t *ld)
  781. {
  782. int side;
  783. angle_t lineangle, moveangle, deltaangle;
  784. fixed_t movelen, newlen;
  785. if (ld->slopetype == ST_HORIZONTAL)
  786. {
  787. tmymove = 0;
  788. return;
  789. }
  790. if (ld->slopetype == ST_VERTICAL)
  791. {
  792. tmxmove = 0;
  793. return;
  794. }
  795. side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  796. lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  797. if (side == 1)
  798. lineangle += ANG180;
  799. moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  800. deltaangle = moveangle-lineangle;
  801. if (deltaangle > ANG180)
  802. deltaangle += ANG180;
  803. // I_Error ("SlideLine: ang>ANG180");
  804. lineangle >>= ANGLETOFINESHIFT;
  805. deltaangle >>= ANGLETOFINESHIFT;
  806. movelen = P_AproxDistance (tmxmove, tmymove);
  807. newlen = FixedMul (movelen, finecosine[deltaangle]);
  808. tmxmove = FixedMul (newlen, finecosine[lineangle]);
  809. tmymove = FixedMul (newlen, finesine[lineangle]);
  810. }
  811. /*
  812. ==============
  813. =
  814. = PTR_SlideTraverse
  815. =
  816. ==============
  817. */
  818. boolean PTR_SlideTraverse (intercept_t *in)
  819. {
  820. line_t *li;
  821. if (!in->isaline)
  822. I_Error ("PTR_SlideTraverse: not a line?");
  823. li = in->d.line;
  824. if ( ! (li->flags & ML_TWOSIDED) )
  825. {
  826. if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  827. return true; // don't hit the back side
  828. goto isblocking;
  829. }
  830. P_LineOpening (li); // set openrange, opentop, openbottom
  831. if (openrange < slidemo->height)
  832. goto isblocking; // doesn't fit
  833. if (opentop - slidemo->z < slidemo->height)
  834. goto isblocking; // mobj is too high
  835. if (openbottom - slidemo->z > 24*FRACUNIT )
  836. goto isblocking; // too big a step up
  837. return true; // this line doesn't block movement
  838. // the line does block movement, see if it is closer than best so far
  839. isblocking:
  840. if (in->frac < bestslidefrac)
  841. {
  842. secondslidefrac = bestslidefrac;
  843. secondslideline = bestslideline;
  844. bestslidefrac = in->frac;
  845. bestslideline = li;
  846. }
  847. return false; // stop
  848. }
  849. /*
  850. ==================
  851. =
  852. = P_SlideMove
  853. =
  854. = The momx / momy move is bad, so try to slide along a wall
  855. =
  856. = Find the first line hit, move flush to it, and slide along it
  857. =
  858. = This is a kludgy mess.
  859. ==================
  860. */
  861. void P_SlideMove (mobj_t *mo)
  862. {
  863. fixed_t leadx, leady;
  864. fixed_t trailx, traily;
  865. fixed_t newx, newy;
  866. int hitcount;
  867. slidemo = mo;
  868. hitcount = 0;
  869. retry:
  870. if (++hitcount == 3)
  871. goto stairstep; // don't loop forever
  872. //
  873. // trace along the three leading corners
  874. //
  875. if (mo->momx > 0)
  876. {
  877. leadx = mo->x + mo->radius;
  878. trailx = mo->x - mo->radius;
  879. }
  880. else
  881. {
  882. leadx = mo->x - mo->radius;
  883. trailx = mo->x + mo->radius;
  884. }
  885. if (mo->momy > 0)
  886. {
  887. leady = mo->y + mo->radius;
  888. traily = mo->y - mo->radius;
  889. }
  890. else
  891. {
  892. leady = mo->y - mo->radius;
  893. traily = mo->y + mo->radius;
  894. }
  895. bestslidefrac = FRACUNIT+1;
  896. P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
  897. PT_ADDLINES, PTR_SlideTraverse );
  898. P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
  899. PT_ADDLINES, PTR_SlideTraverse );
  900. P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
  901. PT_ADDLINES, PTR_SlideTraverse );
  902. //
  903. // move up to the wall
  904. //
  905. if (bestslidefrac == FRACUNIT+1)
  906. { // the move most have hit the middle, so stairstep
  907. stairstep:
  908. if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
  909. P_TryMove (mo, mo->x + mo->momx, mo->y);
  910. return;
  911. }
  912. bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
  913. if (bestslidefrac > 0)
  914. {
  915. newx = FixedMul (mo->momx, bestslidefrac);
  916. newy = FixedMul (mo->momy, bestslidefrac);
  917. if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
  918. goto stairstep;
  919. }
  920. //
  921. // now continue along the wall
  922. //
  923. bestslidefrac = FRACUNIT-(bestslidefrac+0x800); // remainder
  924. if (bestslidefrac > FRACUNIT)
  925. bestslidefrac = FRACUNIT;
  926. if (bestslidefrac <= 0)
  927. return;
  928. tmxmove = FixedMul (mo->momx, bestslidefrac);
  929. tmymove = FixedMul (mo->momy, bestslidefrac);
  930. P_HitSlideLine (bestslideline); // clip the moves
  931. mo->momx = tmxmove;
  932. mo->momy = tmymove;
  933. if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
  934. {
  935. goto retry;
  936. }
  937. }
  938. /*
  939. ==============================================================================
  940. P_LineAttack
  941. ==============================================================================
  942. */
  943. mobj_t *linetarget; // who got hit (or NULL)
  944. mobj_t *shootthing;
  945. fixed_t shootz; // height if not aiming up or down
  946. // ???: use slope for monsters?
  947. int la_damage;
  948. fixed_t attackrange;
  949. fixed_t aimslope;
  950. extern fixed_t topslope, bottomslope; // slopes to top and bottom of target
  951. /*
  952. ===============================================================================
  953. =
  954. = PTR_AimTraverse
  955. =
  956. = Sets linetaget and aimslope when a target is aimed at
  957. ===============================================================================
  958. */
  959. boolean PTR_AimTraverse (intercept_t *in)
  960. {
  961. line_t *li;
  962. mobj_t *th;
  963. fixed_t slope, thingtopslope, thingbottomslope;
  964. fixed_t dist;
  965. if (in->isaline)
  966. {
  967. li = in->d.line;
  968. if ( !(li->flags & ML_TWOSIDED) )
  969. return false; // stop
  970. //
  971. // crosses a two sided line
  972. // a two sided line will restrict the possible target ranges
  973. P_LineOpening (li);
  974. if (openbottom >= opentop)
  975. return false; // stop
  976. dist = FixedMul (attackrange, in->frac);
  977. if (li->frontsector->floorheight != li->backsector->floorheight)
  978. {
  979. slope = FixedDiv (openbottom - shootz , dist);
  980. if (slope > bottomslope)
  981. bottomslope = slope;
  982. }
  983. if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  984. {
  985. slope = FixedDiv (opentop - shootz , dist);
  986. if (slope < topslope)
  987. topslope = slope;
  988. }
  989. if (topslope <= bottomslope)
  990. return false; // stop
  991. return true; // shot continues
  992. }
  993. //
  994. // shoot a thing
  995. //
  996. th = in->d.thing;
  997. if (th == shootthing)
  998. return true; // can't shoot self
  999. if (!(th->flags&MF_SHOOTABLE))
  1000. return true; // corpse or something
  1001. if(th->type == MT_POD)
  1002. { // Can't auto-aim at pods
  1003. return(true);
  1004. }
  1005. // check angles to see if the thing can be aimed at
  1006. dist = FixedMul (attackrange, in->frac);
  1007. thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1008. if (thingtopslope < bottomslope)
  1009. return true; // shot over the thing
  1010. thingbottomslope = FixedDiv (th->z - shootz, dist);
  1011. if (thingbottomslope > topslope)
  1012. return true; // shot under the thing
  1013. //
  1014. // this thing can be hit!
  1015. //
  1016. if (thingtopslope > topslope)
  1017. thingtopslope = topslope;
  1018. if (thingbottomslope < bottomslope)
  1019. thingbottomslope = bottomslope;
  1020. aimslope = (thingtopslope+thingbottomslope)/2;
  1021. linetarget = th;
  1022. return false; // don't go any farther
  1023. }
  1024. /*
  1025. ==============================================================================
  1026. =
  1027. = PTR_ShootTraverse
  1028. =
  1029. ==============================================================================
  1030. */
  1031. boolean PTR_ShootTraverse (intercept_t *in)
  1032. {
  1033. fixed_t x,y,z;
  1034. fixed_t frac;
  1035. line_t *li;
  1036. mobj_t *th;
  1037. fixed_t slope;
  1038. fixed_t dist;
  1039. fixed_t thingtopslope, thingbottomslope;
  1040. mobj_t *mo;
  1041. if (in->isaline)
  1042. {
  1043. li = in->d.line;
  1044. if (li->special)
  1045. P_ShootSpecialLine (shootthing, li);
  1046. if ( !(li->flags & ML_TWOSIDED) )
  1047. goto hitline;
  1048. //
  1049. // crosses a two sided line
  1050. //
  1051. P_LineOpening (li);
  1052. dist = FixedMul (attackrange, in->frac);
  1053. if (li->frontsector->floorheight != li->backsector->floorheight)
  1054. {
  1055. slope = FixedDiv (openbottom - shootz , dist);
  1056. if (slope > aimslope)
  1057. goto hitline;
  1058. }
  1059. if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1060. {
  1061. slope = FixedDiv (opentop - shootz , dist);
  1062. if (slope < aimslope)
  1063. goto hitline;
  1064. }
  1065. return true; // shot continues
  1066. //
  1067. // hit line
  1068. //
  1069. hitline:
  1070. // position a bit closer
  1071. frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  1072. x = trace.x + FixedMul (trace.dx, frac);
  1073. y = trace.y + FixedMul (trace.dy, frac);
  1074. z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1075. if (li->frontsector->ceilingpic == skyflatnum)
  1076. {
  1077. if (z > li->frontsector->ceilingheight)
  1078. return false; // don't shoot the sky!
  1079. if (li->backsector && li->backsector->ceilingpic == skyflatnum)
  1080. return false; // it's a sky hack wall
  1081. }
  1082. P_SpawnPuff (x,y,z);
  1083. return false; // don't go any farther
  1084. }
  1085. //
  1086. // shoot a thing
  1087. //
  1088. th = in->d.thing;
  1089. if (th == shootthing)
  1090. return true; // can't shoot self
  1091. if (!(th->flags&MF_SHOOTABLE))
  1092. return true; // corpse or something
  1093. //
  1094. // check for physical attacks on a ghost
  1095. //
  1096. if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
  1097. {
  1098. return(true);
  1099. }
  1100. // check angles to see if the thing can be aimed at
  1101. dist = FixedMul (attackrange, in->frac);
  1102. thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1103. if (thingtopslope < aimslope)
  1104. return true; // shot over the thing
  1105. thingbottomslope = FixedDiv (th->z - shootz, dist);
  1106. if (thingbottomslope > aimslope)
  1107. return true; // shot under the thing
  1108. //
  1109. // hit thing
  1110. //
  1111. // position a bit closer
  1112. frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  1113. x = trace.x + FixedMul(trace.dx, frac);
  1114. y = trace.y + FixedMul(trace.dy, frac);
  1115. z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
  1116. if(PuffType == MT_BLASTERPUFF1)
  1117. { // Make blaster big puff
  1118. mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2);
  1119. S_StartSound(mo, sfx_blshit);
  1120. }
  1121. else
  1122. {
  1123. P_SpawnPuff(x, y, z);
  1124. }
  1125. if(la_damage)
  1126. {
  1127. if(!(in->d.thing->flags&MF_NOBLOOD) && P_Random() < 192)
  1128. {
  1129. P_BloodSplatter(x, y, z, in->d.thing);
  1130. }
  1131. P_DamageMobj(th, shootthing, shootthing, la_damage);
  1132. }
  1133. return(false); // don't go any farther
  1134. }
  1135. /*
  1136. =================
  1137. =
  1138. = P_AimLineAttack
  1139. =
  1140. =================
  1141. */
  1142. fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
  1143. {
  1144. fixed_t x2, y2;
  1145. angle >>= ANGLETOFINESHIFT;
  1146. shootthing = t1;
  1147. x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1148. y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1149. shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1150. topslope = 100*FRACUNIT/160; // can't shoot outside view angles
  1151. bottomslope = -100*FRACUNIT/160;
  1152. attackrange = distance;
  1153. linetarget = NULL;
  1154. P_PathTraverse ( t1->x, t1->y, x2, y2
  1155. , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
  1156. if (linetarget)
  1157. return aimslope;
  1158. return 0;
  1159. }
  1160. /*
  1161. =================
  1162. =
  1163. = P_LineAttack
  1164. =
  1165. = if damage == 0, it is just a test trace that will leave linetarget set
  1166. =
  1167. =================
  1168. */
  1169. void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
  1170. {
  1171. fixed_t x2, y2;
  1172. angle >>= ANGLETOFINESHIFT;
  1173. shootthing = t1;
  1174. la_damage = damage;
  1175. x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1176. y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1177. shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1178. if(t1->flags2&MF2_FEETARECLIPPED)
  1179. {
  1180. shootz -= FOOTCLIPSIZE;
  1181. }
  1182. attackrange = distance;
  1183. aimslope = slope;
  1184. P_PathTraverse ( t1->x, t1->y, x2, y2
  1185. , PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse );
  1186. }
  1187. /*
  1188. ==============================================================================
  1189. USE LINES
  1190. ==============================================================================
  1191. */
  1192. mobj_t *usething;
  1193. boolean PTR_UseTraverse (intercept_t *in)
  1194. {
  1195. if (!in->d.line->special)
  1196. {
  1197. P_LineOpening (in->d.line);
  1198. if (openrange <= 0)
  1199. {
  1200. //S_StartSound (usething, sfx_noway);
  1201. return false; // can't use through a wall
  1202. }
  1203. return true ; // not a special line, but keep checking
  1204. }
  1205. if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1206. return false; // don't use back sides
  1207. P_UseSpecialLine (usething, in->d.line);
  1208. return false; // can't use for than one special line in a row
  1209. }
  1210. /*
  1211. ================
  1212. =
  1213. = P_UseLines
  1214. =
  1215. = Looks for special lines in front of the player to activate
  1216. ================
  1217. */
  1218. void P_UseLines (player_t *player)
  1219. {
  1220. int angle;
  1221. fixed_t x1, y1, x2, y2;
  1222. usething = player->mo;
  1223. angle = player->mo->angle >> ANGLETOFINESHIFT;
  1224. x1 = player->mo->x;
  1225. y1 = player->mo->y;
  1226. x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1227. y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1228. P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1229. }
  1230. /*
  1231. ==============================================================================
  1232. RADIUS ATTACK
  1233. ==============================================================================
  1234. */
  1235. mobj_t *bombsource;
  1236. mobj_t *bombspot;
  1237. int bombdamage;
  1238. /*
  1239. =================
  1240. =
  1241. = PIT_RadiusAttack
  1242. =
  1243. = Source is the creature that casued the explosion at spot
  1244. =================
  1245. */
  1246. boolean PIT_RadiusAttack (mobj_t *thing)
  1247. {
  1248. fixed_t dx, dy, dist;
  1249. if(!(thing->flags&MF_SHOOTABLE))
  1250. {
  1251. return true;
  1252. }
  1253. if(thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1
  1254. || thing->type == MT_SORCERER2)
  1255. { // Episode 2 and 3 bosses take no damage from PIT_RadiusAttack
  1256. return(true);
  1257. }
  1258. dx = abs(thing->x - bombspot->x);
  1259. dy = abs(thing->y - bombspot->y);
  1260. dist = dx > dy ? dx : dy;
  1261. dist = (dist - thing->radius) >> FRACBITS;
  1262. if(dist < 0)
  1263. {
  1264. dist = 0;
  1265. }
  1266. if(dist >= bombdamage)
  1267. { // Out of range
  1268. return true;
  1269. }
  1270. if(P_CheckSight(thing, bombspot))
  1271. { // OK to damage, target is in direct path
  1272. P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist);
  1273. }
  1274. return(true);
  1275. }
  1276. /*
  1277. =================
  1278. =
  1279. = P_RadiusAttack
  1280. =
  1281. = Source is the creature that casued the explosion at spot
  1282. =================
  1283. */
  1284. void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage)
  1285. {
  1286. int x,y, xl, xh, yl, yh;
  1287. fixed_t dist;
  1288. dist = (damage+MAXRADIUS)<<FRACBITS;
  1289. yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
  1290. yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
  1291. xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
  1292. xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
  1293. bombspot = spot;
  1294. if(spot->type == MT_POD && spot->target)
  1295. {
  1296. bombsource = spot->target;
  1297. }
  1298. else
  1299. {
  1300. bombsource = source;
  1301. }
  1302. bombdamage = damage;
  1303. for (y=yl ; y<=yh ; y++)
  1304. for (x=xl ; x<=xh ; x++)
  1305. P_BlockThingsIterator (x, y, PIT_RadiusAttack );
  1306. }
  1307. /*
  1308. ==============================================================================
  1309. SECTOR HEIGHT CHANGING
  1310. = After modifying a sectors floor or ceiling height, call this
  1311. = routine to adjust the positions of all things that touch the
  1312. = sector.
  1313. =
  1314. = If anything doesn't fit anymore, true will be returned.
  1315. = If crunch is true, they will take damage as they are being crushed
  1316. = If Crunch is false, you should set the sector height back the way it
  1317. = was and call P_ChangeSector again to undo the changes
  1318. ==============================================================================
  1319. */
  1320. boolean crushchange;
  1321. boolean nofit;
  1322. /*
  1323. ===============
  1324. =
  1325. = PIT_ChangeSector
  1326. =
  1327. ===============
  1328. */
  1329. boolean PIT_ChangeSector (mobj_t *thing)
  1330. {
  1331. mobj_t *mo;
  1332. if (P_ThingHeightClip (thing))
  1333. return true; // keep checking
  1334. // crunch bodies to giblets
  1335. if (thing->health <= 0)
  1336. {
  1337. //P_SetMobjState (thing, S_GIBS);
  1338. thing->height = 0;
  1339. thing->radius = 0;
  1340. return true; // keep checking
  1341. }
  1342. // crunch dropped items
  1343. if (thing->flags & MF_DROPPED)
  1344. {
  1345. P_RemoveMobj (thing);
  1346. return true; // keep checking
  1347. }
  1348. if (! (thing->flags & MF_SHOOTABLE) )
  1349. return true; // assume it is bloody gibs or something
  1350. nofit = true;
  1351. if (crushchange && !(leveltime&3) )
  1352. {
  1353. P_DamageMobj(thing,NULL,NULL,10);
  1354. // spray blood in a random direction
  1355. mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD);
  1356. mo->momx = (P_Random() - P_Random ())<<12;
  1357. mo->momy = (P_Random() - P_Random ())<<12;
  1358. }
  1359. return true; // keep checking (crush other things)
  1360. }
  1361. /*
  1362. ===============
  1363. =
  1364. = P_ChangeSector
  1365. =
  1366. ===============
  1367. */
  1368. boolean P_ChangeSector (sector_t *sector, boolean crunch)
  1369. {
  1370. int x,y;
  1371. nofit = false;
  1372. crushchange = crunch;
  1373. // recheck heights for all things near the moving sector
  1374. for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  1375. for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  1376. P_BlockThingsIterator (x, y, PIT_ChangeSector);
  1377. return nofit;
  1378. }