A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2207 lines 65 kB view raw
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 48static mobj_t *tmthing; 49static fixed_t tmx; 50static fixed_t tmy; 51static int pe_x; // Pain Elemental position for Lost Soul checks // phares 52static int pe_y; // Pain Elemental position for Lost Soul checks // phares 53static int ls_x; // Lost Soul position for Lost Soul checks // phares 54static 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 59boolean floatok; 60 61/* killough 11/98: if "felldown" true, object was pushed down ledge */ 62boolean felldown; 63 64// The tm* items are used to hold information globally, usually for 65// line or object intersection checking 66 67fixed_t tmbbox[4]; // bounding box for line intersection checks 68fixed_t tmfloorz; // floor you'd hit if free to fall 69fixed_t tmceilingz; // ceiling of sector you're in 70fixed_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 75line_t *ceilingline; 76line_t *blockline; /* killough 8/11/98: blocking linedef */ 77line_t *floorline; /* killough 8/1/98: Highest touched floor */ 78static 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 84line_t **spechit; // new code -- killough 85static int spechit_max; // killough 86 87int numspechit; 88 89// Temporary holder for thing_sectorlist threads 90msecnode_t* sector_list = NULL; // phares 3/16/98 91 92// 93// TELEPORT MOVE 94// 95 96// 97// PIT_StompThing 98// 99 100static boolean telefrag; /* killough 8/9/98: whether to telefrag at exit */ 101 102boolean 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 139int 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 180int 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 213boolean 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 305static // killough 3/26/98: make static 306boolean 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 324static 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 340static // killough 3/26/98: make static 341boolean 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 426static 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 584boolean 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 646boolean 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// 725boolean 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 836static 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 912void 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 963boolean 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 */ 1009static fixed_t bestslidefrac; 1010static fixed_t secondslidefrac; 1011static line_t* bestslideline; 1012static line_t* secondslideline; 1013static mobj_t* slidemo; 1014static fixed_t tmxmove; 1015static 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 1025void 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 1125boolean 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 1162isblocking: 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 1187void 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 1227stairstep: 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// 1296mobj_t* linetarget; // who got hit (or NULL) 1297static mobj_t* shootthing; 1298 1299/* killough 8/2/98: for more intelligent autoaiming */ 1300static uint_64_t aim_flags_mask; 1301 1302// Height if not aiming up or down 1303fixed_t shootz; 1304 1305int la_damage; 1306fixed_t attackrange; 1307 1308static 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 1313static fixed_t topslope; 1314static fixed_t bottomslope; 1315 1316 1317// 1318// PTR_AimTraverse 1319// Sets linetaget and aimslope when a target is aimed at. 1320// 1321boolean 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// 1414boolean 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// 1533fixed_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 1571void 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 1598mobj_t* usething; 1599 1600boolean 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 1645boolean 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// 1663void 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 1696static mobj_t *bombsource, *bombspot; 1697static int bombdamage; 1698 1699 1700// 1701// PIT_RadiusAttack 1702// "bombsource" is the creature 1703// that caused the explosion at "bombspot". 1704// 1705 1706boolean 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// 1756void 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 1798static boolean crushchange, nofit; 1799 1800// 1801// PIT_ChangeSector 1802// 1803 1804boolean 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// 1873boolean 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 1901boolean 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 1944IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone, sizeof(msecnode_t), PU_LEVEL, 32, "SecNodes"); 1945 1946inline 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 1953inline 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 1965msecnode_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 2010msecnode_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 2052void 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 2068boolean 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 2109void 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. */ 2201void P_MapStart(void) { 2202 if (tmthing) I_Error("P_MapStart: tmthing set!"); 2203} 2204void P_MapEnd(void) { 2205 tmthing = NULL; 2206} 2207