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