P_MAP.C 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297
  1. //**************************************************************************
  2. //**
  3. //** p_map.c : Heretic 2 : Raven Software, Corp.
  4. //**
  5. //** $RCSfile: p_map.c,v $
  6. //** $Revision: 1.107 $
  7. //** $Date: 95/10/13 04:26:47 $
  8. //** $Author: paul $
  9. //**
  10. //**************************************************************************
  11. #include "h2def.h"
  12. #include "p_local.h"
  13. #include "soundst.h"
  14. static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj);
  15. /*
  16. ===============================================================================
  17. NOTES:
  18. ===============================================================================
  19. */
  20. /*
  21. ===============================================================================
  22. mobj_t NOTES
  23. 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.
  24. 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.
  25. The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
  26. 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.
  27. Every mobj_t is linked into a single sector based on it's origin coordinates.
  28. 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.
  29. 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.
  30. 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.
  31. ===============================================================================
  32. */
  33. fixed_t tmbbox[4];
  34. mobj_t *tmthing;
  35. mobj_t *tsthing;
  36. int tmflags;
  37. fixed_t tmx, tmy;
  38. boolean floatok; // if true, move would be ok if
  39. // within tmfloorz - tmceilingz
  40. fixed_t tmfloorz, tmceilingz, tmdropoffz;
  41. int tmfloorpic;
  42. // keep track of the line that lowers the ceiling, so missiles don't explode
  43. // against sky hack walls
  44. line_t *ceilingline;
  45. // keep track of special lines as they are hit, but don't process them
  46. // until the move is proven valid
  47. #define MAXSPECIALCROSS 8
  48. line_t *spechit[MAXSPECIALCROSS];
  49. int numspechit;
  50. mobj_t *onmobj; // generic global onmobj...used for landing on pods/players
  51. mobj_t *BlockingMobj;
  52. /*
  53. ===============================================================================
  54. TELEPORT MOVE
  55. ===============================================================================
  56. */
  57. /*
  58. ==================
  59. =
  60. = PIT_StompThing
  61. =
  62. ==================
  63. */
  64. boolean PIT_StompThing (mobj_t *thing)
  65. {
  66. fixed_t blockdist;
  67. if (!(thing->flags & MF_SHOOTABLE) )
  68. return true;
  69. blockdist = thing->radius + tmthing->radius;
  70. if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
  71. return true; // didn't hit it
  72. if (thing == tmthing)
  73. return true; // don't clip against self
  74. if(!(tmthing->flags2&MF2_TELESTOMP))
  75. { // Not allowed to stomp things
  76. return(false);
  77. }
  78. P_DamageMobj (thing, tmthing, tmthing, 10000);
  79. return true;
  80. }
  81. /*
  82. ===================
  83. =
  84. = P_TeleportMove
  85. =
  86. ===================
  87. */
  88. boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
  89. {
  90. int xl,xh,yl,yh,bx,by;
  91. subsector_t *newsubsec;
  92. //
  93. // kill anything occupying the position
  94. //
  95. tmthing = thing;
  96. tmflags = thing->flags;
  97. tmx = x;
  98. tmy = y;
  99. tmbbox[BOXTOP] = y + tmthing->radius;
  100. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  101. tmbbox[BOXRIGHT] = x + tmthing->radius;
  102. tmbbox[BOXLEFT] = x - tmthing->radius;
  103. newsubsec = R_PointInSubsector (x,y);
  104. ceilingline = NULL;
  105. //
  106. // the base floor / ceiling is from the subsector that contains the
  107. // point. Any contacted lines the step closer together will adjust them
  108. //
  109. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  110. tmceilingz = newsubsec->sector->ceilingheight;
  111. tmfloorpic = newsubsec->sector->floorpic;
  112. validcount++;
  113. numspechit = 0;
  114. //
  115. // stomp on any things contacted
  116. //
  117. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  118. xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  119. yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  120. yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  121. for (bx=xl ; bx<=xh ; bx++)
  122. for (by=yl ; by<=yh ; by++)
  123. if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  124. return false;
  125. //
  126. // the move is ok, so link the thing into its new position
  127. //
  128. P_UnsetThingPosition (thing);
  129. thing->floorz = tmfloorz;
  130. thing->ceilingz = tmceilingz;
  131. thing->x = x;
  132. thing->y = y;
  133. P_SetThingPosition (thing);
  134. return true;
  135. }
  136. boolean PIT_ThrustStompThing (mobj_t *thing)
  137. {
  138. fixed_t blockdist;
  139. if (!(thing->flags & MF_SHOOTABLE) )
  140. return true;
  141. blockdist = thing->radius + tsthing->radius;
  142. if ( abs(thing->x - tsthing->x) >= blockdist ||
  143. abs(thing->y - tsthing->y) >= blockdist ||
  144. (thing->z > tsthing->z+tsthing->height) )
  145. return true; // didn't hit it
  146. if (thing == tsthing)
  147. return true; // don't clip against self
  148. P_DamageMobj (thing, tsthing, tsthing, 10001);
  149. tsthing->args[1] = 1; // Mark thrust thing as bloody
  150. return true;
  151. }
  152. void PIT_ThrustSpike(mobj_t *actor)
  153. {
  154. int xl,xh,yl,yh,bx,by;
  155. int x0,x2,y0,y2;
  156. tsthing = actor;
  157. x0 = actor->x - actor->info->radius;
  158. x2 = actor->x + actor->info->radius;
  159. y0 = actor->y - actor->info->radius;
  160. y2 = actor->y + actor->info->radius;
  161. xl = (x0 - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  162. xh = (x2 - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  163. yl = (y0 - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  164. yh = (y2 - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  165. // stomp on any things contacted
  166. for (bx=xl ; bx<=xh ; bx++)
  167. for (by=yl ; by<=yh ; by++)
  168. P_BlockThingsIterator(bx,by,PIT_ThrustStompThing);
  169. }
  170. /*
  171. ===============================================================================
  172. MOVEMENT ITERATOR FUNCTIONS
  173. ===============================================================================
  174. */
  175. /*
  176. ==================
  177. =
  178. = PIT_CheckLine
  179. =
  180. = Adjusts tmfloorz and tmceilingz as lines are contacted
  181. ==================
  182. */
  183. boolean PIT_CheckLine(line_t *ld)
  184. {
  185. if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  186. || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  187. || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  188. || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
  189. {
  190. return(true);
  191. }
  192. if(P_BoxOnLineSide(tmbbox, ld) != -1)
  193. {
  194. return(true);
  195. }
  196. // a line has been hit
  197. /*
  198. =
  199. = The moving thing's destination position will cross the given line.
  200. = If this should not be allowed, return false.
  201. = If the line is special, keep track of it to process later if the move
  202. = is proven ok. NOTE: specials are NOT sorted by order, so two special lines
  203. = that are only 8 pixels apart could be crossed in either order.
  204. */
  205. if(!ld->backsector)
  206. { // One sided line
  207. if (tmthing->flags2&MF2_BLASTED)
  208. {
  209. P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  210. }
  211. CheckForPushSpecial(ld, 0, tmthing);
  212. return(false);
  213. }
  214. if(!(tmthing->flags&MF_MISSILE))
  215. {
  216. if(ld->flags&ML_BLOCKING)
  217. { // Explicitly blocking everything
  218. if (tmthing->flags2&MF2_BLASTED)
  219. {
  220. P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  221. }
  222. CheckForPushSpecial(ld, 0, tmthing);
  223. return(false);
  224. }
  225. if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS)
  226. { // Block monsters only
  227. if (tmthing->flags2&MF2_BLASTED)
  228. {
  229. P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  230. }
  231. return(false);
  232. }
  233. }
  234. P_LineOpening(ld); // set openrange, opentop, openbottom
  235. // adjust floor / ceiling heights
  236. if(opentop < tmceilingz)
  237. {
  238. tmceilingz = opentop;
  239. ceilingline = ld;
  240. }
  241. if(openbottom > tmfloorz)
  242. {
  243. tmfloorz = openbottom;
  244. }
  245. if(lowfloor < tmdropoffz)
  246. {
  247. tmdropoffz = lowfloor;
  248. }
  249. if(ld->special)
  250. { // Contacted a special line, add it to the list
  251. spechit[numspechit] = ld;
  252. numspechit++;
  253. }
  254. return(true);
  255. }
  256. //---------------------------------------------------------------------------
  257. //
  258. // FUNC PIT_CheckThing
  259. //
  260. //---------------------------------------------------------------------------
  261. boolean PIT_CheckThing(mobj_t *thing)
  262. {
  263. fixed_t blockdist;
  264. boolean solid;
  265. int damage;
  266. if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  267. { // Can't hit thing
  268. return(true);
  269. }
  270. blockdist = thing->radius+tmthing->radius;
  271. if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  272. { // Didn't hit thing
  273. return(true);
  274. }
  275. if(thing == tmthing)
  276. { // Don't clip against self
  277. return(true);
  278. }
  279. BlockingMobj = thing;
  280. if(tmthing->flags2&MF2_PASSMOBJ)
  281. { // check if a mobj passed over/under another object
  282. if(tmthing->type == MT_BISHOP && thing->type == MT_BISHOP)
  283. { // don't let bishops fly over other bishops
  284. return false;
  285. }
  286. if(tmthing->z >= thing->z+thing->height
  287. && !(thing->flags&MF_SPECIAL))
  288. {
  289. return(true);
  290. }
  291. else if(tmthing->z+tmthing->height < thing->z
  292. && !(thing->flags&MF_SPECIAL))
  293. { // under thing
  294. return(true);
  295. }
  296. }
  297. // Check for skulls slamming into things
  298. if(tmthing->flags&MF_SKULLFLY)
  299. {
  300. if(tmthing->type == MT_MINOTAUR)
  301. {
  302. // Slamming minotaurs shouldn't move non-creatures
  303. if (!(thing->flags&MF_COUNTKILL))
  304. {
  305. return(false);
  306. }
  307. }
  308. else if(tmthing->type == MT_HOLY_FX)
  309. {
  310. if(thing->flags&MF_SHOOTABLE && thing != tmthing->target)
  311. {
  312. if(netgame && !deathmatch && thing->player)
  313. { // don't attack other co-op players
  314. return true;
  315. }
  316. if(thing->flags2&MF2_REFLECTIVE
  317. && (thing->player || thing->flags2&MF2_BOSS))
  318. {
  319. tmthing->special1 = (int)tmthing->target;
  320. tmthing->target = thing;
  321. return true;
  322. }
  323. if(thing->flags&MF_COUNTKILL || thing->player)
  324. {
  325. tmthing->special1 = (int)thing;
  326. }
  327. if(P_Random() < 96)
  328. {
  329. damage = 12;
  330. if(thing->player || thing->flags2&MF2_BOSS)
  331. {
  332. damage = 3;
  333. // ghost burns out faster when attacking players/bosses
  334. tmthing->health -= 6;
  335. }
  336. P_DamageMobj(thing, tmthing, tmthing->target, damage);
  337. if(P_Random() < 128)
  338. {
  339. P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z,
  340. MT_HOLY_PUFF);
  341. S_StartSound(tmthing, SFX_SPIRIT_ATTACK);
  342. if(thing->flags&MF_COUNTKILL && P_Random() < 128
  343. && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
  344. {
  345. if ((thing->type == MT_CENTAUR) ||
  346. (thing->type == MT_CENTAURLEADER) ||
  347. (thing->type == MT_ETTIN))
  348. {
  349. S_StartSound(thing, SFX_PUPPYBEAT);
  350. }
  351. }
  352. }
  353. }
  354. if(thing->health <= 0)
  355. {
  356. tmthing->special1 = 0;
  357. }
  358. }
  359. return true;
  360. }
  361. damage = ((P_Random()%8)+1)*tmthing->damage;
  362. P_DamageMobj(thing, tmthing, tmthing, damage);
  363. tmthing->flags &= ~MF_SKULLFLY;
  364. tmthing->momx = tmthing->momy = tmthing->momz = 0;
  365. P_SetMobjState(tmthing, tmthing->info->seestate);
  366. return(false);
  367. }
  368. // Check for blasted thing running into another
  369. if(tmthing->flags2&MF2_BLASTED && thing->flags&MF_SHOOTABLE)
  370. {
  371. if (!(thing->flags2&MF2_BOSS) &&
  372. (thing->flags&MF_COUNTKILL))
  373. {
  374. thing->momx += tmthing->momx;
  375. thing->momy += tmthing->momy;
  376. if ((thing->momx + thing->momy) > 3*FRACUNIT)
  377. {
  378. damage = (tmthing->info->mass/100)+1;
  379. P_DamageMobj(thing, tmthing, tmthing, damage);
  380. damage = (thing->info->mass/100)+1;
  381. P_DamageMobj(tmthing, thing, thing, damage>>2);
  382. }
  383. return(false);
  384. }
  385. }
  386. // Check for missile
  387. if(tmthing->flags&MF_MISSILE)
  388. {
  389. // Check for a non-shootable mobj
  390. if(thing->flags2&MF2_NONSHOOTABLE)
  391. {
  392. return true;
  393. }
  394. // Check if it went over / under
  395. if(tmthing->z > thing->z+thing->height)
  396. { // Over thing
  397. return(true);
  398. }
  399. if(tmthing->z+tmthing->height < thing->z)
  400. { // Under thing
  401. return(true);
  402. }
  403. if(tmthing->flags2&MF2_FLOORBOUNCE)
  404. {
  405. if(tmthing->target == thing || !(thing->flags&MF_SOLID))
  406. {
  407. return true;
  408. }
  409. else
  410. {
  411. return false;
  412. }
  413. }
  414. if(tmthing->type == MT_LIGHTNING_FLOOR
  415. || tmthing->type == MT_LIGHTNING_CEILING)
  416. {
  417. if(thing->flags&MF_SHOOTABLE && thing != tmthing->target)
  418. {
  419. if(thing->info->mass != MAXINT)
  420. {
  421. thing->momx += tmthing->momx>>4;
  422. thing->momy += tmthing->momy>>4;
  423. }
  424. if((!thing->player && !(thing->flags2&MF2_BOSS))
  425. || !(leveltime&1))
  426. {
  427. if(thing->type == MT_CENTAUR
  428. || thing->type == MT_CENTAURLEADER)
  429. { // Lightning does more damage to centaurs
  430. P_DamageMobj(thing, tmthing, tmthing->target, 9);
  431. }
  432. else
  433. {
  434. P_DamageMobj(thing, tmthing, tmthing->target, 3);
  435. }
  436. if(!(S_GetSoundPlayingInfo(tmthing,
  437. SFX_MAGE_LIGHTNING_ZAP)))
  438. {
  439. S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP);
  440. }
  441. if(thing->flags&MF_COUNTKILL && P_Random() < 64
  442. && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
  443. {
  444. if ((thing->type == MT_CENTAUR) ||
  445. (thing->type == MT_CENTAURLEADER) ||
  446. (thing->type == MT_ETTIN))
  447. {
  448. S_StartSound(thing, SFX_PUPPYBEAT);
  449. }
  450. }
  451. }
  452. tmthing->health--;
  453. if(tmthing->health <= 0 || thing->health <= 0)
  454. {
  455. return false;
  456. }
  457. if(tmthing->type == MT_LIGHTNING_FLOOR)
  458. {
  459. if(tmthing->special2
  460. && !((mobj_t *)tmthing->special2)->special1)
  461. {
  462. ((mobj_t *)tmthing->special2)->special1 =
  463. (int)thing;
  464. }
  465. }
  466. else if(!tmthing->special1)
  467. {
  468. tmthing->special1 = (int)thing;
  469. }
  470. }
  471. return true; // lightning zaps through all sprites
  472. }
  473. else if(tmthing->type == MT_LIGHTNING_ZAP)
  474. {
  475. mobj_t *lmo;
  476. if(thing->flags&MF_SHOOTABLE && thing != tmthing->target)
  477. {
  478. lmo = (mobj_t *)tmthing->special2;
  479. if(lmo)
  480. {
  481. if(lmo->type == MT_LIGHTNING_FLOOR)
  482. {
  483. if(lmo->special2
  484. && !((mobj_t *)lmo->special2)->special1)
  485. {
  486. ((mobj_t *)lmo->special2)->special1 = (int)thing;
  487. }
  488. }
  489. else if(!lmo->special1)
  490. {
  491. lmo->special1 = (int)thing;
  492. }
  493. if(!(leveltime&3))
  494. {
  495. lmo->health--;
  496. }
  497. }
  498. }
  499. }
  500. else if(tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target)
  501. {
  502. if(!thing->player && !(thing->flags2&MF2_BOSS))
  503. {
  504. switch(thing->type)
  505. {
  506. case MT_FIGHTER_BOSS: // these not flagged boss
  507. case MT_CLERIC_BOSS: // so they can be blasted
  508. case MT_MAGE_BOSS:
  509. break;
  510. default:
  511. P_DamageMobj(thing, tmthing, tmthing->target, 10);
  512. return true;
  513. break;
  514. }
  515. }
  516. }
  517. if(tmthing->target && tmthing->target->type == thing->type)
  518. { // Don't hit same species as originator
  519. if(thing == tmthing->target)
  520. { // Don't missile self
  521. return(true);
  522. }
  523. if(!thing->player)
  524. { // Hit same species as originator, explode, no damage
  525. return(false);
  526. }
  527. }
  528. if(!(thing->flags&MF_SHOOTABLE))
  529. { // Didn't do any damage
  530. return!(thing->flags&MF_SOLID);
  531. }
  532. if(tmthing->flags2&MF2_RIP)
  533. {
  534. if (!(thing->flags&MF_NOBLOOD) &&
  535. !(thing->flags2&MF2_REFLECTIVE) &&
  536. !(thing->flags2&MF2_INVULNERABLE))
  537. { // Ok to spawn some blood
  538. P_RipperBlood(tmthing);
  539. }
  540. //S_StartSound(tmthing, sfx_ripslop);
  541. damage = ((P_Random()&3)+2)*tmthing->damage;
  542. P_DamageMobj(thing, tmthing, tmthing->target, damage);
  543. if(thing->flags2&MF2_PUSHABLE
  544. && !(tmthing->flags2&MF2_CANNOTPUSH))
  545. { // Push thing
  546. thing->momx += tmthing->momx>>2;
  547. thing->momy += tmthing->momy>>2;
  548. }
  549. numspechit = 0;
  550. return(true);
  551. }
  552. // Do damage
  553. damage = ((P_Random()%8)+1)*tmthing->damage;
  554. if(damage)
  555. {
  556. if (!(thing->flags&MF_NOBLOOD) &&
  557. !(thing->flags2&MF2_REFLECTIVE) &&
  558. !(thing->flags2&MF2_INVULNERABLE) &&
  559. !(tmthing->type == MT_TELOTHER_FX1) &&
  560. !(tmthing->type == MT_TELOTHER_FX2) &&
  561. !(tmthing->type == MT_TELOTHER_FX3) &&
  562. !(tmthing->type == MT_TELOTHER_FX4) &&
  563. !(tmthing->type == MT_TELOTHER_FX5) &&
  564. (P_Random() < 192))
  565. {
  566. P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
  567. }
  568. P_DamageMobj(thing, tmthing, tmthing->target, damage);
  569. }
  570. return(false);
  571. }
  572. if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
  573. { // Push thing
  574. thing->momx += tmthing->momx>>2;
  575. thing->momy += tmthing->momy>>2;
  576. }
  577. // Check for special thing
  578. if(thing->flags&MF_SPECIAL)
  579. {
  580. solid = thing->flags&MF_SOLID;
  581. if(tmflags&MF_PICKUP)
  582. { // Can be picked up by tmthing
  583. P_TouchSpecialThing(thing, tmthing); // Can remove thing
  584. }
  585. return(!solid);
  586. }
  587. return(!(thing->flags&MF_SOLID));
  588. }
  589. //---------------------------------------------------------------------------
  590. //
  591. // PIT_CheckOnmobjZ
  592. //
  593. //---------------------------------------------------------------------------
  594. boolean PIT_CheckOnmobjZ(mobj_t *thing)
  595. {
  596. fixed_t blockdist;
  597. if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  598. { // Can't hit thing
  599. return(true);
  600. }
  601. blockdist = thing->radius+tmthing->radius;
  602. if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  603. { // Didn't hit thing
  604. return(true);
  605. }
  606. if(thing == tmthing)
  607. { // Don't clip against self
  608. return(true);
  609. }
  610. if(tmthing->z > thing->z+thing->height)
  611. {
  612. return(true);
  613. }
  614. else if(tmthing->z+tmthing->height < thing->z)
  615. { // under thing
  616. return(true);
  617. }
  618. if(thing->flags&MF_SOLID)
  619. {
  620. onmobj = thing;
  621. }
  622. return(!(thing->flags&MF_SOLID));
  623. }
  624. /*
  625. ===============================================================================
  626. MOVEMENT CLIPPING
  627. ===============================================================================
  628. */
  629. //----------------------------------------------------------------------------
  630. //
  631. // FUNC P_TestMobjLocation
  632. //
  633. // Returns true if the mobj is not blocked by anything at its current
  634. // location, otherwise returns false.
  635. //
  636. //----------------------------------------------------------------------------
  637. boolean P_TestMobjLocation(mobj_t *mobj)
  638. {
  639. int flags;
  640. flags = mobj->flags;
  641. mobj->flags &= ~MF_PICKUP;
  642. if(P_CheckPosition(mobj, mobj->x, mobj->y))
  643. { // XY is ok, now check Z
  644. mobj->flags = flags;
  645. if((mobj->z < mobj->floorz)
  646. || (mobj->z+mobj->height > mobj->ceilingz))
  647. { // Bad Z
  648. return(false);
  649. }
  650. return(true);
  651. }
  652. mobj->flags = flags;
  653. return(false);
  654. }
  655. /*
  656. ==================
  657. =
  658. = P_CheckPosition
  659. =
  660. = This is purely informative, nothing is modified (except things picked up)
  661. in:
  662. a mobj_t (can be valid or invalid)
  663. a position to be checked (doesn't need to be related to the mobj_t->x,y)
  664. during:
  665. special things are touched if MF_PICKUP
  666. early out on solid lines?
  667. out:
  668. newsubsec
  669. floorz
  670. ceilingz
  671. tmdropoffz = the lowest point contacted (monsters won't move to a dropoff)
  672. speciallines[]
  673. numspeciallines
  674. mobj_t *BlockingMobj = pointer to thing that blocked position (NULL if not
  675. blocked, or blocked by a line).
  676. ==================
  677. */
  678. boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
  679. {
  680. int xl,xh,yl,yh,bx,by;
  681. subsector_t *newsubsec;
  682. tmthing = thing;
  683. tmflags = thing->flags;
  684. tmx = x;
  685. tmy = y;
  686. tmbbox[BOXTOP] = y + tmthing->radius;
  687. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  688. tmbbox[BOXRIGHT] = x + tmthing->radius;
  689. tmbbox[BOXLEFT] = x - tmthing->radius;
  690. newsubsec = R_PointInSubsector (x,y);
  691. ceilingline = NULL;
  692. //
  693. // the base floor / ceiling is from the subsector that contains the
  694. // point. Any contacted lines the step closer together will adjust them
  695. //
  696. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  697. tmceilingz = newsubsec->sector->ceilingheight;
  698. tmfloorpic = newsubsec->sector->floorpic;
  699. validcount++;
  700. numspechit = 0;
  701. if(tmflags&MF_NOCLIP && !(tmflags&MF_SKULLFLY))
  702. {
  703. return true;
  704. }
  705. //
  706. // check things first, possibly picking things up
  707. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  708. // into mapblocks based on their origin point, and can overlap into adjacent
  709. // blocks by up to MAXRADIUS units
  710. //
  711. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  712. xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  713. yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  714. yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  715. BlockingMobj = NULL;
  716. for (bx=xl ; bx<=xh ; bx++)
  717. for (by=yl ; by<=yh ; by++)
  718. if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  719. return false;
  720. //
  721. // check lines
  722. //
  723. if(tmflags&MF_NOCLIP)
  724. {
  725. return true;
  726. }
  727. BlockingMobj = NULL;
  728. xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
  729. xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
  730. yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
  731. yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
  732. for (bx=xl ; bx<=xh ; bx++)
  733. for (by=yl ; by<=yh ; by++)
  734. if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  735. return false;
  736. return true;
  737. }
  738. //=============================================================================
  739. //
  740. // P_CheckOnmobj(mobj_t *thing)
  741. //
  742. // Checks if the new Z position is legal
  743. //=============================================================================
  744. mobj_t *P_CheckOnmobj(mobj_t *thing)
  745. {
  746. int xl,xh,yl,yh,bx,by;
  747. subsector_t *newsubsec;
  748. fixed_t x;
  749. fixed_t y;
  750. mobj_t oldmo;
  751. x = thing->x;
  752. y = thing->y;
  753. tmthing = thing;
  754. tmflags = thing->flags;
  755. oldmo = *thing; // save the old mobj before the fake zmovement
  756. P_FakeZMovement(tmthing);
  757. tmx = x;
  758. tmy = y;
  759. tmbbox[BOXTOP] = y + tmthing->radius;
  760. tmbbox[BOXBOTTOM] = y - tmthing->radius;
  761. tmbbox[BOXRIGHT] = x + tmthing->radius;
  762. tmbbox[BOXLEFT] = x - tmthing->radius;
  763. newsubsec = R_PointInSubsector (x,y);
  764. ceilingline = NULL;
  765. //
  766. // the base floor / ceiling is from the subsector that contains the
  767. // point. Any contacted lines the step closer together will adjust them
  768. //
  769. tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  770. tmceilingz = newsubsec->sector->ceilingheight;
  771. tmfloorpic = newsubsec->sector->floorpic;
  772. validcount++;
  773. numspechit = 0;
  774. if ( tmflags & MF_NOCLIP )
  775. return NULL;
  776. //
  777. // check things first, possibly picking things up
  778. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  779. // into mapblocks based on their origin point, and can overlap into adjacent
  780. // blocks by up to MAXRADIUS units
  781. //
  782. xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  783. xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  784. yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  785. yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  786. for (bx=xl ; bx<=xh ; bx++)
  787. for (by=yl ; by<=yh ; by++)
  788. if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
  789. {
  790. *tmthing = oldmo;
  791. return onmobj;
  792. }
  793. *tmthing = oldmo;
  794. return NULL;
  795. }
  796. //=============================================================================
  797. //
  798. // P_FakeZMovement
  799. //
  800. // Fake the zmovement so that we can check if a move is legal
  801. //=============================================================================
  802. void P_FakeZMovement(mobj_t *mo)
  803. {
  804. int dist;
  805. int delta;
  806. //
  807. // adjust height
  808. //
  809. mo->z += mo->momz;
  810. if(mo->flags&MF_FLOAT && mo->target)
  811. { // float down towards target if too close
  812. if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
  813. {
  814. dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
  815. delta =( mo->target->z+(mo->height>>1))-mo->z;
  816. if (delta < 0 && dist < -(delta*3))
  817. mo->z -= FLOATSPEED;
  818. else if (delta > 0 && dist < (delta*3))
  819. mo->z += FLOATSPEED;
  820. }
  821. }
  822. if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
  823. && leveltime&2)
  824. {
  825. mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
  826. }
  827. //
  828. // clip movement
  829. //
  830. if(mo->z <= mo->floorz)
  831. { // Hit the floor
  832. mo->z = mo->floorz;
  833. if(mo->momz < 0)
  834. {
  835. mo->momz = 0;
  836. }
  837. if(mo->flags&MF_SKULLFLY)
  838. { // The skull slammed into something
  839. mo->momz = -mo->momz;
  840. }
  841. if(mo->info->crashstate && (mo->flags&MF_CORPSE))
  842. {
  843. return;
  844. }
  845. }
  846. else if(mo->flags2&MF2_LOGRAV)
  847. {
  848. if(mo->momz == 0)
  849. mo->momz = -(GRAVITY>>3)*2;
  850. else
  851. mo->momz -= GRAVITY>>3;
  852. }
  853. else if (! (mo->flags & MF_NOGRAVITY) )
  854. {
  855. if (mo->momz == 0)
  856. mo->momz = -GRAVITY*2;
  857. else
  858. mo->momz -= GRAVITY;
  859. }
  860. if (mo->z + mo->height > mo->ceilingz)
  861. { // hit the ceiling
  862. if (mo->momz > 0)
  863. mo->momz = 0;
  864. mo->z = mo->ceilingz - mo->height;
  865. if (mo->flags & MF_SKULLFLY)
  866. { // the skull slammed into something
  867. mo->momz = -mo->momz;
  868. }
  869. }
  870. }
  871. //===========================================================================
  872. //
  873. // CheckForPushSpecial
  874. //
  875. //===========================================================================
  876. static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj)
  877. {
  878. if (line->special)
  879. {
  880. if(mobj->flags2&MF2_PUSHWALL)
  881. {
  882. P_ActivateLine(line, mobj, side, SPAC_PUSH);
  883. }
  884. else if(mobj->flags2&MF2_IMPACT)
  885. {
  886. P_ActivateLine(line, mobj, side, SPAC_IMPACT);
  887. }
  888. }
  889. }
  890. /*
  891. ===================
  892. =
  893. = P_TryMove
  894. =
  895. = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
  896. = is set
  897. =
  898. ===================
  899. */
  900. boolean P_TryMove (mobj_t *thing, fixed_t x, fixed_t y)
  901. {
  902. fixed_t oldx, oldy;
  903. int side, oldside;
  904. line_t *ld;
  905. floatok = false;
  906. if(!P_CheckPosition(thing, x, y))
  907. { // Solid wall or thing
  908. if(!BlockingMobj || BlockingMobj->player
  909. || !thing->player)
  910. {
  911. goto pushline;
  912. }
  913. else if (BlockingMobj->z+BlockingMobj->height-thing->z
  914. > 24*FRACUNIT
  915. || (BlockingMobj->subsector->sector->ceilingheight
  916. -(BlockingMobj->z+BlockingMobj->height) < thing->height)
  917. || (tmceilingz-(BlockingMobj->z+BlockingMobj->height)
  918. < thing->height))
  919. {
  920. goto pushline;
  921. }
  922. }
  923. if(!(thing->flags&MF_NOCLIP))
  924. {
  925. if(tmceilingz-tmfloorz < thing->height)
  926. { // Doesn't fit
  927. goto pushline;
  928. }
  929. floatok = true;
  930. if(!(thing->flags&MF_TELEPORT)
  931. && tmceilingz-thing->z < thing->height
  932. && thing->type != MT_LIGHTNING_CEILING
  933. && !(thing->flags2&MF2_FLY))
  934. { // mobj must lower itself to fit
  935. goto pushline;
  936. }
  937. if(thing->flags2&MF2_FLY)
  938. {
  939. if(thing->z+thing->height > tmceilingz)
  940. {
  941. thing->momz = -8*FRACUNIT;
  942. goto pushline;
  943. }
  944. else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
  945. {
  946. thing->momz = 8*FRACUNIT;
  947. goto pushline;
  948. }
  949. }
  950. if(!(thing->flags&MF_TELEPORT)
  951. // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
  952. && thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR
  953. && tmfloorz-thing->z > 24*FRACUNIT)
  954. {
  955. goto pushline;
  956. }
  957. if (!(thing->flags&(MF_DROPOFF|MF_FLOAT)) &&
  958. (tmfloorz-tmdropoffz > 24*FRACUNIT) &&
  959. !(thing->flags2&MF2_BLASTED))
  960. { // Can't move over a dropoff unless it's been blasted
  961. return(false);
  962. }
  963. if(thing->flags2&MF2_CANTLEAVEFLOORPIC
  964. && (tmfloorpic != thing->subsector->sector->floorpic
  965. || tmfloorz-thing->z != 0))
  966. { // must stay within a sector of a certain floor type
  967. return false;
  968. }
  969. }
  970. //
  971. // the move is ok, so link the thing into its new position
  972. //
  973. P_UnsetThingPosition (thing);
  974. oldx = thing->x;
  975. oldy = thing->y;
  976. thing->floorz = tmfloorz;
  977. thing->ceilingz = tmceilingz;
  978. thing->floorpic = tmfloorpic;
  979. thing->x = x;
  980. thing->y = y;
  981. P_SetThingPosition (thing);
  982. if(thing->flags2&MF2_FLOORCLIP)
  983. {
  984. if(thing->z == thing->subsector->sector->floorheight
  985. && P_GetThingFloorType(thing) >= FLOOR_LIQUID)
  986. {
  987. thing->floorclip = 10*FRACUNIT;
  988. }
  989. else
  990. {
  991. thing->floorclip = 0;
  992. }
  993. }
  994. //
  995. // if any special lines were hit, do the effect
  996. //
  997. if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  998. {
  999. while (numspechit > 0)
  1000. {
  1001. numspechit--;
  1002. // see if the line was crossed
  1003. ld = spechit[numspechit];
  1004. side = P_PointOnLineSide (thing->x, thing->y, ld);
  1005. oldside = P_PointOnLineSide (oldx, oldy, ld);
  1006. if (side != oldside)
  1007. {
  1008. if (ld->special)
  1009. {
  1010. if(thing->player)
  1011. {
  1012. P_ActivateLine(ld, thing, oldside, SPAC_CROSS);
  1013. }
  1014. else if(thing->flags2&MF2_MCROSS)
  1015. {
  1016. P_ActivateLine(ld, thing, oldside, SPAC_MCROSS);
  1017. }
  1018. else if(thing->flags2&MF2_PCROSS)
  1019. {
  1020. P_ActivateLine(ld, thing, oldside, SPAC_PCROSS);
  1021. }
  1022. }
  1023. }
  1024. }
  1025. }
  1026. return true;
  1027. pushline:
  1028. if(!(thing->flags&(MF_TELEPORT|MF_NOCLIP)))
  1029. {
  1030. int numSpecHitTemp;
  1031. if (tmthing->flags2&MF2_BLASTED)
  1032. {
  1033. P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  1034. }
  1035. numSpecHitTemp = numspechit;
  1036. while (numSpecHitTemp > 0)
  1037. {
  1038. numSpecHitTemp--;
  1039. // see if the line was crossed
  1040. ld = spechit[numSpecHitTemp];
  1041. side = P_PointOnLineSide (thing->x, thing->y, ld);
  1042. CheckForPushSpecial(ld, side, thing);
  1043. }
  1044. }
  1045. return false;
  1046. }
  1047. /*
  1048. ==================
  1049. =
  1050. = P_ThingHeightClip
  1051. =
  1052. = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
  1053. = anf possibly thing->z
  1054. =
  1055. = This is called for all nearby monsters whenever a sector changes height
  1056. =
  1057. = If the thing doesn't fit, the z will be set to the lowest value and
  1058. = false will be returned
  1059. ==================
  1060. */
  1061. boolean P_ThingHeightClip (mobj_t *thing)
  1062. {
  1063. boolean onfloor;
  1064. onfloor = (thing->z == thing->floorz);
  1065. P_CheckPosition (thing, thing->x, thing->y);
  1066. // what about stranding a monster partially off an edge?
  1067. thing->floorz = tmfloorz;
  1068. thing->ceilingz = tmceilingz;
  1069. thing->floorpic = tmfloorpic;
  1070. if (onfloor)
  1071. { // walking monsters rise and fall with the floor
  1072. if((thing->z-thing->floorz < 9*FRACUNIT)
  1073. || (thing->flags&MF_NOGRAVITY))
  1074. {
  1075. thing->z = thing->floorz;
  1076. }
  1077. }
  1078. else
  1079. { // don't adjust a floating monster unless forced to
  1080. if (thing->z+thing->height > thing->ceilingz)
  1081. thing->z = thing->ceilingz - thing->height;
  1082. }
  1083. if (thing->ceilingz - thing->floorz < thing->height)
  1084. return false;
  1085. return true;
  1086. }
  1087. /*
  1088. ==============================================================================
  1089. SLIDE MOVE
  1090. Allows the player to slide along any angled walls
  1091. ==============================================================================
  1092. */
  1093. fixed_t bestslidefrac, secondslidefrac;
  1094. line_t *bestslideline, *secondslideline;
  1095. mobj_t *slidemo;
  1096. fixed_t tmxmove, tmymove;
  1097. /*
  1098. ==================
  1099. =
  1100. = P_HitSlideLine
  1101. =
  1102. = Adjusts the xmove / ymove so that the next move will slide along the wall
  1103. ==================
  1104. */
  1105. void P_HitSlideLine (line_t *ld)
  1106. {
  1107. int side;
  1108. angle_t lineangle, moveangle, deltaangle;
  1109. fixed_t movelen, newlen;
  1110. if (ld->slopetype == ST_HORIZONTAL)
  1111. {
  1112. tmymove = 0;
  1113. return;
  1114. }
  1115. if (ld->slopetype == ST_VERTICAL)
  1116. {
  1117. tmxmove = 0;
  1118. return;
  1119. }
  1120. side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  1121. lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  1122. if (side == 1)
  1123. lineangle += ANG180;
  1124. moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  1125. deltaangle = moveangle-lineangle;
  1126. if (deltaangle > ANG180)
  1127. deltaangle += ANG180;
  1128. // I_Error ("SlideLine: ang>ANG180");
  1129. lineangle >>= ANGLETOFINESHIFT;
  1130. deltaangle >>= ANGLETOFINESHIFT;
  1131. movelen = P_AproxDistance (tmxmove, tmymove);
  1132. newlen = FixedMul (movelen, finecosine[deltaangle]);
  1133. tmxmove = FixedMul (newlen, finecosine[lineangle]);
  1134. tmymove = FixedMul (newlen, finesine[lineangle]);
  1135. }
  1136. /*
  1137. ==============
  1138. =
  1139. = PTR_SlideTraverse
  1140. =
  1141. ==============
  1142. */
  1143. boolean PTR_SlideTraverse (intercept_t *in)
  1144. {
  1145. line_t *li;
  1146. if (!in->isaline)
  1147. I_Error ("PTR_SlideTraverse: not a line?");
  1148. li = in->d.line;
  1149. if ( ! (li->flags & ML_TWOSIDED) )
  1150. {
  1151. if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  1152. return true; // don't hit the back side
  1153. goto isblocking;
  1154. }
  1155. P_LineOpening (li); // set openrange, opentop, openbottom
  1156. if (openrange < slidemo->height)
  1157. goto isblocking; // doesn't fit
  1158. if (opentop - slidemo->z < slidemo->height)
  1159. goto isblocking; // mobj is too high
  1160. if (openbottom - slidemo->z > 24*FRACUNIT )
  1161. goto isblocking; // too big a step up
  1162. return true; // this line doesn't block movement
  1163. // the line does block movement, see if it is closer than best so far
  1164. isblocking:
  1165. if (in->frac < bestslidefrac)
  1166. {
  1167. secondslidefrac = bestslidefrac;
  1168. secondslideline = bestslideline;
  1169. bestslidefrac = in->frac;
  1170. bestslideline = li;
  1171. }
  1172. return false; // stop
  1173. }
  1174. /*
  1175. ==================
  1176. =
  1177. = P_SlideMove
  1178. =
  1179. = The momx / momy move is bad, so try to slide along a wall
  1180. =
  1181. = Find the first line hit, move flush to it, and slide along it
  1182. =
  1183. = This is a kludgy mess.
  1184. ==================
  1185. */
  1186. void P_SlideMove (mobj_t *mo)
  1187. {
  1188. fixed_t leadx, leady;
  1189. fixed_t trailx, traily;
  1190. fixed_t newx, newy;
  1191. int hitcount;
  1192. slidemo = mo;
  1193. hitcount = 0;
  1194. retry:
  1195. if (++hitcount == 3)
  1196. goto stairstep; // don't loop forever
  1197. //
  1198. // trace along the three leading corners
  1199. //
  1200. if (mo->momx > 0)
  1201. {
  1202. leadx = mo->x + mo->radius;
  1203. trailx = mo->x - mo->radius;
  1204. }
  1205. else
  1206. {
  1207. leadx = mo->x - mo->radius;
  1208. trailx = mo->x + mo->radius;
  1209. }
  1210. if (mo->momy > 0)
  1211. {
  1212. leady = mo->y + mo->radius;
  1213. traily = mo->y - mo->radius;
  1214. }
  1215. else
  1216. {
  1217. leady = mo->y - mo->radius;
  1218. traily = mo->y + mo->radius;
  1219. }
  1220. bestslidefrac = FRACUNIT+1;
  1221. P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
  1222. PT_ADDLINES, PTR_SlideTraverse );
  1223. P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
  1224. PT_ADDLINES, PTR_SlideTraverse );
  1225. P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
  1226. PT_ADDLINES, PTR_SlideTraverse );
  1227. //
  1228. // move up to the wall
  1229. //
  1230. if(bestslidefrac == FRACUNIT+1)
  1231. { // the move must have hit the middle, so stairstep
  1232. stairstep:
  1233. if(!P_TryMove(mo, mo->x, mo->y+mo->momy))
  1234. {
  1235. P_TryMove(mo, mo->x+mo->momx, mo->y);
  1236. }
  1237. return;
  1238. }
  1239. bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
  1240. if (bestslidefrac > 0)
  1241. {
  1242. newx = FixedMul (mo->momx, bestslidefrac);
  1243. newy = FixedMul (mo->momy, bestslidefrac);
  1244. if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
  1245. goto stairstep;
  1246. }
  1247. //
  1248. // now continue along the wall
  1249. //
  1250. bestslidefrac = FRACUNIT-(bestslidefrac+0x800); // remainder
  1251. if (bestslidefrac > FRACUNIT)
  1252. bestslidefrac = FRACUNIT;
  1253. if (bestslidefrac <= 0)
  1254. return;
  1255. tmxmove = FixedMul (mo->momx, bestslidefrac);
  1256. tmymove = FixedMul (mo->momy, bestslidefrac);
  1257. P_HitSlideLine (bestslideline); // clip the moves
  1258. mo->momx = tmxmove;
  1259. mo->momy = tmymove;
  1260. if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
  1261. {
  1262. goto retry;
  1263. }
  1264. }
  1265. //============================================================================
  1266. //
  1267. // PTR_BounceTraverse
  1268. //
  1269. //============================================================================
  1270. boolean PTR_BounceTraverse(intercept_t *in)
  1271. {
  1272. line_t *li;
  1273. if (!in->isaline)
  1274. I_Error ("PTR_BounceTraverse: not a line?");
  1275. li = in->d.line;
  1276. if (!(li->flags&ML_TWOSIDED))
  1277. {
  1278. if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  1279. return true; // don't hit the back side
  1280. goto bounceblocking;
  1281. }
  1282. P_LineOpening (li); // set openrange, opentop, openbottom
  1283. if (openrange < slidemo->height)
  1284. goto bounceblocking; // doesn't fit
  1285. if (opentop - slidemo->z < slidemo->height)
  1286. goto bounceblocking; // mobj is too high
  1287. return true; // this line doesn't block movement
  1288. // the line does block movement, see if it is closer than best so far
  1289. bounceblocking:
  1290. if (in->frac < bestslidefrac)
  1291. {
  1292. secondslidefrac = bestslidefrac;
  1293. secondslideline = bestslideline;
  1294. bestslidefrac = in->frac;
  1295. bestslideline = li;
  1296. }
  1297. return false; // stop
  1298. }
  1299. //============================================================================
  1300. //
  1301. // P_BounceWall
  1302. //
  1303. //============================================================================
  1304. void P_BounceWall(mobj_t *mo)
  1305. {
  1306. fixed_t leadx, leady;
  1307. int side;
  1308. angle_t lineangle, moveangle, deltaangle;
  1309. fixed_t movelen;
  1310. slidemo = mo;
  1311. //
  1312. // trace along the three leading corners
  1313. //
  1314. if(mo->momx > 0)
  1315. {
  1316. leadx = mo->x+mo->radius;
  1317. }
  1318. else
  1319. {
  1320. leadx = mo->x-mo->radius;
  1321. }
  1322. if(mo->momy > 0)
  1323. {
  1324. leady = mo->y+mo->radius;
  1325. }
  1326. else
  1327. {
  1328. leady = mo->y-mo->radius;
  1329. }
  1330. bestslidefrac = FRACUNIT+1;
  1331. P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy,
  1332. PT_ADDLINES, PTR_BounceTraverse);
  1333. side = P_PointOnLineSide(mo->x, mo->y, bestslideline);
  1334. lineangle = R_PointToAngle2(0, 0, bestslideline->dx,
  1335. bestslideline->dy);
  1336. if(side == 1)
  1337. lineangle += ANG180;
  1338. moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
  1339. deltaangle = (2*lineangle)-moveangle;
  1340. // if (deltaangle > ANG180)
  1341. // deltaangle += ANG180;
  1342. // I_Error ("SlideLine: ang>ANG180");
  1343. lineangle >>= ANGLETOFINESHIFT;
  1344. deltaangle >>= ANGLETOFINESHIFT;
  1345. movelen = P_AproxDistance(mo->momx, mo->momy);
  1346. movelen = FixedMul(movelen, 0.75*FRACUNIT); // friction
  1347. if (movelen < FRACUNIT) movelen = 2*FRACUNIT;
  1348. mo->momx = FixedMul(movelen, finecosine[deltaangle]);
  1349. mo->momy = FixedMul(movelen, finesine[deltaangle]);
  1350. }
  1351. /*
  1352. ==============================================================================
  1353. P_LineAttack
  1354. ==============================================================================
  1355. */
  1356. mobj_t *PuffSpawned;
  1357. mobj_t *linetarget; // who got hit (or NULL)
  1358. mobj_t *shootthing;
  1359. fixed_t shootz; // height if not aiming up or down
  1360. // ???: use slope for monsters?
  1361. int la_damage;
  1362. fixed_t attackrange;
  1363. fixed_t aimslope;
  1364. extern fixed_t topslope, bottomslope; // slopes to top and bottom of target
  1365. /*
  1366. ===============================================================================
  1367. =
  1368. = PTR_AimTraverse
  1369. =
  1370. = Sets linetaget and aimslope when a target is aimed at
  1371. ===============================================================================
  1372. */
  1373. boolean PTR_AimTraverse (intercept_t *in)
  1374. {
  1375. line_t *li;
  1376. mobj_t *th;
  1377. fixed_t slope, thingtopslope, thingbottomslope;
  1378. fixed_t dist;
  1379. if (in->isaline)
  1380. {
  1381. li = in->d.line;
  1382. if ( !(li->flags & ML_TWOSIDED) )
  1383. return false; // stop
  1384. //
  1385. // crosses a two sided line
  1386. // a two sided line will restrict the possible target ranges
  1387. P_LineOpening (li);
  1388. if (openbottom >= opentop)
  1389. return false; // stop
  1390. dist = FixedMul (attackrange, in->frac);
  1391. if (li->frontsector->floorheight != li->backsector->floorheight)
  1392. {
  1393. slope = FixedDiv (openbottom - shootz , dist);
  1394. if (slope > bottomslope)
  1395. bottomslope = slope;
  1396. }
  1397. if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1398. {
  1399. slope = FixedDiv (opentop - shootz , dist);
  1400. if (slope < topslope)
  1401. topslope = slope;
  1402. }
  1403. if (topslope <= bottomslope)
  1404. return false; // stop
  1405. return true; // shot continues
  1406. }
  1407. //
  1408. // shoot a thing
  1409. //
  1410. th = in->d.thing;
  1411. if (th == shootthing)
  1412. return true; // can't shoot self
  1413. if(!(th->flags&MF_SHOOTABLE))
  1414. { // corpse or something
  1415. return true;
  1416. }
  1417. if(th->player && netgame && !deathmatch)
  1418. { // don't aim at fellow co-op players
  1419. return true;
  1420. }
  1421. // check angles to see if the thing can be aimed at
  1422. dist = FixedMul (attackrange, in->frac);
  1423. thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1424. if (thingtopslope < bottomslope)
  1425. return true; // shot over the thing
  1426. thingbottomslope = FixedDiv (th->z - shootz, dist);
  1427. if (thingbottomslope > topslope)
  1428. return true; // shot under the thing
  1429. //
  1430. // this thing can be hit!
  1431. //
  1432. if (thingtopslope > topslope)
  1433. thingtopslope = topslope;
  1434. if (thingbottomslope < bottomslope)
  1435. thingbottomslope = bottomslope;
  1436. aimslope = (thingtopslope+thingbottomslope)/2;
  1437. linetarget = th;
  1438. return false; // don't go any farther
  1439. }
  1440. /*
  1441. ==============================================================================
  1442. =
  1443. = PTR_ShootTraverse
  1444. =
  1445. ==============================================================================
  1446. */
  1447. boolean PTR_ShootTraverse (intercept_t *in)
  1448. {
  1449. fixed_t x,y,z;
  1450. fixed_t frac;
  1451. line_t *li;
  1452. mobj_t *th;
  1453. fixed_t slope;
  1454. fixed_t dist;
  1455. fixed_t thingtopslope, thingbottomslope;
  1456. extern mobj_t LavaInflictor;
  1457. if (in->isaline)
  1458. {
  1459. li = in->d.line;
  1460. if (li->special)
  1461. {
  1462. P_ActivateLine(li, shootthing, 0, SPAC_IMPACT);
  1463. // P_ShootSpecialLine (shootthing, li);
  1464. }
  1465. if ( !(li->flags & ML_TWOSIDED) )
  1466. goto hitline;
  1467. //
  1468. // crosses a two sided line
  1469. //
  1470. P_LineOpening (li);
  1471. dist = FixedMul (attackrange, in->frac);
  1472. if (li->frontsector->floorheight != li->backsector->floorheight)
  1473. {
  1474. slope = FixedDiv (openbottom - shootz , dist);
  1475. if (slope > aimslope)
  1476. goto hitline;
  1477. }
  1478. if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1479. {
  1480. slope = FixedDiv (opentop - shootz , dist);
  1481. if (slope < aimslope)
  1482. goto hitline;
  1483. }
  1484. return true; // shot continues
  1485. //
  1486. // hit line
  1487. //
  1488. hitline:
  1489. // position a bit closer
  1490. frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  1491. x = trace.x + FixedMul (trace.dx, frac);
  1492. y = trace.y + FixedMul (trace.dy, frac);
  1493. z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1494. if (li->frontsector->ceilingpic == skyflatnum)
  1495. {
  1496. if (z > li->frontsector->ceilingheight)
  1497. return false; // don't shoot the sky!
  1498. if (li->backsector && li->backsector->ceilingpic == skyflatnum)
  1499. return false; // it's a sky hack wall
  1500. }
  1501. P_SpawnPuff (x,y,z);
  1502. return false; // don't go any farther
  1503. }
  1504. //
  1505. // shoot a thing
  1506. //
  1507. th = in->d.thing;
  1508. if (th == shootthing)
  1509. return true; // can't shoot self
  1510. if (!(th->flags&MF_SHOOTABLE))
  1511. return true; // corpse or something
  1512. //
  1513. // check for physical attacks on a ghost
  1514. //
  1515. /* FIX: Impliment Heretic 2 weapons here
  1516. if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
  1517. {
  1518. return(true);
  1519. }
  1520. */
  1521. // check angles to see if the thing can be aimed at
  1522. dist = FixedMul (attackrange, in->frac);
  1523. thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1524. if (thingtopslope < aimslope)
  1525. return true; // shot over the thing
  1526. thingbottomslope = FixedDiv (th->z - shootz, dist);
  1527. if (thingbottomslope > aimslope)
  1528. return true; // shot under the thing
  1529. //
  1530. // hit thing
  1531. //
  1532. // position a bit closer
  1533. frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  1534. x = trace.x + FixedMul(trace.dx, frac);
  1535. y = trace.y + FixedMul(trace.dy, frac);
  1536. z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
  1537. P_SpawnPuff(x, y, z);
  1538. if(la_damage)
  1539. {
  1540. if (!(in->d.thing->flags&MF_NOBLOOD) &&
  1541. !(in->d.thing->flags2&MF2_INVULNERABLE))
  1542. {
  1543. if(PuffType == MT_AXEPUFF || PuffType == MT_AXEPUFF_GLOW)
  1544. {
  1545. P_BloodSplatter2(x, y, z, in->d.thing);
  1546. }
  1547. if(P_Random() < 192)
  1548. {
  1549. P_BloodSplatter(x, y, z, in->d.thing);
  1550. }
  1551. }
  1552. if(PuffType == MT_FLAMEPUFF2)
  1553. { // Cleric FlameStrike does fire damage
  1554. P_DamageMobj(th, &LavaInflictor, shootthing, la_damage);
  1555. }
  1556. else
  1557. {
  1558. P_DamageMobj(th, shootthing, shootthing, la_damage);
  1559. }
  1560. }
  1561. return(false); // don't go any farther
  1562. }
  1563. /*
  1564. =================
  1565. =
  1566. = P_AimLineAttack
  1567. =
  1568. =================
  1569. */
  1570. fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
  1571. {
  1572. fixed_t x2, y2;
  1573. angle >>= ANGLETOFINESHIFT;
  1574. shootthing = t1;
  1575. x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1576. y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1577. shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1578. topslope = 100*FRACUNIT/160; // can't shoot outside view angles
  1579. bottomslope = -100*FRACUNIT/160;
  1580. attackrange = distance;
  1581. linetarget = NULL;
  1582. P_PathTraverse ( t1->x, t1->y, x2, y2
  1583. , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
  1584. if (linetarget)
  1585. return aimslope;
  1586. return 0;
  1587. }
  1588. /*
  1589. =================
  1590. =
  1591. = P_LineAttack
  1592. =
  1593. = if damage == 0, it is just a test trace that will leave linetarget set
  1594. =
  1595. =================
  1596. */
  1597. void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
  1598. {
  1599. fixed_t x2, y2;
  1600. angle >>= ANGLETOFINESHIFT;
  1601. shootthing = t1;
  1602. la_damage = damage;
  1603. x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1604. y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1605. shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1606. shootz -= t1->floorclip;
  1607. attackrange = distance;
  1608. aimslope = slope;
  1609. if(P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
  1610. PTR_ShootTraverse))
  1611. {
  1612. switch(PuffType)
  1613. {
  1614. case MT_PUNCHPUFF:
  1615. S_StartSound(t1, SFX_FIGHTER_PUNCH_MISS);
  1616. break;
  1617. case MT_HAMMERPUFF:
  1618. case MT_AXEPUFF:
  1619. case MT_AXEPUFF_GLOW:
  1620. S_StartSound(t1, SFX_FIGHTER_HAMMER_MISS);
  1621. break;
  1622. case MT_FLAMEPUFF:
  1623. P_SpawnPuff(x2, y2, shootz+FixedMul(slope, distance));
  1624. break;
  1625. default:
  1626. break;
  1627. }
  1628. }
  1629. }
  1630. /*
  1631. ==============================================================================
  1632. USE LINES
  1633. ==============================================================================
  1634. */
  1635. mobj_t *usething;
  1636. boolean PTR_UseTraverse (intercept_t *in)
  1637. {
  1638. int sound;
  1639. fixed_t pheight;
  1640. if (!in->d.line->special)
  1641. {
  1642. P_LineOpening (in->d.line);
  1643. if (openrange <= 0)
  1644. {
  1645. if(usething->player)
  1646. {
  1647. switch(usething->player->class)
  1648. {
  1649. case PCLASS_FIGHTER:
  1650. sound = SFX_PLAYER_FIGHTER_FAILED_USE;
  1651. break;
  1652. case PCLASS_CLERIC:
  1653. sound = SFX_PLAYER_CLERIC_FAILED_USE;
  1654. break;
  1655. case PCLASS_MAGE:
  1656. sound = SFX_PLAYER_MAGE_FAILED_USE;
  1657. break;
  1658. case PCLASS_PIG:
  1659. sound = SFX_PIG_ACTIVE1;
  1660. break;
  1661. default:
  1662. sound = SFX_NONE;
  1663. break;
  1664. }
  1665. S_StartSound(usething, sound);
  1666. }
  1667. return false; // can't use through a wall
  1668. }
  1669. if(usething->player)
  1670. {
  1671. pheight = usething->z + (usething->height/2);
  1672. if ((opentop < pheight) || (openbottom > pheight))
  1673. {
  1674. switch(usething->player->class)
  1675. {
  1676. case PCLASS_FIGHTER:
  1677. sound = SFX_PLAYER_FIGHTER_FAILED_USE;
  1678. break;
  1679. case PCLASS_CLERIC:
  1680. sound = SFX_PLAYER_CLERIC_FAILED_USE;
  1681. break;
  1682. case PCLASS_MAGE:
  1683. sound = SFX_PLAYER_MAGE_FAILED_USE;
  1684. break;
  1685. case PCLASS_PIG:
  1686. sound = SFX_PIG_ACTIVE1;
  1687. break;
  1688. default:
  1689. sound = SFX_NONE;
  1690. break;
  1691. }
  1692. S_StartSound(usething, sound);
  1693. }
  1694. }
  1695. return true ; // not a special line, but keep checking
  1696. }
  1697. if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1698. return false; // don't use back sides
  1699. // P_UseSpecialLine (usething, in->d.line);
  1700. P_ActivateLine(in->d.line, usething, 0, SPAC_USE);
  1701. return false; // can't use for than one special line in a row
  1702. }
  1703. /*
  1704. ================
  1705. =
  1706. = P_UseLines
  1707. =
  1708. = Looks for special lines in front of the player to activate
  1709. ================
  1710. */
  1711. void P_UseLines (player_t *player)
  1712. {
  1713. int angle;
  1714. fixed_t x1, y1, x2, y2;
  1715. usething = player->mo;
  1716. angle = player->mo->angle >> ANGLETOFINESHIFT;
  1717. x1 = player->mo->x;
  1718. y1 = player->mo->y;
  1719. x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1720. y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1721. P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1722. }
  1723. //==========================================================================
  1724. //
  1725. // PTR_PuzzleItemTraverse
  1726. //
  1727. //==========================================================================
  1728. #define USE_PUZZLE_ITEM_SPECIAL 129
  1729. static mobj_t *PuzzleItemUser;
  1730. static int PuzzleItemType;
  1731. static boolean PuzzleActivated;
  1732. boolean PTR_PuzzleItemTraverse(intercept_t *in)
  1733. {
  1734. mobj_t *mobj;
  1735. int sound;
  1736. if(in->isaline)
  1737. { // Check line
  1738. if(in->d.line->special != USE_PUZZLE_ITEM_SPECIAL)
  1739. {
  1740. P_LineOpening(in->d.line);
  1741. if(openrange <= 0)
  1742. {
  1743. sound = SFX_NONE;
  1744. if(PuzzleItemUser->player)
  1745. {
  1746. switch(PuzzleItemUser->player->class)
  1747. {
  1748. case PCLASS_FIGHTER:
  1749. sound = SFX_PUZZLE_FAIL_FIGHTER;
  1750. break;
  1751. case PCLASS_CLERIC:
  1752. sound = SFX_PUZZLE_FAIL_CLERIC;
  1753. break;
  1754. case PCLASS_MAGE:
  1755. sound = SFX_PUZZLE_FAIL_MAGE;
  1756. break;
  1757. default:
  1758. sound = SFX_NONE;
  1759. break;
  1760. }
  1761. }
  1762. S_StartSound(PuzzleItemUser, sound);
  1763. return false; // can't use through a wall
  1764. }
  1765. return true; // Continue searching
  1766. }
  1767. if(P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y,
  1768. in->d.line) == 1)
  1769. { // Don't use back sides
  1770. return false;
  1771. }
  1772. if(PuzzleItemType != in->d.line->arg1)
  1773. { // Item type doesn't match
  1774. return false;
  1775. }
  1776. P_StartACS(in->d.line->arg2, 0, &in->d.line->arg3,
  1777. PuzzleItemUser, in->d.line, 0);
  1778. in->d.line->special = 0;
  1779. PuzzleActivated = true;
  1780. return false; // Stop searching
  1781. }
  1782. // Check thing
  1783. mobj = in->d.thing;
  1784. if(mobj->special != USE_PUZZLE_ITEM_SPECIAL)
  1785. { // Wrong special
  1786. return true;
  1787. }
  1788. if(PuzzleItemType != mobj->args[0])
  1789. { // Item type doesn't match
  1790. return true;
  1791. }
  1792. P_StartACS(mobj->args[1], 0, &mobj->args[2], PuzzleItemUser, NULL, 0);
  1793. mobj->special = 0;
  1794. PuzzleActivated = true;
  1795. return false; // Stop searching
  1796. }
  1797. //==========================================================================
  1798. //
  1799. // P_UsePuzzleItem
  1800. //
  1801. // Returns true if the puzzle item was used on a line or a thing.
  1802. //
  1803. //==========================================================================
  1804. boolean P_UsePuzzleItem(player_t *player, int itemType)
  1805. {
  1806. int angle;
  1807. fixed_t x1, y1, x2, y2;
  1808. PuzzleItemType = itemType;
  1809. PuzzleItemUser = player->mo;
  1810. PuzzleActivated = false;
  1811. angle = player->mo->angle>>ANGLETOFINESHIFT;
  1812. x1 = player->mo->x;
  1813. y1 = player->mo->y;
  1814. x2 = x1+(USERANGE>>FRACBITS)*finecosine[angle];
  1815. y2 = y1+(USERANGE>>FRACBITS)*finesine[angle];
  1816. P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
  1817. PTR_PuzzleItemTraverse);
  1818. return PuzzleActivated;
  1819. }
  1820. /*
  1821. ==============================================================================
  1822. RADIUS ATTACK
  1823. ==============================================================================
  1824. */
  1825. mobj_t *bombsource;
  1826. mobj_t *bombspot;
  1827. int bombdamage;
  1828. int bombdistance;
  1829. boolean DamageSource;
  1830. /*
  1831. =================
  1832. =
  1833. = PIT_RadiusAttack
  1834. =
  1835. = Source is the creature that casued the explosion at spot
  1836. =================
  1837. */
  1838. boolean PIT_RadiusAttack (mobj_t *thing)
  1839. {
  1840. fixed_t dx, dy, dist;
  1841. int damage;
  1842. if(!(thing->flags&MF_SHOOTABLE))
  1843. {
  1844. return true;
  1845. }
  1846. // if(thing->flags2&MF2_BOSS)
  1847. // { // Bosses take no damage from PIT_RadiusAttack
  1848. // return(true);
  1849. // }
  1850. if(!DamageSource && thing == bombsource)
  1851. { // don't damage the source of the explosion
  1852. return true;
  1853. }
  1854. if(abs((thing->z-bombspot->z)>>FRACBITS) > 2*bombdistance)
  1855. { // too high/low
  1856. return true;
  1857. }
  1858. dx = abs(thing->x-bombspot->x);
  1859. dy = abs(thing->y-bombspot->y);
  1860. dist = dx > dy ? dx : dy;
  1861. dist = (dist-thing->radius)>>FRACBITS;
  1862. if(dist < 0)
  1863. {
  1864. dist = 0;
  1865. }
  1866. if(dist >= bombdistance)
  1867. { // Out of range
  1868. return true;
  1869. }
  1870. if(P_CheckSight(thing, bombspot))
  1871. { // OK to damage, target is in direct path
  1872. damage = (bombdamage*(bombdistance-dist)/bombdistance)+1;
  1873. if(thing->player)
  1874. {
  1875. damage >>= 2;
  1876. }
  1877. P_DamageMobj(thing, bombspot, bombsource, damage);
  1878. }
  1879. return(true);
  1880. }
  1881. /*
  1882. =================
  1883. =
  1884. = P_RadiusAttack
  1885. =
  1886. = Source is the creature that caused the explosion at spot
  1887. =================
  1888. */
  1889. void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int distance,
  1890. boolean damageSource)
  1891. {
  1892. int x,y, xl, xh, yl, yh;
  1893. fixed_t dist;
  1894. dist = (distance+MAXRADIUS)<<FRACBITS;
  1895. yh = (spot->y+dist-bmaporgy)>>MAPBLOCKSHIFT;
  1896. yl = (spot->y-dist-bmaporgy)>>MAPBLOCKSHIFT;
  1897. xh = (spot->x+dist-bmaporgx)>>MAPBLOCKSHIFT;
  1898. xl = (spot->x-dist-bmaporgx)>>MAPBLOCKSHIFT;
  1899. bombspot = spot;
  1900. bombsource = source;
  1901. bombdamage = damage;
  1902. bombdistance = distance;
  1903. DamageSource = damageSource;
  1904. for (y = yl; y <= yh; y++)
  1905. {
  1906. for (x = xl; x <= xh; x++)
  1907. {
  1908. P_BlockThingsIterator(x, y, PIT_RadiusAttack);
  1909. }
  1910. }
  1911. }
  1912. /*
  1913. ==============================================================================
  1914. SECTOR HEIGHT CHANGING
  1915. = After modifying a sectors floor or ceiling height, call this
  1916. = routine to adjust the positions of all things that touch the
  1917. = sector.
  1918. =
  1919. = If anything doesn't fit anymore, true will be returned.
  1920. = If crunch is true, they will take damage as they are being crushed
  1921. = If Crunch is false, you should set the sector height back the way it
  1922. = was and call P_ChangeSector again to undo the changes
  1923. ==============================================================================
  1924. */
  1925. int crushchange;
  1926. boolean nofit;
  1927. /*
  1928. ===============
  1929. =
  1930. = PIT_ChangeSector
  1931. =
  1932. ===============
  1933. */
  1934. boolean PIT_ChangeSector (mobj_t *thing)
  1935. {
  1936. mobj_t *mo;
  1937. if (P_ThingHeightClip (thing))
  1938. return true; // keep checking
  1939. // crunch bodies to giblets
  1940. if ((thing->flags&MF_CORPSE) && (thing->health <= 0))
  1941. {
  1942. if (thing->flags&MF_NOBLOOD)
  1943. {
  1944. P_RemoveMobj (thing);
  1945. }
  1946. else
  1947. {
  1948. if (thing->state != &states[S_GIBS1])
  1949. {
  1950. P_SetMobjState (thing, S_GIBS1);
  1951. thing->height = 0;
  1952. thing->radius = 0;
  1953. S_StartSound(thing, SFX_PLAYER_FALLING_SPLAT);
  1954. }
  1955. }
  1956. return true; // keep checking
  1957. }
  1958. // crunch dropped items
  1959. if (thing->flags2&MF2_DROPPED)
  1960. {
  1961. P_RemoveMobj (thing);
  1962. return true; // keep checking
  1963. }
  1964. if (! (thing->flags & MF_SHOOTABLE) )
  1965. return true; // assume it is bloody gibs or something
  1966. nofit = true;
  1967. if (crushchange && !(leveltime&3))
  1968. {
  1969. P_DamageMobj(thing, NULL, NULL, crushchange);
  1970. // spray blood in a random direction
  1971. if ((!(thing->flags&MF_NOBLOOD)) &&
  1972. (!(thing->flags2&MF2_INVULNERABLE)))
  1973. {
  1974. mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2,
  1975. MT_BLOOD);
  1976. mo->momx = (P_Random() - P_Random ())<<12;
  1977. mo->momy = (P_Random() - P_Random ())<<12;
  1978. }
  1979. }
  1980. return true; // keep checking (crush other things)
  1981. }
  1982. /*
  1983. ===============
  1984. =
  1985. = P_ChangeSector
  1986. =
  1987. ===============
  1988. */
  1989. boolean P_ChangeSector (sector_t *sector, int crunch)
  1990. {
  1991. int x,y;
  1992. nofit = false;
  1993. crushchange = crunch;
  1994. // recheck heights for all things near the moving sector
  1995. for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  1996. for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  1997. P_BlockThingsIterator (x, y, PIT_ChangeSector);
  1998. return nofit;
  1999. }