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