p_base.c (17188B)
1 /* p_base.c */ 2 3 #include "doomdef.h" 4 #include "p_local.h" 5 6 //completo y revisado 7 8 mobj_t *checkthing; /* Used for PB_CheckThing */ // 800A55D0 9 fixed_t testx, testy; // 800A55D8, 800A55DC 10 static fixed_t testfloorz, testceilingz, testdropoffz; // 800A5604, 800A5608, 800A560C 11 static subsector_t *testsubsec; // 800A55F8 12 static line_t *ceilingline; // 800A5600 13 static mobj_t *hitthing; // 800A55fC 14 static fixed_t testbbox[4]; /* Bounding box for tests */ // 800A55E8 15 int testflags; // 800A55D4 16 fixed_t testradius; // 800A55E0 17 18 void P_XYMovement(mobj_t *mo); 19 void P_FloatChange(mobj_t *mo); 20 void P_ZMovement(mobj_t *mo); 21 void P_MobjThinker(mobj_t *mobj); 22 boolean PB_TryMove(int tryx, int tryy); 23 void PB_UnsetThingPosition(mobj_t *thing); 24 void PB_SetThingPosition(mobj_t *thing); 25 boolean PB_CheckPosition(void); 26 boolean PB_BoxCrossLine(line_t *ld); 27 boolean PB_CheckLine(line_t *ld); 28 boolean PB_CheckThing(mobj_t *thing); 29 boolean PB_BlockLinesIterator(int x, int y); 30 boolean PB_BlockThingsIterator(int x, int y); 31 32 /* 33 ================= 34 = 35 = P_RunMobjBase 36 = 37 = Execute base think logic for the critters every tic 38 = 39 ================= 40 */ 41 42 void P_RunMobjBase(void) // 8000CDE0 43 { 44 mobj_t *mo; 45 mobj_t *next; 46 47 for (mo = mobjhead.next; mo != &mobjhead; mo = mo->next) 48 { 49 /* Based on Doom 64 Ex */ 50 /*-----------------------------------------------------------------------------------*/ 51 if((players[0].cheats & CF_LOCKMOSTERS) && !mo->player && mo->flags & MF_COUNTKILL) { 52 continue; 53 } 54 /*-----------------------------------------------------------------------------------*/ 55 56 if (!mo->player) 57 { 58 mo->latecall = NULL; 59 P_MobjThinker(mo); 60 } 61 } 62 63 //P_RunMobjLate(); 64 for (mo = mobjhead.next; mo != &mobjhead; mo = next) 65 { 66 next = mo->next; /* in case mo is removed this time */ 67 68 /* Based on Doom 64 Ex */ 69 /*-----------------------------------------------------------------------------------*/ 70 if((players[0].cheats & CF_LOCKMOSTERS) && !mo->player && mo->flags & MF_COUNTKILL) { 71 continue; 72 } 73 /*-----------------------------------------------------------------------------------*/ 74 75 if(mo->latecall) 76 { 77 mo->latecall(mo); 78 } 79 } 80 } 81 82 /* 83 =================== 84 = 85 = P_MobjThinker 86 = 87 = Process all the critter logic 88 = 89 =================== 90 */ 91 92 void P_MobjThinker(mobj_t *mobj) // 8000CE74 93 { 94 state_t *st; 95 statenum_t state; 96 97 checkthing = mobj; 98 99 // momentum movement 100 if (mobj->momx || mobj->momy) 101 { 102 P_XYMovement(mobj); 103 104 // removed or has a special action to perform? 105 if (mobj->latecall) 106 return; 107 } 108 109 if (mobj->z != mobj->floorz || mobj->momz) 110 { 111 P_ZMovement(mobj); 112 113 // removed or has a special action to perform? 114 if (mobj->latecall) 115 return; 116 } 117 118 // cycle through states 119 if (mobj->tics != -1) 120 { 121 mobj->tics--; 122 123 // you can cycle through multiple states in a tic 124 if (mobj->tics <= 0) 125 { 126 state = mobj->state->nextstate; 127 if (state == S_000) 128 { 129 mobj->latecall = P_RemoveMobj; 130 } 131 else 132 { 133 st = &states[state]; 134 mobj->state = st; 135 mobj->tics = st->tics; 136 mobj->sprite = st->sprite; 137 mobj->frame = st->frame; 138 mobj->latecall = st->action; 139 } 140 } 141 } 142 } 143 144 145 /* 146 =================== 147 = 148 = P_XYMovement 149 = 150 =================== 151 */ 152 153 #define STOPSPEED 0x1000 154 #define FRICTION 0xd200 //Jag 0xd240 155 156 void P_XYMovement(mobj_t *mo) // 8000CF98 157 { 158 fixed_t xleft, yleft; 159 fixed_t xuse, yuse; 160 161 // 162 // cut the move into chunks if too large 163 // 164 165 xleft = xuse = mo->momx & ~7; 166 yleft = yuse = mo->momy & ~7; 167 168 while (xuse > MAXMOVE || xuse < -MAXMOVE 169 || yuse > MAXMOVE || yuse < -MAXMOVE) 170 { 171 xuse >>= 1; 172 yuse >>= 1; 173 } 174 175 while (xleft || yleft) 176 { 177 xleft -= xuse; 178 yleft -= yuse; 179 if (!PB_TryMove(mo->x + xuse, mo->y + yuse)) 180 { 181 // blocked move 182 if (mo->flags & MF_SKULLFLY) 183 { 184 mo->latecall = L_SkullBash; 185 mo->extradata = (mobj_t*)hitthing; 186 } 187 188 // explode a missile 189 if (mo->flags & MF_MISSILE) 190 { 191 if(hitthing == NULL && ceilingline) 192 { 193 if ((ceilingline->backsector && (ceilingline->backsector->ceilingpic == -1)) || 194 ((ceilingline->backsector == NULL) && (sides[ceilingline->sidenum[0]].midtexture == 1))) // hack to prevent missiles exploding against the sky 195 { 196 mo->latecall = P_RemoveMobj; 197 return; 198 } 199 } 200 201 mo->latecall = L_MissileHit; 202 mo->extradata = (mobj_t*)hitthing; 203 return; 204 } 205 206 mo->momx = mo->momy = 0; 207 return; 208 } 209 } 210 211 // 212 // slow down 213 // 214 if (mo->flags & (MF_MISSILE | MF_SKULLFLY)) 215 return; // no friction for missiles ever 216 217 if (mo->z > mo->floorz) 218 return; // no friction when airborne 219 220 if ((mo->flags & MF_CORPSE) && (mo->floorz != mo->subsector->sector->floorheight)) 221 return; // don't stop halfway off a step 222 223 if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && 224 mo->momy > -STOPSPEED && mo->momy < STOPSPEED) 225 { 226 mo->momx = 0; 227 mo->momy = 0; 228 } 229 else 230 { 231 mo->momx = (mo->momx >> 8) * (FRICTION >> 8); 232 mo->momy = (mo->momy >> 8) * (FRICTION >> 8); 233 } 234 } 235 236 /* 237 =================== 238 = 239 = P_FloatChange 240 = 241 = Float up or down at a set speed, used by flying monsters 242 = 243 =================== 244 */ 245 246 void P_FloatChange(mobj_t *mo) // inline function 247 { 248 mobj_t *target; 249 fixed_t dist, delta; 250 251 target = mo->target; /* Get the target object */ 252 253 dist = P_AproxDistance(target->x - mo->x, target->y - mo->y); /* Distance to target */ 254 255 delta = (target->z + (mo->height >> 1)) - mo->z; /* Get the height differance */ 256 delta *= 3; /* Mul by 3 for a fudge factor */ 257 258 if (delta<0) /* Delta is signed... */ 259 { 260 if (dist < (-delta)) /* Negate */ 261 { 262 mo->z -= FLOATSPEED; /* Adjust the height */ 263 } 264 } 265 else if (delta>0) /* Delta is signed... */ 266 { 267 if (dist < delta) /* Normal compare */ 268 { 269 mo->z += FLOATSPEED; /* Adjust the height */ 270 } 271 } 272 } 273 274 /* 275 =================== 276 = 277 = P_ZMovement 278 = 279 = Move a critter in the Z axis 280 = 281 =================== 282 */ 283 284 void P_ZMovement(mobj_t *mo) // 8000D228 285 { 286 287 mo->z += mo->momz; /* Basic z motion */ 288 289 if ((mo->flags & MF_FLOAT) && mo->target) /* float down towards target if too close */ 290 { 291 P_FloatChange(mo); 292 } 293 294 // 295 // clip movement 296 // 297 if (mo->z <= mo->floorz) // hit the floor 298 { 299 if (mo->momz < 0) 300 mo->momz = 0; 301 302 mo->z = mo->floorz; 303 if ((mo->flags & MF_MISSILE) && (mo->type != MT_PROJ_RECTFIRE)) 304 { 305 mo->latecall = P_ExplodeMissile; 306 return; 307 } 308 } 309 else if (mo->flags & MF_GRAVITY) 310 { 311 // apply gravity 312 if (mo->momz == 0) 313 mo->momz = -(GRAVITY/2); 314 else 315 mo->momz -= ((GRAVITY/FRACBITS)*3); // [d64]: non-players fall slightly slower 316 } 317 318 if (mo->z + mo->height > mo->ceilingz) // hit the ceiling 319 { 320 if (mo->momz > 0) 321 mo->momz = 0; 322 323 mo->z = mo->ceilingz - mo->height; 324 if (mo->flags & MF_MISSILE) 325 mo->latecall = P_ExplodeMissile; 326 } 327 } 328 329 /* 330 =================== 331 = 332 = PB_TryMove 333 = 334 = Attempt to move to a new position 335 = 336 =================== 337 */ 338 339 boolean PB_TryMove(int tryx, int tryy) // 8000D3F4 340 { 341 testradius = checkthing->radius; 342 testflags = checkthing->flags; 343 testx = tryx; 344 testy = tryy; 345 346 if (!PB_CheckPosition()) 347 return false; // solid wall or thing 348 349 if (testceilingz - testfloorz < checkthing->height) 350 return false; // doesn't fit 351 if (testceilingz - checkthing->z < checkthing->height) 352 return false; // mobj must lower itself to fit 353 if (testfloorz - checkthing->z > 24 * FRACUNIT) 354 return false; // too big a step up 355 if (!(testflags&(MF_DROPOFF | MF_FLOAT)) && testfloorz - testdropoffz > 24 * FRACUNIT) 356 return false; // don't stand over a dropoff 357 358 // 359 // the move is ok, so link the thing into its new position 360 // 361 362 PB_UnsetThingPosition(checkthing); 363 checkthing->floorz = testfloorz; 364 checkthing->ceilingz = testceilingz; 365 checkthing->x = tryx; 366 checkthing->y = tryy; 367 PB_SetThingPosition(checkthing); 368 return true; 369 } 370 371 /* 372 =================== 373 = 374 = PB_UnsetThingPosition 375 = 376 =================== 377 */ 378 379 void PB_UnsetThingPosition(mobj_t *thing) // 8000D55C 380 { 381 int blockx, blocky; 382 383 // inert things don't need to be in blockmap 384 // unlink from subsector 385 if (thing->snext) 386 thing->snext->sprev = thing->sprev; 387 if (thing->sprev) 388 thing->sprev->snext = thing->snext; 389 else 390 thing->subsector->sector->thinglist = thing->snext; 391 392 if (!(testflags & MF_NOBLOCKMAP)) 393 { 394 // inert things don't need to be in blockmap 395 // unlink from block map 396 if (thing->bnext) 397 thing->bnext->bprev = thing->bprev; 398 if (thing->bprev) 399 thing->bprev->bnext = thing->bnext; 400 else 401 { 402 blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT; 403 blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT; 404 405 // Prevent buffer overflow if the map object is out of bounds. 406 // This is part of the fix for the famous 'linedef deletion' bug. 407 // From PsyDoom (StationDoom) by BodbDearg 408 #if FIX_LINEDEFS_DELETION == 1 409 if (blockx>=0 && blockx <bmapwidth 410 && blocky>=0 && blocky <bmapheight) 411 { 412 blocklinks[blocky*bmapwidth+blockx] = thing->bnext; 413 } 414 #else 415 blocklinks[blocky*bmapwidth+blockx] = thing->bnext; 416 #endif 417 } 418 } 419 } 420 421 /* 422 =================== 423 = 424 = PB_SetThingPosition 425 = 426 =================== 427 */ 428 429 void PB_SetThingPosition(mobj_t *thing) // 8000D650 430 { 431 sector_t *sec; 432 int blockx, blocky; 433 mobj_t **link; 434 435 // 436 // link into subsector 437 // 438 439 thing->subsector = testsubsec; 440 sec = thing->subsector->sector; 441 442 thing->sprev = NULL; 443 thing->snext = sec->thinglist; 444 445 if (sec->thinglist) 446 sec->thinglist->sprev = thing; 447 448 sec->thinglist = thing; 449 450 // 451 // link into blockmap 452 // 453 if (!(testflags & MF_NOBLOCKMAP)) 454 { 455 // inert things don't need to be in blockmap 456 blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT; 457 blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT; 458 if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight) 459 { 460 link = &blocklinks[blocky*bmapwidth + blockx]; 461 thing->bprev = NULL; 462 thing->bnext = *link; 463 if (*link) 464 (*link)->bprev = thing; 465 *link = thing; 466 } 467 else 468 { 469 // thing is off the map 470 thing->bnext = thing->bprev = NULL; 471 } 472 } 473 } 474 475 /* 476 ================== 477 = 478 = PB_CheckPosition 479 = 480 = This is purely informative, nothing is modified (except things picked up) 481 482 in: 483 basething a mobj_t 484 testx,testy a position to be checked (doesn't need relate to the mobj_t->x,y) 485 486 out: 487 488 testsubsec 489 floorz 490 ceilingz 491 testdropoffz the lowest point contacted (monsters won't move to a dropoff) 492 hitthing 493 494 ================== 495 */ 496 497 boolean PB_CheckPosition(void) // 8000D750 498 { 499 int xl, xh, yl, yh, bx, by; 500 501 testbbox[BOXTOP ] = testy + testradius; 502 testbbox[BOXBOTTOM] = testy - testradius; 503 testbbox[BOXRIGHT ] = testx + testradius; 504 testbbox[BOXLEFT ] = testx - testradius; 505 506 // 507 // the base floor / ceiling is from the subsector that contains the 508 // point. Any contacted lines the step closer together will adjust them 509 // 510 testsubsec = R_PointInSubsector(testx, testy); 511 testfloorz = testdropoffz = testsubsec->sector->floorheight; 512 testceilingz = testsubsec->sector->ceilingheight; 513 514 ++validcount; 515 516 ceilingline = NULL; 517 hitthing = NULL; 518 519 // 520 // the bounding box is extended by MAXRADIUS because mobj_ts are grouped 521 // into mapblocks based on their origin point, and can overlap into adjacent 522 // blocks by up to MAXRADIUS units 523 // 524 525 // [d64]: intentionally removed MAXRADIUS? 526 xl = (testbbox[BOXLEFT ] - bmaporgx) >> MAPBLOCKSHIFT; 527 xh = (testbbox[BOXRIGHT ] - bmaporgx) >> MAPBLOCKSHIFT; 528 yl = (testbbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT; 529 yh = (testbbox[BOXTOP ] - bmaporgy) >> MAPBLOCKSHIFT; 530 531 if (xl<0) 532 { 533 xl = 0; 534 } 535 if (yl<0) 536 { 537 yl = 0; 538 } 539 if (xh >= bmapwidth) 540 { 541 xh = bmapwidth - 1; 542 } 543 if (yh >= bmapheight) 544 { 545 yh = bmapheight - 1; 546 } 547 548 for (bx = xl; bx <= xh; bx++) 549 { 550 for (by = yl; by <= yh; by++) 551 { 552 if (!PB_BlockLinesIterator(bx, by)) 553 return false; 554 if (!PB_BlockThingsIterator(bx, by)) 555 return false; 556 } 557 } 558 559 return true; 560 } 561 562 /* 563 ================= 564 = 565 = PB_BoxCrossLine 566 = 567 ================= 568 */ 569 570 boolean PB_BoxCrossLine(line_t *ld) // 8000920 571 { 572 fixed_t x1, x2; 573 fixed_t lx, ly; 574 fixed_t ldx, ldy; 575 fixed_t dx1, dy1; 576 fixed_t dx2, dy2; 577 boolean side1, side2; 578 579 // entirely outside bounding box of line? 580 if(testbbox[BOXRIGHT ] <= ld->bbox[BOXLEFT ] || 581 testbbox[BOXLEFT ] >= ld->bbox[BOXRIGHT ] || 582 testbbox[BOXTOP ] <= ld->bbox[BOXBOTTOM] || 583 testbbox[BOXBOTTOM] >= ld->bbox[BOXTOP ]) 584 { 585 return false; 586 } 587 588 if (ld->slopetype == ST_POSITIVE) 589 { 590 x1 = testbbox[BOXLEFT]; 591 x2 = testbbox[BOXRIGHT]; 592 } 593 else 594 { 595 x1 = testbbox[BOXRIGHT]; 596 x2 = testbbox[BOXLEFT]; 597 } 598 599 lx = ld->v1->x; 600 ly = ld->v1->y; 601 ldx = ld->dx >> FRACBITS; 602 ldy = ld->dy >> FRACBITS; 603 604 dx1 = (x1 - lx) >> 16; 605 dy1 = (testbbox[BOXTOP] - ly) >> FRACBITS; 606 dx2 = (x2 - lx) >> 16; 607 dy2 = (testbbox[BOXBOTTOM] - ly) >> FRACBITS; 608 609 side1 = ldy*dx1 < dy1*ldx; 610 side2 = ldy*dx2 < dy2*ldx; 611 612 return (side1 != side2); 613 } 614 615 /* 616 ================== 617 = 618 = PB_CheckLine 619 = 620 = Adjusts testfloorz and testceilingz as lines are contacted 621 ================== 622 */ 623 624 boolean PB_CheckLine(line_t *ld) // 8000DA44 625 { 626 fixed_t opentop, openbottom; 627 fixed_t lowfloor; 628 sector_t *front, *back; 629 630 /* 631 = 632 = The moving thing's destination position will cross the given line. 633 = If this should not be allowed, return FALSE. 634 */ 635 if (!ld->backsector) 636 { 637 ceilingline = ld; 638 return false; // one sided line 639 } 640 641 if (!(testflags & MF_MISSILE) && (ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS))) 642 { 643 ceilingline = ld; 644 return false; // explicitly blocking 645 } 646 647 // [d64] don't cross projectile blockers 648 if ((ld->flags & ML_BLOCKPROJECTILES)) //psx doom / doom 64 new 649 { 650 ceilingline = ld; 651 return false; 652 } 653 654 front = ld->frontsector; 655 back = ld->backsector; 656 657 if (front->ceilingheight < back->ceilingheight) 658 opentop = front->ceilingheight; 659 else 660 opentop = back->ceilingheight; 661 662 if (front->floorheight > back->floorheight) 663 { 664 openbottom = front->floorheight; 665 lowfloor = back->floorheight; 666 } 667 else 668 { 669 openbottom = back->floorheight; 670 lowfloor = front->floorheight; 671 } 672 673 // adjust floor / ceiling heights 674 if (opentop < testceilingz) 675 { 676 testceilingz = opentop; 677 ceilingline = ld; 678 } 679 if (openbottom > testfloorz) 680 testfloorz = openbottom; 681 if (lowfloor < testdropoffz) 682 testdropoffz = lowfloor; 683 684 return true; 685 } 686 687 /* 688 ================== 689 = 690 = PB_BlockLinesIterator 691 = 692 ================== 693 */ 694 695 boolean PB_BlockLinesIterator(int x, int y) // 8000DB70 696 { 697 int offset; 698 short *list; 699 line_t *ld; 700 701 offset = y*bmapwidth+x; 702 703 offset = *(blockmap + offset); 704 705 for (list = blockmaplump + offset; *list != -1; list++) 706 { 707 ld = &lines[*list]; 708 if (ld->validcount == validcount) 709 continue; // line has already been checked 710 ld->validcount = validcount; 711 712 if (PB_BoxCrossLine(ld)) 713 { 714 if (!PB_CheckLine(ld)) 715 return false; 716 } 717 } 718 719 return true; // everything was checked 720 } 721 722 /* 723 ================== 724 = 725 = PB_CheckThing 726 = 727 ================== 728 */ 729 730 boolean PB_CheckThing(mobj_t *thing) // 8000DC70 731 { 732 fixed_t blockdist; 733 int delta; 734 mobj_t *mo; 735 736 if (!(thing->flags & MF_SOLID)) 737 return true; // not blocking 738 739 mo = checkthing; 740 741 if(thing == mo) 742 return true; // don't clip against self 743 744 blockdist = thing->radius + testradius; 745 746 delta = thing->x - testx; 747 if (delta < 0) 748 delta = -delta; 749 750 if (delta >= blockdist) 751 return true; // didn't hit it 752 753 delta = thing->y - testy; 754 if (delta < 0) 755 delta = -delta; 756 757 if (delta >= blockdist) 758 return true; // didn't hit it 759 760 // 761 // check for skulls slamming into things 762 // 763 if (testflags & MF_SKULLFLY) 764 { 765 hitthing = thing; 766 return false; // stop moving 767 } 768 769 // 770 // missiles can hit other things 771 // 772 if (testflags & MF_MISSILE) 773 { 774 // see if it went over / under 775 if (mo->z > thing->z + thing->height) 776 return true; // overhead 777 778 if (mo->z + mo->height < thing->z) 779 return true; // underneath 780 781 if (mo->target->type == thing->type) // don't hit same species as originator 782 { 783 if (thing == mo->target) 784 return true; // don't explode on shooter 785 786 if (thing->type != MT_PLAYER) 787 return false; // explode, but do no damage 788 // let players missile other players 789 } 790 if (!(thing->flags & MF_SHOOTABLE)) 791 return !(thing->flags & MF_SOLID); // didn't do any damage 792 // damage / explode 793 hitthing = thing; 794 return false; // don't traverse any more 795 } 796 797 return !(thing->flags & MF_SOLID); 798 } 799 800 801 /* 802 ================== 803 = 804 = PB_BlockThingsIterator 805 = 806 ================== 807 */ 808 809 boolean PB_BlockThingsIterator(int x, int y) // 8000DDD4 810 { 811 mobj_t *mobj; 812 813 for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext) 814 { 815 if (!PB_CheckThing(mobj)) 816 return false; 817 } 818 819 return true; 820 }