p_move.c (15996B)
1 #include "doomdef.h" 2 #include "p_local.h" 3 4 /*================== */ 5 /* */ 6 /* out */ 7 /* */ 8 /*================== */ 9 10 extern mobj_t *tmthing; // 800A56B0 11 extern fixed_t tmx, tmy; // 800A56B4, 800A56B8 12 extern boolean checkposonly; // 800A56C8 13 14 /*================== */ 15 /* */ 16 /* in */ 17 /* */ 18 /*================== */ 19 20 boolean trymove2; // 800A5D80 /* Result from P_TryMove2 */ 21 boolean floatok; // 800A5D84 /* if true, move would be ok if within tmfloorz - tmceilingz */ 22 fixed_t tmfloorz; // 800A5D88 /* Current floor z for P_TryMove2 */ 23 fixed_t tmceilingz; // 800A5D8C /* Current ceiling z for P_TryMove2 */ 24 mobj_t *movething; // 800A5D98 /* Either a skull/missile target or a special pickup */ 25 line_t *blockline; // 800A5D9C /* Might be a door that can be opened */ 26 27 fixed_t oldx, oldy; // 800A5DA0, 800A5DA4 28 fixed_t tmbbox[4]; // 29 int tmflags; // 800A5DB8 30 fixed_t tmdropoffz; // 800A5D90 /* Lowest point contacted */ 31 subsector_t *newsubsec; // 800A5D94 /* Dest subsector */ 32 33 //PSX NEW 34 line_t *thingspec[8]; // 800A5DE0 35 int numthingspec; // 800A5DE0 36 37 /* 38 =================== 39 = 40 = P_TryMove2 41 = 42 = Attempt to move to a new position, crossing special lines unless MF_TELEPORT 43 = is set 44 = 45 =================== 46 */ 47 48 void P_TryMove2(void) // 80019980 49 { 50 int side; 51 int oldside; 52 line_t *line; 53 54 trymove2 = false; // until proven otherwise 55 floatok = false; 56 57 oldx = tmthing->x; 58 oldy = tmthing->y; 59 60 PM_CheckPosition(); 61 62 if (checkposonly) 63 { 64 checkposonly = false; 65 return; 66 } 67 68 if (!trymove2) 69 return; 70 71 if (!(tmthing->flags & MF_NOCLIP)) 72 { 73 trymove2 = false; 74 75 if (tmceilingz - tmfloorz < tmthing->height) 76 return; // doesn't fit 77 floatok = true; 78 if ( !(tmthing->flags&MF_TELEPORT) && tmceilingz - tmthing->z < tmthing->height) 79 return; // mobj must lower itself to fit 80 if ( !(tmthing->flags&MF_TELEPORT) && tmfloorz - tmthing->z > 24*FRACUNIT ) 81 return; // too big a step up 82 if ( !(tmthing->flags&(MF_DROPOFF|MF_FLOAT)) && tmfloorz - tmdropoffz > 24*FRACUNIT ) 83 return; // don't stand over a dropoff 84 } 85 86 // 87 // the move is ok, so link the thing into its new position 88 // 89 P_UnsetThingPosition(tmthing); 90 91 tmthing->floorz = tmfloorz; 92 tmthing->ceilingz = tmceilingz; 93 tmthing->x = tmx; 94 tmthing->y = tmy; 95 96 P_SetThingPosition(tmthing); 97 98 if (!(tmthing->flags & (MF_NOCLIP | MF_TELEPORT))) 99 { 100 while (numthingspec > 0) 101 { 102 numthingspec--; 103 line = thingspec[numthingspec]; 104 105 side = P_PointOnLineSide(tmthing->x, tmthing->y, line); 106 oldside = P_PointOnLineSide(oldx, oldy, line); 107 108 if (side != oldside) 109 { 110 if (!(line->flags & ML_TRIGGERFRONT) || (side)) 111 { 112 P_UseSpecialLine(line, tmthing); 113 } 114 } 115 } 116 } 117 118 trymove2 = true; 119 120 return; 121 } 122 123 /* 124 ================== 125 = 126 = P_PointOnLineSide 127 = 128 = Returns 0 or 1 129 ================== 130 */ 131 132 int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line) // 80019C24 133 { 134 fixed_t dx,dy; 135 fixed_t left, right; 136 137 if (!line->dx) 138 { 139 if (x <= line->v1->x) 140 return line->dy > 0; 141 return line->dy < 0; 142 } 143 if (!line->dy) 144 { 145 if (y <= line->v1->y) 146 return line->dx < 0; 147 return line->dx > 0; 148 } 149 150 dx = (x - line->v1->x); 151 dy = (y - line->v1->y); 152 153 left = (line->dy>>16) * (dx>>16); 154 right = (dy>>16) * (line->dx>>16); 155 156 if (right < left) 157 return 0; /* front side */ 158 return 1; /* back side */ 159 } 160 161 #if 0 162 static boolean PM_CrossCheck(line_t *ld) 163 { 164 if (PM_BoxCrossLine (ld)) { 165 if (!PIT_CheckLine(ld)) { 166 return true; 167 } 168 } 169 return false; 170 } 171 172 /* 173 ================== 174 = 175 = PM_PointOnLineSide 176 = Exclusive Psx Doom 177 = 178 = Returns 0 or 1 179 = 180 ================== 181 */ 182 183 int PM_PointOnLineSide(fixed_t x, fixed_t y, line_t *line)//L8001EB8C() 184 { 185 fixed_t dx, dy; 186 fixed_t left, right; 187 188 dx = (x - line->v1->x); 189 dy = (y - line->v1->y); 190 191 left = (line->dy >> 16) * (dx >> 16); 192 right = (dy >> 16) *(line->dx >> 16); 193 194 if (right < left) 195 return 0; /* front side */ 196 return 1; /* back side */ 197 } 198 #endif 199 200 /* 201 =============================================================================== 202 203 THING POSITION SETTING 204 205 =============================================================================== 206 */ 207 208 /* 209 =================== 210 = 211 = P_UnsetThingPosition 212 = 213 = Unlinks a thing from block map and sectors 214 = 215 =================== 216 */ 217 218 void P_UnsetThingPosition (mobj_t *thing)//L8001C768() 219 { 220 int blockx, blocky; 221 222 if (!(thing->flags & MF_NOSECTOR)) 223 { /* inert things don't need to be in blockmap */ 224 /* unlink from subsector */ 225 if (thing->snext) 226 thing->snext->sprev = thing->sprev; 227 if (thing->sprev) 228 thing->sprev->snext = thing->snext; 229 else 230 thing->subsector->sector->thinglist = thing->snext; 231 } 232 233 if (!(thing->flags & MF_NOBLOCKMAP)) 234 { /* inert things don't need to be in blockmap */ 235 /* unlink from block map */ 236 if (thing->bnext) 237 thing->bnext->bprev = thing->bprev; 238 if (thing->bprev) 239 thing->bprev->bnext = thing->bnext; 240 else 241 { 242 blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; 243 blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; 244 245 // Prevent buffer overflow if the map object is out of bounds. 246 // This is part of the fix for the famous 'linedef deletion' bug. 247 // From PsyDoom (StationDoom) by BodbDearg 248 #if FIX_LINEDEFS_DELETION == 1 249 if (blockx>=0 && blockx <bmapwidth 250 && blocky>=0 && blocky <bmapheight) 251 { 252 blocklinks[blocky*bmapwidth+blockx] = thing->bnext; 253 } 254 #else 255 blocklinks[blocky*bmapwidth+blockx] = thing->bnext; 256 #endif 257 } 258 } 259 } 260 261 262 /* 263 =================== 264 = 265 = P_SetThingPosition 266 = 267 = Links a thing into both a block and a subsector based on it's x y 268 = Sets thing->subsector properly 269 = 270 =================== 271 */ 272 273 void P_SetThingPosition (mobj_t *thing) // 80019E20 274 { 275 subsector_t *ss; 276 sector_t *sec; 277 int blockx, blocky; 278 mobj_t **link; 279 280 /* */ 281 /* link into subsector */ 282 /* */ 283 ss = R_PointInSubsector (thing->x,thing->y); 284 thing->subsector = ss; 285 if(!(thing->flags & MF_NOSECTOR)) 286 { 287 /* invisible things don't go into the sector links */ 288 sec = ss->sector; 289 290 thing->sprev = NULL; 291 thing->snext = sec->thinglist; 292 if(sec->thinglist) 293 sec->thinglist->sprev = thing; 294 sec->thinglist = thing; 295 } 296 297 /* */ 298 /* link into blockmap */ 299 /* */ 300 if(!(thing->flags & MF_NOBLOCKMAP)) 301 { 302 /* inert things don't need to be in blockmap */ 303 blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; 304 blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; 305 if(blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight) 306 { 307 link = &blocklinks[blocky*bmapwidth+blockx]; 308 thing->bprev = NULL; 309 thing->bnext = *link; 310 if (*link) 311 (*link)->bprev = thing; 312 *link = thing; 313 } 314 else 315 { 316 /* thing is off the map */ 317 thing->bnext = thing->bprev = NULL; 318 } 319 } 320 } 321 322 /* 323 ================== 324 = 325 = PM_CheckPosition 326 = 327 = This is purely informative, nothing is modified (except things picked up) 328 329 in: 330 tmthing a mobj_t (can be valid or invalid) 331 tmx,tmy a position to be checked (doesn't need relate to the mobj_t->x,y) 332 333 out: 334 335 newsubsec 336 floorz 337 ceilingz 338 tmdropoffz the lowest point contacted (monsters won't move to a dropoff) 339 movething 340 341 ================== 342 */ 343 344 void PM_CheckPosition (void) // 80019F50 345 { 346 int xl,xh,yl,yh,bx,by; 347 348 tmflags = tmthing->flags; 349 350 tmbbox[BOXTOP] = tmy + tmthing->radius; 351 tmbbox[BOXBOTTOM] = tmy - tmthing->radius; 352 tmbbox[BOXRIGHT] = tmx + tmthing->radius; 353 tmbbox[BOXLEFT] = tmx - tmthing->radius; 354 355 newsubsec = R_PointInSubsector(tmx,tmy); 356 357 // 358 // the base floor / ceiling is from the subsector that contains the 359 // point. Any contacted lines the step closer together will adjust them 360 // 361 tmfloorz = tmdropoffz = newsubsec->sector->floorheight; 362 tmceilingz = newsubsec->sector->ceilingheight; 363 364 ++validcount; 365 366 numthingspec = 0;//PSX 367 movething = NULL; 368 blockline = NULL; 369 370 if (tmflags & MF_NOCLIP) 371 { 372 trymove2 = true; 373 return; 374 } 375 376 // 377 // check things first, possibly picking things up 378 // the bounding box is extended by MAXRADIUS because mobj_ts are grouped 379 // into mapblocks based on their origin point, and can overlap into adjacent 380 // blocks by up to MAXRADIUS units 381 // 382 // [D64] no use MAXRADIUS 383 // 384 xl = (tmbbox[BOXLEFT] - bmaporgx/* - MAXRADIUS*/)>>MAPBLOCKSHIFT; 385 xh = (tmbbox[BOXRIGHT] - bmaporgx/* + MAXRADIUS*/)>>MAPBLOCKSHIFT; 386 yl = (tmbbox[BOXBOTTOM] - bmaporgy/* - MAXRADIUS*/)>>MAPBLOCKSHIFT; 387 yh = (tmbbox[BOXTOP] - bmaporgy/* + MAXRADIUS*/)>>MAPBLOCKSHIFT; 388 389 if (xl<0) 390 xl = 0; 391 if (yl<0) 392 yl = 0; 393 if (xh>= bmapwidth) 394 xh = bmapwidth -1; 395 if (yh>= bmapheight) 396 yh = bmapheight -1; 397 398 for (bx = xl; bx <= xh; bx++) 399 { 400 for (by = yl; by <= yh; by++) 401 { 402 if (!PM_BlockThingsIterator(bx, by)) 403 { 404 trymove2 = false; 405 return; 406 } 407 } 408 } 409 410 // 411 // check lines 412 // 413 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; 414 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; 415 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; 416 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; 417 418 if (xl<0) 419 xl = 0; 420 if (yl<0) 421 yl = 0; 422 if (xh>= bmapwidth) 423 xh = bmapwidth -1; 424 if (yh>= bmapheight) 425 yh = bmapheight -1; 426 427 for (bx = xl; bx <= xh; bx++) 428 { 429 for (by = yl; by <= yh; by++) 430 { 431 if (!PM_BlockLinesIterator(bx, by)) 432 { 433 trymove2 = false; 434 return; 435 } 436 } 437 } 438 439 trymove2 = true; 440 return; 441 } 442 443 //============================================================================= 444 445 446 /* 447 ================= 448 = 449 = PM_BoxCrossLine 450 = 451 ================= 452 */ 453 boolean PM_BoxCrossLine (line_t *ld) // 8001A280 454 { 455 boolean side1, side2; 456 457 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] 458 || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] 459 || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] 460 || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) 461 return false; 462 463 switch(ld->slopetype) 464 { 465 case ST_HORIZONTAL: 466 side1 = (ld->bbox[BOXTOP] < tmbbox[BOXTOP]); 467 side2 = (ld->bbox[BOXTOP] < tmbbox[BOXBOTTOM]); 468 break; 469 470 case ST_VERTICAL: 471 side1 = (ld->bbox[BOXLEFT] < tmbbox[BOXRIGHT]); 472 side2 = (ld->bbox[BOXLEFT] < tmbbox[BOXLEFT]); 473 break; 474 475 case ST_POSITIVE: 476 side1 = P_PointOnLineSide(tmbbox[BOXLEFT], tmbbox[BOXTOP], ld); 477 side2 = P_PointOnLineSide(tmbbox[BOXRIGHT], tmbbox[BOXBOTTOM], ld); 478 break; 479 480 case ST_NEGATIVE: 481 side1 = P_PointOnLineSide(tmbbox[BOXRIGHT], tmbbox[BOXTOP], ld); 482 side2 = P_PointOnLineSide(tmbbox[BOXLEFT], tmbbox[BOXBOTTOM], ld); 483 break; 484 485 default: 486 break; 487 } 488 489 return (0 < (side1 ^ side2)); 490 } 491 492 //============================================================================= 493 494 495 /* 496 ================== 497 = 498 = PIT_CheckLine 499 = 500 = Adjusts tmfloorz and tmceilingz as lines are contacted 501 ================== 502 */ 503 504 boolean PIT_CheckLine (line_t *ld) // 8001A3DC 505 { 506 fixed_t pm_opentop, pm_openbottom; 507 fixed_t pm_lowfloor; 508 sector_t *front, *back; 509 510 // a line has been hit 511 512 /* 513 = 514 = The moving thing's destination position will cross the given line. 515 = If this should not be allowed, return false. 516 */ 517 if (!ld->backsector) 518 return false; // one sided line 519 520 if (!(tmthing->flags & MF_MISSILE) ) 521 { 522 if ( ld->flags & ML_BLOCKING ) 523 return false; // explicitly blocking everything 524 if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS ) 525 return false; // block monsters only 526 } 527 528 front = ld->frontsector; 529 back = ld->backsector; 530 531 if (front->ceilingheight == front->floorheight 532 || back->ceilingheight == back->floorheight) 533 { 534 blockline = ld; 535 return false; // probably a closed door 536 } 537 538 if (front->ceilingheight < back->ceilingheight) 539 pm_opentop = front->ceilingheight; 540 else 541 pm_opentop = back->ceilingheight; 542 543 if (front->floorheight > back->floorheight) 544 { 545 pm_openbottom = front->floorheight; 546 pm_lowfloor = back->floorheight; 547 } 548 else 549 { 550 pm_openbottom = back->floorheight; 551 pm_lowfloor = front->floorheight; 552 } 553 554 // adjust floor / ceiling heights 555 if (pm_opentop < tmceilingz) 556 tmceilingz = pm_opentop; 557 if (pm_openbottom > tmfloorz) 558 tmfloorz = pm_openbottom; 559 if (pm_lowfloor < tmdropoffz) 560 tmdropoffz = pm_lowfloor; 561 562 // if contacted a special line, add it to the list 563 if(ld->special & MLU_CROSS) 564 { 565 //New Psx Doom 566 if (numthingspec < MAXTHINGSPEC) 567 { 568 thingspec[numthingspec] = ld; 569 numthingspec++; 570 } 571 } 572 573 return true; 574 } 575 576 /* 577 ================== 578 = 579 = PIT_CheckThing 580 = 581 ================== 582 */ 583 584 boolean PIT_CheckThing(mobj_t *thing) // 8001A560 585 { 586 fixed_t blockdist; 587 fixed_t x, y; 588 fixed_t rx, ry; 589 590 if (thing == tmthing) 591 return true; // don't clip against self 592 593 if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) )) 594 return true; 595 596 blockdist = thing->radius + tmthing->radius; 597 598 /*delta = thing->x - tmx; 599 if (delta < 0) 600 delta = -delta; 601 if (delta >= blockdist) 602 return true; // didn't hit it 603 604 delta = thing->y - tmy; 605 if (delta < 0) 606 delta = -delta; 607 if (delta >= blockdist) 608 return true; // didn't hit it 609 610 if (thing == tmthing) 611 return true; // don't clip against self*/ 612 613 // [d64]: different logic versus Jaguar Doom 614 x = abs(thing->x - tmx); 615 y = abs(thing->y - tmy); 616 617 rx = blockdist - x; 618 ry = blockdist - x; 619 620 if(!(x < y)) 621 { 622 if(((rx - y) + (y >> 1)) <= 0) 623 return true; // didn't hit it 624 } 625 else 626 { 627 if(((ry - y) + (x >> 1)) <= 0) 628 return true; // didn't hit it 629 } 630 631 // 632 // check for skulls slamming into things 633 // 634 if (tmthing->flags & MF_SKULLFLY) 635 { 636 movething = thing; 637 return false; // stop moving 638 } 639 640 // 641 // missiles can hit other things 642 // 643 if (tmthing->flags & MF_MISSILE) 644 { 645 // see if it went over / under 646 if (tmthing->z > thing->z + thing->height) 647 return true; // overhead 648 if (tmthing->z+tmthing->height < thing->z) 649 return true; // underneath 650 if (tmthing->target->type == thing->type) // don't hit same species as originator 651 { 652 if (thing == tmthing->target) 653 return true; 654 if (thing->type != MT_PLAYER) // let players missile other players 655 return false; // explode, but do no damage 656 } 657 if (! (thing->flags & MF_SHOOTABLE) ) 658 return !(thing->flags & MF_SOLID); // didn't do any damage 659 660 // damage / explode 661 movething = thing; 662 return false; // don't traverse any more 663 } 664 665 // 666 // check for special pickup 667 // 668 if ((thing->flags&MF_SPECIAL) && (tmflags&MF_PICKUP) ) 669 { 670 movething = thing; 671 return true; 672 } 673 674 return !(thing->flags & MF_SOLID); 675 } 676 677 /* 678 =============================================================================== 679 680 BLOCK MAP ITERATORS 681 682 For each line/thing in the given mapblock, call the passed function. 683 If the function returns false, exit with false without checking anything else. 684 685 =============================================================================== 686 */ 687 688 /* 689 ================== 690 = 691 = PM_BlockLinesIterator 692 = Exclusive Psx Doom / Doom 64 693 = 694 = The validcount flags are used to avoid checking lines 695 = that are marked in multiple mapblocks, so increment validcount before 696 = the first call to PM_BlockLinesIterator, then make one or more calls to it 697 = 698 ================== 699 */ 700 701 boolean PM_BlockLinesIterator(int x, int y) // 8001A710 702 { 703 int offset; 704 short *list; 705 line_t *ld; 706 707 offset = (y*bmapwidth)+x; 708 offset = *(blockmap + offset); 709 710 for (list = blockmaplump + offset; *list != -1; list++) 711 { 712 ld = &lines[*list]; 713 if (ld->validcount == validcount) 714 continue; /* line has already been checked */ 715 ld->validcount = validcount; 716 717 if (PM_BoxCrossLine(ld)) 718 { 719 if (!PIT_CheckLine(ld)) 720 return false; 721 } 722 } 723 724 return true; /* everything was checked */ 725 } 726 727 /* 728 ================== 729 = 730 = PM_BlockThingsIterator 731 = Exclusive Psx Doom / Doom 64 732 = 733 ================== 734 */ 735 736 boolean PM_BlockThingsIterator(int x, int y) // 8001A810 737 { 738 mobj_t *mobj; 739 740 for (mobj = blocklinks[y * bmapwidth + x]; mobj; mobj = mobj->bnext) 741 { 742 if (!PIT_CheckThing(mobj)) 743 return false; 744 } 745 746 return true; 747 }