p_slide.c (16109B)
1 #include "doomdef.h" 2 #include "p_local.h" 3 4 #define CLIPRADIUS 23 5 #define SIDE_ON 0 6 #define SIDE_FRONT 1 7 #define SIDE_BACK -1 8 9 fixed_t bestslidefrac; // 800A5728 10 line_t *bestslideline; // 800A572C 11 mobj_t *slidemo; // 800A5730 12 13 /* 14 ==================== 15 = 16 = PTR_SlideTraverse 17 = 18 ==================== 19 */ 20 21 boolean PTR_SlideTraverse(intercept_t* in) // 800170AC 22 { 23 line_t* li; 24 25 li = in->d.line; 26 27 if(!(li->flags & ML_TWOSIDED)) 28 { 29 if(P_PointOnLineSide(slidemo->x, slidemo->y, li)) 30 return true; /* don't hit the back side */ 31 32 goto isblocking; 33 } 34 35 /* set openrange, opentop, openbottom */ 36 P_LineOpening(li); 37 38 if(openrange < slidemo->height) 39 { 40 goto isblocking; /* doesn't fit */ 41 } 42 43 if(opentop - slidemo->z < slidemo->height) 44 { 45 goto isblocking; /* mobj is too high */ 46 } 47 48 if(openbottom - slidemo->z > 24*FRACUNIT) 49 { 50 goto isblocking; /* too big a step up */ 51 } 52 53 /* this line doesn't block movement */ 54 return true; 55 56 /* the line does block movement, */ 57 /* see if it is closer than best so far */ 58 59 isblocking: 60 61 if(in->frac < bestslidefrac) 62 { 63 bestslidefrac = in->frac; 64 bestslideline = li; 65 } 66 67 return false; /* stop */ 68 } 69 70 /* 71 =============================================== 72 = P_SlideMove 73 = The momx / momy move is bad, so try to slide 74 = along a wall. 75 = Find the first line hit, move flush to it, 76 = and slide along it 77 = 78 = This is a kludgy mess. 79 =============================================== 80 */ 81 82 void P_SlideMove(mobj_t* mo) // 800171B0 83 { 84 fixed_t tmxmove; 85 fixed_t tmymove; 86 fixed_t leadx; 87 fixed_t leady; 88 fixed_t trailx; 89 fixed_t traily; 90 fixed_t newx; 91 fixed_t newy; 92 int hitcount; 93 line_t* ld; 94 int an1; 95 int an2; 96 97 slidemo = mo; 98 hitcount = 0; 99 100 retry: 101 hitcount++; 102 103 if(hitcount == 3) 104 { 105 goto stairstep; // don't loop forever 106 } 107 108 // trace along the three leading corners 109 if(mo->momx > 0) 110 { 111 leadx = mo->x + mo->radius; 112 trailx = mo->x - mo->radius; 113 } 114 else 115 { 116 leadx = mo->x - mo->radius; 117 trailx = mo->x + mo->radius; 118 } 119 120 if(mo->momy > 0) 121 { 122 leady = mo->y + mo->radius; 123 traily = mo->y - mo->radius; 124 } 125 else 126 { 127 leady = mo->y - mo->radius; 128 traily = mo->y + mo->radius; 129 } 130 131 bestslidefrac = FRACUNIT+1; 132 133 P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy, 134 PT_ADDLINES, PTR_SlideTraverse); 135 P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy, 136 PT_ADDLINES, PTR_SlideTraverse); 137 P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy, 138 PT_ADDLINES, PTR_SlideTraverse); 139 140 // move up to the wall 141 if(bestslidefrac == FRACUNIT+1) 142 { 143 // the move most have hit the middle, so stairstep 144 stairstep: 145 if(!P_TryMove(mo, mo->x, mo->y + mo->momy)) 146 { 147 if(!P_TryMove(mo, mo->x + mo->momx, mo->y)) 148 { 149 // [d64] set momx and momy to 0 150 mo->momx = 0; 151 mo->momy = 0; 152 } 153 } 154 return; 155 } 156 157 // fudge a bit to make sure it doesn't hit 158 bestslidefrac -= 0x800; 159 if(bestslidefrac > 0) 160 { 161 newx = FixedMul(mo->momx, bestslidefrac); 162 newy = FixedMul(mo->momy, bestslidefrac); 163 164 if(!P_TryMove(mo, mo->x + newx, mo->y + newy)) 165 { 166 bestslidefrac = FRACUNIT; 167 168 // [d64] jump to hitslideline instead of stairstep 169 goto hitslideline; 170 } 171 } 172 173 // Now continue along the wall. 174 // First calculate remainder. 175 bestslidefrac = 0xf800 - bestslidefrac; 176 //bestslidefrac = FRACUNIT - (bestslidefrac + 0x800); 177 178 if(bestslidefrac > FRACUNIT) 179 { 180 bestslidefrac = FRACUNIT; 181 } 182 183 if(bestslidefrac <= 0) 184 { 185 return; 186 } 187 188 // 189 // [d64] code below is loosely based on P_HitSlideLine 190 // 191 hitslideline: 192 193 ld = bestslideline; 194 195 if(ld->slopetype == ST_HORIZONTAL) 196 { 197 tmymove = 0; 198 } 199 else 200 { 201 tmymove = FixedMul(mo->momy, bestslidefrac); 202 } 203 204 if(ld->slopetype == ST_VERTICAL) 205 { 206 tmxmove = 0; 207 } 208 else 209 { 210 tmxmove = FixedMul(mo->momx, bestslidefrac); 211 } 212 213 // 214 // [d64] this new algorithm seems to reduce the chances 215 // of boosting the player's speed when wall running 216 // 217 218 an1 = finecosine[ld->fineangle]; 219 an2 = finesine[ld->fineangle]; 220 221 if(P_PointOnLineSide(mo->x, mo->y, bestslideline)) 222 { 223 // 224 // [d64] same as deltaangle += ANG180 ? 225 // 226 an1 = -an1; 227 an2 = -an2; 228 } 229 230 newx = FixedMul(tmxmove, an1); 231 newy = FixedMul(tmymove, an2); 232 233 mo->momx = FixedMul(newx + newy, an1); 234 mo->momy = FixedMul(newx + newy, an2); 235 236 if(!P_TryMove(mo, mo->x + mo->momx, mo->y + mo->momy)) 237 { 238 goto retry; 239 } 240 } 241 242 //---------------------- 243 244 #if 0 245 246 fixed_t slidex, slidey; // the final position //80077DBC|fGp000009ac, 80077DC0|fGp000009b0 247 line_t *specialline; //80077DC8, uGp000009b8 248 249 fixed_t slidedx, slidedy; // current move for completablefrac //80077E9C|fGp00000a8c, 80077EA0|fGp00000a90 250 251 fixed_t endbox[4]; // final proposed position //800979d0 252 253 fixed_t blockfrac; // the fraction of move that gets completed //8007804C|iGp00000c3c 254 fixed_t blocknvx, blocknvy; // the vector of the line that blocks move //80077FD0|fGp00000bc0, 80077FD8|fGp00000bc8 255 256 // p1, p2 are line endpoints 257 // p3, p4 are move endpoints 258 /*iGp00000ae4, iGp00000aec*///p1x, p1y 259 /*iGp00000ae8, iGp00000af8*///p2x, p2y 260 /*iGp00000af4, iGp00000b0c*///p3x, p3y 261 /*iGp00000b08, iGp00000b14*///p4x, p4y 262 263 int p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; 264 fixed_t nvx, nvy; // normalized line vector //fGp00000b70, fGp00000b74 265 266 extern mobj_t *slidething;//80077D04 267 268 269 fixed_t P_CompletableFrac(fixed_t dx, fixed_t dy); 270 int SL_PointOnSide(fixed_t x, fixed_t y); 271 fixed_t SL_CrossFrac (void); 272 boolean CheckLineEnds (void); 273 void SL_ClipToLine( void ); 274 boolean SL_CheckLine(line_t *ld); 275 int SL_PointOnSide2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, fixed_t x3, fixed_t y3); 276 void SL_CheckSpecialLines (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); 277 278 /* 279 =================== 280 = 281 = P_SlideMove 282 = 283 =================== 284 */ 285 286 void P_SlideMove(void)//L8002553C() 287 { 288 fixed_t dx, dy, rx, ry; 289 fixed_t frac, slide; 290 int i; 291 292 dx = slidething->momx; 293 dy = slidething->momy; 294 slidex = slidething->x; 295 slidey = slidething->y; 296 297 if (slidething->flags & MF_NOCLIP)//Psx Doom 298 { 299 frac = FRACUNIT; 300 goto Skip_P_CompletableFrac; 301 } 302 303 // perform a maximum of three bumps 304 for (i = 0; i < 3; i++) 305 { 306 frac = P_CompletableFrac(dx, dy); 307 308 if (frac != FRACUNIT) 309 frac -= 0x1000; 310 311 if (frac < 0) 312 frac = 0; 313 314 Skip_P_CompletableFrac: 315 rx = FixedMul(frac, dx); 316 ry = FixedMul(frac, dy); 317 318 slidex += rx; 319 slidey += ry; 320 321 // made it the entire way 322 if (frac == FRACUNIT) 323 { 324 slidething->momx = dx; 325 slidething->momy = dy; 326 SL_CheckSpecialLines(slidething->x, slidething->y, slidex, slidey); 327 return; 328 } 329 330 // project the remaining move along the line that blocked movement 331 dx -= rx; 332 dy -= ry; 333 slide = FixedMul(dx, blocknvx) + FixedMul(dy, blocknvy); 334 335 dx = FixedMul(slide, blocknvx); 336 dy = FixedMul(slide, blocknvy); 337 } 338 339 // some hideous situation has happened that won't let the player slide 340 slidex = slidething->x; 341 slidey = slidething->y; 342 slidething->momx = slidething->momy = 0; 343 } 344 345 346 /* 347 =================== 348 = 349 = P_CompletableFrac 350 = 351 = Returns the fraction of the move that is completable 352 =================== 353 */ 354 355 fixed_t P_CompletableFrac(fixed_t dx, fixed_t dy)//L800256CC() 356 { 357 int xl,xh,yl,yh,bx,by; 358 int offset; 359 short *list; 360 line_t *ld; 361 362 blockfrac = FRACUNIT; // the entire dist until shown otherwise 363 slidedx = dx; 364 slidedy = dy; 365 366 endbox[BOXTOP ] = slidey + CLIPRADIUS*FRACUNIT; 367 endbox[BOXBOTTOM] = slidey - CLIPRADIUS*FRACUNIT; 368 endbox[BOXRIGHT ] = slidex + CLIPRADIUS*FRACUNIT; 369 endbox[BOXLEFT ] = slidex - CLIPRADIUS*FRACUNIT; 370 371 if (dx > 0) 372 endbox[BOXRIGHT ] += dx; 373 else 374 endbox[BOXLEFT ] += dx; 375 376 if (dy > 0) 377 endbox[BOXTOP ] += dy; 378 else 379 endbox[BOXBOTTOM] += dy; 380 381 ++validcount; 382 383 // 384 // check lines 385 // 386 xl = (endbox[BOXLEFT ] - bmaporgx) >> MAPBLOCKSHIFT; 387 xh = (endbox[BOXRIGHT ] - bmaporgx) >> MAPBLOCKSHIFT; 388 yl = (endbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT; 389 yh = (endbox[BOXTOP ] - bmaporgy) >> MAPBLOCKSHIFT; 390 391 if (xl<0) 392 xl = 0; 393 if (yl<0) 394 yl = 0; 395 396 if (xh>= bmapwidth) 397 xh = bmapwidth -1; 398 399 if (yh>= bmapheight) 400 yh = bmapheight -1; 401 402 for (bx = xl; bx <= xh; bx++) 403 { 404 for (by = yl; by <= yh; by++) 405 { 406 /*inline ??*/ 407 //P_BlockLinesIterator(bx, by, SL_CheckLine); 408 409 offset = by*bmapwidth+bx; 410 411 offset = *(blockmap+offset); 412 413 for ( list = blockmaplump+offset ; *list != -1 ; list++) 414 { 415 ld = &lines[*list]; 416 417 if (ld->validcount != validcount) 418 { 419 ld->validcount = validcount; 420 SL_CheckLine(ld); 421 } 422 } 423 } 424 } 425 426 // 427 // examine results 428 // 429 if (blockfrac < 0x1000) 430 { 431 blockfrac = 0; 432 specialline = 0; // can't cross anything on a bad move 433 return 0; // solid wall or thing 434 } 435 436 return blockfrac; 437 } 438 439 //inline 440 int SL_PointOnSide(fixed_t x, fixed_t y)//L80025970() 441 { 442 //checked 443 fixed_t dx, dy, dist; 444 445 dx = x - p1x; 446 dy = y - p1y; 447 dist = FixedMul(dx,nvx) + FixedMul(dy,nvy); 448 449 if(dist > FRACUNIT) 450 return SIDE_FRONT; 451 else if(dist < -FRACUNIT) 452 return SIDE_BACK; 453 else 454 return SIDE_ON; 455 } 456 457 //inline 458 fixed_t SL_CrossFrac (void)//L800259E0() 459 { 460 //checked 461 fixed_t dx, dy, dist1, dist2, frac; 462 463 // project move start and end points onto line normal 464 dx = p3x - p1x; 465 dy = p3y - p1y; 466 467 dist1 = FixedMul(dx,nvx) + FixedMul(dy,nvy); 468 469 dx = p4x - p1x; 470 dy = p4y - p1y; 471 dist2 = FixedMul(dx,nvx) + FixedMul(dy,nvy); 472 473 if ((dist1 < 0) == (dist2 < 0)) 474 return FRACUNIT; // doesn't cross 475 476 frac = FixedDiv(dist1, dist1 - dist2 ); 477 478 return frac; 479 } 480 481 482 boolean CheckLineEnds (void)//L80025A98() 483 { 484 //checked 485 fixed_t snx, sny; // sight normals 486 fixed_t dist1, dist2; 487 fixed_t dx, dy; 488 489 snx = p4y - p3y; 490 sny = p3x - p4x; 491 492 dx = p1x - p3x; 493 dy = p1y - p3y; 494 495 dist1 = FixedMul(dx,snx) + FixedMul(dy,sny); 496 497 dx = p2x - p3x; 498 dy = p2y - p3y; 499 500 dist2 = FixedMul(dx,snx) + FixedMul(dy,sny); 501 502 return ((dist1 < 0)^(dist2 < 0)); 503 504 /* 505 if ( (dist1<0) == (dist2<0) ) 506 return false; 507 508 return true; 509 */ 510 } 511 512 513 /* 514 ==================== 515 = 516 = SL_ClipToLine 517 = 518 = Call with p1 and p2 set to the endpoints 519 = and nvx, nvy set to normalized vector 520 = Assumes the start point is definately on the front side of the line 521 = returns the fraction of the current move that crosses the line segment 522 ==================== 523 */ 524 525 void SL_ClipToLine( void )//L80025B58() 526 { 527 fixed_t frac; 528 int side2, side3; 529 530 // adjust start so it will be the first point contacted on the player circle 531 // p3, p4 are move endpoints 532 533 p3x = slidex - CLIPRADIUS * nvx; 534 p3y = slidey - CLIPRADIUS * nvy; 535 p4x = p3x + slidedx; 536 p4y = p3y + slidedy; 537 538 // if the adjusted point is on the other side of the line, the endpoint must 539 // be checked. 540 side2 = SL_PointOnSide(p3x, p3y); 541 if(side2 == SIDE_BACK) 542 return; // ClipToPoint and slide along normal to line 543 544 side3 = SL_PointOnSide(p4x, p4y); 545 if(side3 == SIDE_ON) 546 return; // the move goes flush with the wall 547 else if(side3 == SIDE_FRONT) 548 return; // move doesn't cross line 549 550 if(side2 == SIDE_ON) 551 { 552 frac = 0; // moves toward the line 553 goto blockmove; 554 } 555 556 // the line endpoints must be on opposite sides of the move trace 557 558 // find the fractional intercept 559 frac = SL_CrossFrac(); 560 561 if(frac < blockfrac) 562 { 563 blockmove: 564 blockfrac = frac; 565 blocknvx = -nvy; 566 blocknvy = nvx; 567 } 568 } 569 570 /* 571 ================== 572 = 573 = SL_CheckLine 574 = 575 ================== 576 */ 577 578 579 boolean SL_CheckLine(line_t *ld)//L80025D50() 580 { 581 fixed_t opentop, openbottom; 582 sector_t *front, *back; 583 int side1, temp; 584 585 // check bbox first 586 if (endbox[BOXRIGHT ] < ld->bbox[BOXLEFT ] 587 || endbox[BOXLEFT ] > ld->bbox[BOXRIGHT ] 588 || endbox[BOXTOP ] < ld->bbox[BOXBOTTOM] 589 || endbox[BOXBOTTOM] > ld->bbox[BOXTOP ] ) 590 return true; 591 592 // see if it can possibly block movement 593 if (!ld->backsector || ld->flags & ML_BLOCKING) 594 goto findfrac; // explicitly blocking 595 596 front = ld->frontsector; 597 back = ld->backsector; 598 599 if (front->floorheight > back->floorheight) 600 openbottom = front->floorheight; 601 else 602 openbottom = back->floorheight; 603 604 if (openbottom - slidething->z > 24*FRACUNIT) 605 goto findfrac; // too big of a step up 606 607 if (front->ceilingheight < back->ceilingheight) 608 opentop = front->ceilingheight; 609 else 610 opentop = back->ceilingheight; 611 612 if (opentop - openbottom >= 56*FRACUNIT) 613 return true; // the line doesn't block movement 614 615 // the line definately blocks movement 616 findfrac: 617 // p1, p2 are line endpoints 618 p1x = ld->v1->x; 619 p1y = ld->v1->y; 620 p2x = ld->v2->x; 621 p2y = ld->v2->y; 622 623 nvx = finesine[ld->fineangle]; 624 nvy = -finecosine[ld->fineangle]; 625 626 side1 = SL_PointOnSide (slidex, slidey); 627 if (side1 == SIDE_ON) 628 return true; 629 if (side1 == SIDE_BACK) 630 { 631 if (!ld->backsector) 632 return true; // don't clip to backs of one sided lines 633 temp = p1x; 634 p1x = p2x; 635 p2x = temp; 636 temp = p1y; 637 p1y = p2y; 638 p2y = temp; 639 nvx = -nvx; 640 nvy = -nvy; 641 } 642 643 SL_ClipToLine(); 644 return true; 645 } 646 647 int SL_PointOnSide2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, fixed_t x3, fixed_t y3)//L80025f9C() 648 { 649 //checked 650 fixed_t nx, ny; 651 fixed_t dist; 652 653 x1 = (x1 - x2); 654 y1 = (y1 - y2); 655 656 nx = (y3 - y2); 657 ny = (x2 - x3); 658 659 dist = FixedMul(x1, nx) + FixedMul(y1, ny); 660 661 if (dist < 0) 662 return SIDE_BACK; 663 return SIDE_FRONT; 664 } 665 666 static short *list_; //80078074|psGp00000c64 667 static line_t *ld_; //80077E48|plGp00000a38 668 static int offset_; //80077DB0|iGp000009a0 669 670 void SL_CheckSpecialLines (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)//L8002600C() 671 { 672 fixed_t bx, by, xl, xh, yl, yh, bxl, bxh, byl, byh; 673 fixed_t x3,y3,x4,y4; 674 int side1, side2; 675 676 if (x1<x2) { 677 xl = x1; 678 xh = x2; 679 } else { 680 xl = x2; 681 xh = x1; 682 } 683 if (y1<y2) { 684 yl = y1; 685 yh = y2; 686 } else { 687 yl = y2; 688 yh = y1; 689 } 690 691 bxl = (xl - bmaporgx)>>MAPBLOCKSHIFT; 692 bxh = (xh - bmaporgx)>>MAPBLOCKSHIFT; 693 byl = (yl - bmaporgy)>>MAPBLOCKSHIFT; 694 byh = (yh - bmaporgy)>>MAPBLOCKSHIFT; 695 696 if (bxl<0) 697 bxl = 0; 698 if (byl<0) 699 byl = 0; 700 if (bxh>= bmapwidth) 701 bxh = bmapwidth -1; 702 if (byh>= bmapheight) 703 byh = bmapheight -1; 704 705 specialline = 0; 706 ++validcount; 707 708 for (bx = bxl; bx <= bxh; bx++) 709 { 710 for (by = byl; by <= byh; by++) 711 { 712 offset_ = (by*bmapwidth) + bx; 713 offset_ = *(blockmap + offset_); 714 715 for (list_ = blockmaplump + offset_; *list_ != -1; list_++) 716 { 717 ld_ = &lines[*list_]; 718 719 if (!ld_->special) 720 continue; 721 if (ld_->validcount == validcount) 722 continue; // line has already been checked 723 724 ld_->validcount = validcount; 725 726 if (xh < ld_->bbox[BOXLEFT] 727 || xl > ld_->bbox[BOXRIGHT] 728 || yh < ld_->bbox[BOXBOTTOM] 729 || yl > ld_->bbox[BOXTOP]) 730 continue; 731 732 x3 = ld_->v1->x; 733 y3 = ld_->v1->y; 734 x4 = ld_->v2->x; 735 y4 = ld_->v2->y; 736 737 side1 = SL_PointOnSide2(x1, y1, x3, y3, x4, y4); 738 side2 = SL_PointOnSide2(x2, y2, x3, y3, x4, y4); 739 740 if (side1 == side2) 741 continue; // move doesn't cross line 742 743 side1 = SL_PointOnSide2(x3, y3, x1, y1, x2, y2); 744 side2 = SL_PointOnSide2(x4, y4, x1, y1, x2, y2); 745 746 if (side1 == side2) 747 continue; // line doesn't cross move 748 749 specialline = ld_; 750 return; 751 } 752 } 753 } 754 } 755 #endif // 0