am_map.cpp (24961B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #include "Precompiled.h" 30 #include "globaldata.h" 31 32 #include <stdio.h> 33 34 35 #include "z_zone.h" 36 #include "doomdef.h" 37 #include "st_stuff.h" 38 #include "p_local.h" 39 #include "w_wad.h" 40 41 #include "m_cheat.h" 42 #include "i_system.h" 43 44 // Needs access to LFB. 45 #include "v_video.h" 46 47 // State. 48 #include "doomstat.h" 49 #include "r_state.h" 50 51 // Data. 52 #include "dstrings.h" 53 54 #include "am_map.h" 55 56 57 // For use if I do walls with outsides/insides 58 59 // Automap colors 60 61 // drawing stuff 62 63 64 65 // scale on entry 66 // how much the automap moves window per tic in frame-::g->buffer coordinates 67 // moves 140 pixels in 1 second 68 // how much zoom-in per tic 69 // goes to 2x in 1 second 70 // how much zoom-out per tic 71 // pulls out to 0.5x in 1 second 72 73 // translates between frame-::g->buffer and map distances 74 // translates between frame-::g->buffer and map coordinates 75 76 // the following is crap 77 78 79 80 81 82 83 84 85 // 86 // The vector graphics for the automap. 87 // A line drawing of the player pointing right, 88 // starting from the middle. 89 // 90 #define R ((8*PLAYERRADIUS)/7) 91 mline_t player_arrow[] = 92 { 93 { { -R+R/8, 0 }, { R, 0 } }, // ----- 94 { { R, 0 }, { R-R/2, R/4 } }, // -----> 95 { { R, 0 }, { R-R/2, -R/4 } }, 96 { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> 97 { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, 98 { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> 99 { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } 100 }; 101 #undef R 102 103 #define R ((8*PLAYERRADIUS)/7) 104 mline_t cheat_player_arrow[] = 105 { 106 { { -R+R/8, 0 }, { R, 0 } }, // ----- 107 { { R, 0 }, { R-R/2, R/6 } }, // -----> 108 { { R, 0 }, { R-R/2, -R/6 } }, 109 { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> 110 { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, 111 { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> 112 { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, 113 { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> 114 { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, 115 { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, 116 { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> 117 { { -R/6, -R/6 }, { 0, -R/6 } }, 118 { { 0, -R/6 }, { 0, R/4 } }, 119 { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> 120 { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, 121 { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } 122 }; 123 #undef R 124 125 #define R (FRACUNIT) 126 mline_t triangle_guy[] = 127 { 128 { { fixed_t(-.867*R), fixed_t(-.5*R) }, { fixed_t(.867*R), fixed_t(-.5*R) } }, 129 { { fixed_t(.867*R), fixed_t(-.5*R) } , { 0, R } }, 130 { { 0, R }, { fixed_t(-.867*R), fixed_t(-.5*R) } } 131 }; 132 #undef R 133 134 #define R (FRACUNIT) 135 mline_t thintriangle_guy[] = 136 { 137 { { fixed_t(-.5*R), fixed_t(-.7*R) }, { R, 0 } }, 138 { { R, 0 }, { fixed_t(-.5*R), fixed_t(.7*R) } }, 139 { { fixed_t(-.5*R), fixed_t(.7*R) }, { fixed_t(-.5*R), fixed_t(-.7*R) } } 140 }; 141 #undef R 142 143 144 145 146 147 148 149 // location of window on screen 150 151 // size of window on screen 152 153 154 155 156 // 157 // width/height of window on map (map coords) 158 // 159 160 // based on level size 161 162 163 // based on player size 164 165 166 167 // old stuff for recovery later 168 169 // old location used by the Follower routine 170 171 // used by MTOF to scale from map-to-frame-::g->buffer coords 172 // used by FTOM to scale from frame-::g->buffer-to-map coords (=1/::g->scale_mtof) 173 174 175 176 177 const unsigned char cheat_amap_seq[] = 178 { 179 0xb2, 0x26, 0x26, 0x2e, 0xff 180 }; 181 cheatseq_t cheat_amap = cheatseq_t( cheat_amap_seq, 0 ); 182 183 184 //extern byte ::g->screens[][SCREENWIDTH*SCREENHEIGHT]; 185 186 187 188 void 189 V_MarkRect 190 ( int x, 191 int y, 192 int width, 193 int height ); 194 195 // Calculates the slope and slope according to the x-axis of a line 196 // segment in map coordinates (with the upright y-axis n' all) so 197 // that it can be used with the brain-dead drawing stuff. 198 199 void 200 AM_getIslope 201 ( mline_t* ml, 202 islope_t* is ) 203 { 204 int dx, dy; 205 206 dy = ml->a.y - ml->b.y; 207 dx = ml->b.x - ml->a.x; 208 if (!dy) is->islp = (dx<0?-MAXINT:MAXINT); 209 else is->islp = FixedDiv(dx, dy); 210 if (!dx) is->slp = (dy<0?-MAXINT:MAXINT); 211 else is->slp = FixedDiv(dy, dx); 212 213 } 214 215 // 216 // 217 // 218 void AM_activateNewScale(void) 219 { 220 ::g->m_x += ::g->m_w/2; 221 ::g->m_y += ::g->m_h/2; 222 ::g->m_w = FTOM(::g->f_w); 223 ::g->m_h = FTOM(::g->f_h); 224 ::g->m_x -= ::g->m_w/2; 225 ::g->m_y -= ::g->m_h/2; 226 ::g->m_x2 = ::g->m_x + ::g->m_w; 227 ::g->m_y2 = ::g->m_y + ::g->m_h; 228 } 229 230 // 231 // 232 // 233 void AM_saveScaleAndLoc(void) 234 { 235 ::g->old_m_x = ::g->m_x; 236 ::g->old_m_y = ::g->m_y; 237 ::g->old_m_w = ::g->m_w; 238 ::g->old_m_h = ::g->m_h; 239 } 240 241 // 242 // 243 // 244 void AM_restoreScaleAndLoc(void) 245 { 246 247 ::g->m_w = ::g->old_m_w; 248 ::g->m_h = ::g->old_m_h; 249 if (!::g->followplayer) 250 { 251 ::g->m_x = ::g->old_m_x; 252 ::g->m_y = ::g->old_m_y; 253 } else { 254 ::g->m_x = ::g->amap_plr->mo->x - ::g->m_w/2; 255 ::g->m_y = ::g->amap_plr->mo->y - ::g->m_h/2; 256 } 257 ::g->m_x2 = ::g->m_x + ::g->m_w; 258 ::g->m_y2 = ::g->m_y + ::g->m_h; 259 260 // Change the scaling multipliers 261 ::g->scale_mtof = FixedDiv(::g->f_w<<FRACBITS, ::g->m_w); 262 ::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof); 263 } 264 265 // 266 // adds a marker at the current location 267 // 268 void AM_addMark(void) 269 { 270 ::g->markpoints[::g->markpointnum].x = ::g->m_x + ::g->m_w/2; 271 ::g->markpoints[::g->markpointnum].y = ::g->m_y + ::g->m_h/2; 272 ::g->markpointnum = (::g->markpointnum + 1) % AM_NUMMARKPOINTS; 273 274 } 275 276 // 277 // Determines bounding box of all vertices, 278 // sets global variables controlling zoom range. 279 // 280 void AM_findMinMaxBoundaries(void) 281 { 282 int i; 283 fixed_t a; 284 fixed_t b; 285 286 ::g->min_x = ::g->min_y = MAXINT; 287 ::g->max_x = ::g->max_y = -MAXINT; 288 289 for (i=0; i < ::g->numvertexes; i++) 290 { 291 if (::g->vertexes[i].x < ::g->min_x) 292 ::g->min_x = ::g->vertexes[i].x; 293 else if (::g->vertexes[i].x > ::g->max_x) 294 ::g->max_x = ::g->vertexes[i].x; 295 296 if (::g->vertexes[i].y < ::g->min_y) 297 ::g->min_y = ::g->vertexes[i].y; 298 else if (::g->vertexes[i].y > ::g->max_y) 299 ::g->max_y = ::g->vertexes[i].y; 300 } 301 302 ::g->max_w = ::g->max_x - ::g->min_x; 303 ::g->max_h = ::g->max_y - ::g->min_y; 304 305 ::g->min_w = 2*PLAYERRADIUS; // const? never changed? 306 ::g->min_h = 2*PLAYERRADIUS; 307 308 a = FixedDiv(::g->f_w<<FRACBITS, ::g->max_w); 309 b = FixedDiv(::g->f_h<<FRACBITS, ::g->max_h); 310 311 ::g->min_scale_mtof = a < b ? a : b; 312 ::g->max_scale_mtof = FixedDiv(::g->f_h<<FRACBITS, 2*PLAYERRADIUS); 313 314 } 315 316 317 // 318 // 319 // 320 void AM_changeWindowLoc(void) 321 { 322 if (::g->m_paninc.x || ::g->m_paninc.y) 323 { 324 ::g->followplayer = 0; 325 ::g->f_oldloc.x = MAXINT; 326 } 327 328 ::g->m_x += ::g->m_paninc.x; 329 ::g->m_y += ::g->m_paninc.y; 330 331 if (::g->m_x + ::g->m_w/2 > ::g->max_x) 332 ::g->m_x = ::g->max_x - ::g->m_w/2; 333 else if (::g->m_x + ::g->m_w/2 < ::g->min_x) 334 ::g->m_x = ::g->min_x - ::g->m_w/2; 335 336 if (::g->m_y + ::g->m_h/2 > ::g->max_y) 337 ::g->m_y = ::g->max_y - ::g->m_h/2; 338 else if (::g->m_y + ::g->m_h/2 < ::g->min_y) 339 ::g->m_y = ::g->min_y - ::g->m_h/2; 340 341 ::g->m_x2 = ::g->m_x + ::g->m_w; 342 ::g->m_y2 = ::g->m_y + ::g->m_h; 343 } 344 345 346 // 347 // 348 // 349 void AM_initVariables(void) 350 { 351 static event_t st_notify = { ev_keyup, AM_MSGENTERED }; 352 int pnum; 353 354 ::g->automapactive = true; 355 ::g->fb = ::g->screens[0]; 356 357 ::g->f_oldloc.x = MAXINT; 358 ::g->amclock = 0; 359 ::g->lightlev = 0; 360 361 ::g->m_paninc.x = ::g->m_paninc.y = 0; 362 ::g->ftom_zoommul = FRACUNIT; 363 ::g->mtof_zoommul = FRACUNIT; 364 365 ::g->m_w = FTOM(::g->f_w); 366 ::g->m_h = FTOM(::g->f_h); 367 368 // find player to center on initially 369 if (!::g->playeringame[pnum = ::g->consoleplayer]) 370 for (pnum=0;pnum<MAXPLAYERS;pnum++) 371 if (::g->playeringame[pnum]) 372 break; 373 374 ::g->amap_plr = &::g->players[pnum]; 375 ::g->m_x = ::g->amap_plr->mo->x - ::g->m_w/2; 376 ::g->m_y = ::g->amap_plr->mo->y - ::g->m_h/2; 377 AM_changeWindowLoc(); 378 379 // for saving & restoring 380 ::g->old_m_x = ::g->m_x; 381 ::g->old_m_y = ::g->m_y; 382 ::g->old_m_w = ::g->m_w; 383 ::g->old_m_h = ::g->m_h; 384 385 // inform the status bar of the change 386 ST_Responder(&st_notify); 387 388 } 389 390 // 391 // 392 // 393 void AM_loadPics(void) 394 { 395 int i; 396 char namebuf[9]; 397 398 for (i=0;i<10;i++) 399 { 400 sprintf(namebuf, "AMMNUM%d", i); 401 ::g->marknums[i] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED); 402 } 403 404 } 405 406 void AM_unloadPics(void) 407 { 408 // int i; 409 410 } 411 412 void AM_clearMarks(void) 413 { 414 int i; 415 416 for (i=0;i<AM_NUMMARKPOINTS;i++) 417 ::g->markpoints[i].x = -1; // means empty 418 ::g->markpointnum = 0; 419 } 420 421 // 422 // should be called at the start of every level 423 // right now, i figure it out myself 424 // 425 void AM_LevelInit(void) 426 { 427 ::g->leveljuststarted = 0; 428 429 ::g->f_x = ::g->f_y = 0; 430 ::g->f_w = ::g->finit_width; 431 ::g->f_h = ::g->finit_height; 432 433 AM_clearMarks(); 434 435 AM_findMinMaxBoundaries(); 436 ::g->scale_mtof = FixedDiv(::g->min_scale_mtof, (int) (0.7*FRACUNIT)); 437 if (::g->scale_mtof > ::g->max_scale_mtof) 438 ::g->scale_mtof = ::g->min_scale_mtof; 439 ::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof); 440 } 441 442 443 444 445 // 446 // 447 // 448 void AM_Stop (void) 449 { 450 static event_t st_notify = { (evtype_t)0, ev_keyup, AM_MSGEXITED }; 451 452 AM_unloadPics(); 453 ::g->automapactive = false; 454 ST_Responder(&st_notify); 455 ::g->stopped = true; 456 } 457 458 // 459 // 460 // 461 void AM_Start (void) 462 { 463 464 if (!::g->stopped) AM_Stop(); 465 ::g->stopped = false; 466 if (::g->lastlevel != ::g->gamemap || ::g->lastepisode != ::g->gameepisode) 467 { 468 AM_LevelInit(); 469 ::g->lastlevel = ::g->gamemap; 470 ::g->lastepisode = ::g->gameepisode; 471 } 472 AM_initVariables(); 473 AM_loadPics(); 474 } 475 476 // 477 // set the window scale to the maximum size 478 // 479 void AM_minOutWindowScale(void) 480 { 481 ::g->scale_mtof = ::g->min_scale_mtof; 482 ::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof); 483 AM_activateNewScale(); 484 } 485 486 // 487 // set the window scale to the minimum size 488 // 489 void AM_maxOutWindowScale(void) 490 { 491 ::g->scale_mtof = ::g->max_scale_mtof; 492 ::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof); 493 AM_activateNewScale(); 494 } 495 496 497 // 498 // Handle ::g->events (user inputs) in automap mode 499 // 500 qboolean 501 AM_Responder 502 ( event_t* ev ) 503 { 504 505 int rc; 506 rc = false; 507 508 if (!::g->automapactive) 509 { 510 if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY) 511 { 512 AM_Start (); 513 ::g->viewactive = false; 514 rc = true; 515 } 516 } 517 518 else if (ev->type == ev_keydown) 519 { 520 521 rc = true; 522 switch(ev->data1) 523 { 524 case AM_PANRIGHTKEY: // pan right 525 if (!::g->followplayer) ::g->m_paninc.x = FTOM(F_PANINC); 526 else rc = false; 527 break; 528 case AM_PANLEFTKEY: // pan left 529 if (!::g->followplayer) ::g->m_paninc.x = -FTOM(F_PANINC); 530 else rc = false; 531 break; 532 case AM_PANUPKEY: // pan up 533 if (!::g->followplayer) ::g->m_paninc.y = FTOM(F_PANINC); 534 else rc = false; 535 break; 536 case AM_PANDOWNKEY: // pan down 537 if (!::g->followplayer) ::g->m_paninc.y = -FTOM(F_PANINC); 538 else rc = false; 539 break; 540 case AM_ZOOMOUTKEY: // zoom out 541 ::g->mtof_zoommul = M_ZOOMOUT; 542 ::g->ftom_zoommul = M_ZOOMIN; 543 break; 544 case AM_ZOOMINKEY: // zoom in 545 ::g->mtof_zoommul = M_ZOOMIN; 546 ::g->ftom_zoommul = M_ZOOMOUT; 547 break; 548 case AM_ENDKEY: 549 ::g->bigstate = 0; 550 ::g->viewactive = true; 551 AM_Stop (); 552 break; 553 case AM_GOBIGKEY: 554 ::g->bigstate = !::g->bigstate; 555 if (::g->bigstate) 556 { 557 AM_saveScaleAndLoc(); 558 AM_minOutWindowScale(); 559 } 560 else AM_restoreScaleAndLoc(); 561 break; 562 case AM_FOLLOWKEY: 563 ::g->followplayer = !::g->followplayer; 564 ::g->f_oldloc.x = MAXINT; 565 ::g->amap_plr->message = ::g->followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF; 566 break; 567 case AM_GRIDKEY: 568 ::g->grid = !::g->grid; 569 ::g->amap_plr->message = ::g->grid ? AMSTR_GRIDON : AMSTR_GRIDOFF; 570 break; 571 case AM_MARKKEY: 572 sprintf(::g->buffer, "%s %d", AMSTR_MARKEDSPOT, ::g->markpointnum); 573 ::g->amap_plr->message = ::g->buffer; 574 AM_addMark(); 575 break; 576 case AM_CLEARMARKKEY: 577 AM_clearMarks(); 578 ::g->amap_plr->message = AMSTR_MARKSCLEARED; 579 break; 580 default: 581 ::g->cheatstate=0; 582 rc = false; 583 } 584 if (!::g->deathmatch && cht_CheckCheat(&cheat_amap, ev->data1)) 585 { 586 rc = false; 587 ::g->cheating = (::g->cheating+1) % 3; 588 } 589 } 590 591 else if (ev->type == ev_keyup) 592 { 593 rc = false; 594 switch (ev->data1) 595 { 596 case AM_PANRIGHTKEY: 597 if (!::g->followplayer) ::g->m_paninc.x = 0; 598 break; 599 case AM_PANLEFTKEY: 600 if (!::g->followplayer) ::g->m_paninc.x = 0; 601 break; 602 case AM_PANUPKEY: 603 if (!::g->followplayer) ::g->m_paninc.y = 0; 604 break; 605 case AM_PANDOWNKEY: 606 if (!::g->followplayer) ::g->m_paninc.y = 0; 607 break; 608 case AM_ZOOMOUTKEY: 609 case AM_ZOOMINKEY: 610 ::g->mtof_zoommul = FRACUNIT; 611 ::g->ftom_zoommul = FRACUNIT; 612 break; 613 } 614 } 615 616 return rc; 617 618 } 619 620 621 // 622 // Zooming 623 // 624 void AM_changeWindowScale(void) 625 { 626 627 // Change the scaling multipliers 628 ::g->scale_mtof = FixedMul(::g->scale_mtof, ::g->mtof_zoommul); 629 ::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof); 630 631 if (::g->scale_mtof < ::g->min_scale_mtof) 632 AM_minOutWindowScale(); 633 else if (::g->scale_mtof > ::g->max_scale_mtof) 634 AM_maxOutWindowScale(); 635 else 636 AM_activateNewScale(); 637 } 638 639 640 // 641 // 642 // 643 void AM_doFollowPlayer(void) 644 { 645 646 if (::g->f_oldloc.x != ::g->amap_plr->mo->x || ::g->f_oldloc.y != ::g->amap_plr->mo->y) 647 { 648 ::g->m_x = FTOM(MTOF(::g->amap_plr->mo->x)) - ::g->m_w/2; 649 ::g->m_y = FTOM(MTOF(::g->amap_plr->mo->y)) - ::g->m_h/2; 650 ::g->m_x2 = ::g->m_x + ::g->m_w; 651 ::g->m_y2 = ::g->m_y + ::g->m_h; 652 ::g->f_oldloc.x = ::g->amap_plr->mo->x; 653 ::g->f_oldloc.y = ::g->amap_plr->mo->y; 654 655 // ::g->m_x = FTOM(MTOF(::g->amap_plr->mo->x - ::g->m_w/2)); 656 // ::g->m_y = FTOM(MTOF(::g->amap_plr->mo->y - ::g->m_h/2)); 657 // ::g->m_x = ::g->amap_plr->mo->x - ::g->m_w/2; 658 // ::g->m_y = ::g->amap_plr->mo->y - ::g->m_h/2; 659 660 } 661 662 } 663 664 // 665 // 666 // 667 void AM_updateLightLev(void) 668 { 669 //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 }; 670 const static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 }; 671 672 // Change light level 673 if (::g->amclock>::g->nexttic) 674 { 675 ::g->lightlev = litelevels[::g->litelevelscnt++]; 676 if (::g->litelevelscnt == sizeof(litelevels)/sizeof(int)) ::g->litelevelscnt = 0; 677 ::g->nexttic = ::g->amclock + 6 - (::g->amclock % 6); 678 } 679 680 } 681 682 683 // 684 // Updates on Game Tick 685 // 686 void AM_Ticker (void) 687 { 688 689 if (!::g->automapactive) 690 return; 691 692 ::g->amclock++; 693 694 if (::g->followplayer) 695 AM_doFollowPlayer(); 696 697 // Change the zoom if necessary 698 if (::g->ftom_zoommul != FRACUNIT) 699 AM_changeWindowScale(); 700 701 // Change x,y location 702 if (::g->m_paninc.x || ::g->m_paninc.y) 703 AM_changeWindowLoc(); 704 705 // Update light level 706 // AM_updateLightLev(); 707 708 } 709 710 711 // 712 // Clear automap frame ::g->buffer. 713 // 714 void AM_clearFB(int color) 715 { 716 memset(::g->fb, color, ::g->f_w*::g->f_h); 717 } 718 719 720 // 721 // Automap clipping of ::g->lines. 722 // 723 // Based on Cohen-Sutherland clipping algorithm but with a slightly 724 // faster reject and precalculated slopes. If the speed is needed, 725 // use a hash algorithm to handle the common cases. 726 // 727 qboolean 728 AM_clipMline 729 ( mline_t* ml, 730 fline_t* fl ) 731 { 732 enum 733 { 734 LEFT =1, 735 RIGHT =2, 736 BOTTOM =4, 737 TOP =8 738 }; 739 740 register int outcode1 = 0; 741 register int outcode2 = 0; 742 register int outside; 743 744 fpoint_t tmp = { 0, 0 }; 745 int dx; 746 int dy; 747 748 749 750 751 // do trivial rejects and outcodes 752 if (ml->a.y > ::g->m_y2) 753 outcode1 = TOP; 754 else if (ml->a.y < ::g->m_y) 755 outcode1 = BOTTOM; 756 757 if (ml->b.y > ::g->m_y2) 758 outcode2 = TOP; 759 else if (ml->b.y < ::g->m_y) 760 outcode2 = BOTTOM; 761 762 if (outcode1 & outcode2) 763 return false; // trivially outside 764 765 if (ml->a.x < ::g->m_x) 766 outcode1 |= LEFT; 767 else if (ml->a.x > ::g->m_x2) 768 outcode1 |= RIGHT; 769 770 if (ml->b.x < ::g->m_x) 771 outcode2 |= LEFT; 772 else if (ml->b.x > ::g->m_x2) 773 outcode2 |= RIGHT; 774 775 if (outcode1 & outcode2) 776 return false; // trivially outside 777 778 // transform to frame-::g->buffer coordinates. 779 fl->a.x = CXMTOF(ml->a.x); 780 fl->a.y = CYMTOF(ml->a.y); 781 fl->b.x = CXMTOF(ml->b.x); 782 fl->b.y = CYMTOF(ml->b.y); 783 784 DOOUTCODE(outcode1, fl->a.x, fl->a.y); 785 DOOUTCODE(outcode2, fl->b.x, fl->b.y); 786 787 if (outcode1 & outcode2) 788 return false; 789 790 while (outcode1 | outcode2) 791 { 792 // may be partially inside box 793 // find an outside point 794 if (outcode1) 795 outside = outcode1; 796 else 797 outside = outcode2; 798 799 // clip to each side 800 if (outside & TOP) 801 { 802 dy = fl->a.y - fl->b.y; 803 dx = fl->b.x - fl->a.x; 804 tmp.x = fl->a.x + (dx*(fl->a.y))/dy; 805 tmp.y = 0; 806 } 807 else if (outside & BOTTOM) 808 { 809 dy = fl->a.y - fl->b.y; 810 dx = fl->b.x - fl->a.x; 811 tmp.x = fl->a.x + (dx*(fl->a.y-::g->f_h))/dy; 812 tmp.y = ::g->f_h-1; 813 } 814 else if (outside & RIGHT) 815 { 816 dy = fl->b.y - fl->a.y; 817 dx = fl->b.x - fl->a.x; 818 tmp.y = fl->a.y + (dy*(::g->f_w-1 - fl->a.x))/dx; 819 tmp.x = ::g->f_w-1; 820 } 821 else if (outside & LEFT) 822 { 823 dy = fl->b.y - fl->a.y; 824 dx = fl->b.x - fl->a.x; 825 tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; 826 tmp.x = 0; 827 } 828 829 if (outside == outcode1) 830 { 831 fl->a = tmp; 832 DOOUTCODE(outcode1, fl->a.x, fl->a.y); 833 } 834 else 835 { 836 fl->b = tmp; 837 DOOUTCODE(outcode2, fl->b.x, fl->b.y); 838 } 839 840 if (outcode1 & outcode2) 841 return false; // trivially outside 842 } 843 844 return true; 845 } 846 #undef DOOUTCODE 847 848 849 // 850 // Classic Bresenham w/ whatever optimizations needed for speed 851 // 852 void 853 AM_drawFline 854 ( fline_t* fl, 855 int color ) 856 { 857 register int x; 858 register int y; 859 register int dx; 860 register int dy; 861 register int sx; 862 register int sy; 863 register int ax; 864 register int ay; 865 register int d; 866 867 static int fuck = 0; 868 869 // For debugging only 870 if ( fl->a.x < 0 || fl->a.x >= ::g->f_w 871 || fl->a.y < 0 || fl->a.y >= ::g->f_h 872 || fl->b.x < 0 || fl->b.x >= ::g->f_w 873 || fl->b.y < 0 || fl->b.y >= ::g->f_h) 874 { 875 I_PrintfE("fuck %d \r", fuck++); 876 return; 877 } 878 879 880 dx = fl->b.x - fl->a.x; 881 ax = 2 * (dx<0 ? -dx : dx); 882 sx = dx<0 ? -1 : 1; 883 884 dy = fl->b.y - fl->a.y; 885 ay = 2 * (dy<0 ? -dy : dy); 886 sy = dy<0 ? -1 : 1; 887 888 x = fl->a.x; 889 y = fl->a.y; 890 891 if (ax > ay) 892 { 893 d = ay - ax/2; 894 while (1) 895 { 896 PUTDOT(x,y,color); 897 if (x == fl->b.x) return; 898 if (d>=0) 899 { 900 y += sy; 901 d -= ax; 902 } 903 x += sx; 904 d += ay; 905 } 906 } 907 else 908 { 909 d = ax - ay/2; 910 while (1) 911 { 912 PUTDOT(x, y, color); 913 if (y == fl->b.y) return; 914 if (d >= 0) 915 { 916 x += sx; 917 d -= ay; 918 } 919 y += sy; 920 d += ax; 921 } 922 } 923 } 924 925 926 // 927 // Clip ::g->lines, draw visible part sof ::g->lines. 928 // 929 void 930 AM_drawMline 931 ( mline_t* ml, 932 int color ) 933 { 934 static fline_t fl; 935 936 if (AM_clipMline(ml, &fl)) 937 AM_drawFline(&fl, color); // draws it on frame ::g->buffer using ::g->fb coords 938 } 939 940 941 942 // 943 // Draws flat (floor/ceiling tile) aligned ::g->grid ::g->lines. 944 // 945 void AM_drawGrid(int color) 946 { 947 fixed_t x, y; 948 fixed_t start, end; 949 mline_t ml; 950 951 // Figure out start of vertical gridlines 952 start = ::g->m_x; 953 if ((start-::g->bmaporgx)%(MAPBLOCKUNITS<<FRACBITS)) 954 start += (MAPBLOCKUNITS<<FRACBITS) 955 - ((start-::g->bmaporgx)%(MAPBLOCKUNITS<<FRACBITS)); 956 end = ::g->m_x + ::g->m_w; 957 958 // draw vertical gridlines 959 ml.a.y = ::g->m_y; 960 ml.b.y = ::g->m_y+::g->m_h; 961 for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS)) 962 { 963 ml.a.x = x; 964 ml.b.x = x; 965 AM_drawMline(&ml, color); 966 } 967 968 // Figure out start of horizontal gridlines 969 start = ::g->m_y; 970 if ((start-::g->bmaporgy)%(MAPBLOCKUNITS<<FRACBITS)) 971 start += (MAPBLOCKUNITS<<FRACBITS) 972 - ((start-::g->bmaporgy)%(MAPBLOCKUNITS<<FRACBITS)); 973 end = ::g->m_y + ::g->m_h; 974 975 // draw horizontal gridlines 976 ml.a.x = ::g->m_x; 977 ml.b.x = ::g->m_x + ::g->m_w; 978 for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS)) 979 { 980 ml.a.y = y; 981 ml.b.y = y; 982 AM_drawMline(&ml, color); 983 } 984 985 } 986 987 // 988 // Determines visible ::g->lines, draws them. 989 // This is LineDef based, not LineSeg based. 990 // 991 void AM_drawWalls(void) 992 { 993 int i; 994 static mline_t l; 995 996 for (i = 0; i < ::g->numlines; i++) 997 { 998 l.a.x = ::g->lines[i].v1->x; 999 l.a.y = ::g->lines[i].v1->y; 1000 l.b.x = ::g->lines[i].v2->x; 1001 l.b.y = ::g->lines[i].v2->y; 1002 if (::g->cheating || (::g->lines[i].flags & ML_MAPPED)) 1003 { 1004 if ((::g->lines[i].flags & LINE_NEVERSEE) && !::g->cheating) 1005 continue; 1006 if (!::g->lines[i].backsector) 1007 { 1008 AM_drawMline(&l, WALLCOLORS+::g->lightlev); 1009 } 1010 else 1011 { 1012 if (::g->lines[i].special == 39) 1013 { // teleporters 1014 AM_drawMline(&l, WALLCOLORS+WALLRANGE/2); 1015 } 1016 else if (::g->lines[i].flags & ML_SECRET) // secret door 1017 { 1018 if (::g->cheating) AM_drawMline(&l, SECRETWALLCOLORS + ::g->lightlev); 1019 else AM_drawMline(&l, WALLCOLORS+::g->lightlev); 1020 } 1021 else if (::g->lines[i].backsector->floorheight 1022 != ::g->lines[i].frontsector->floorheight) { 1023 AM_drawMline(&l, FDWALLCOLORS + ::g->lightlev); // floor level change 1024 } 1025 else if (::g->lines[i].backsector->ceilingheight 1026 != ::g->lines[i].frontsector->ceilingheight) { 1027 AM_drawMline(&l, CDWALLCOLORS+::g->lightlev); // ceiling level change 1028 } 1029 else if (::g->cheating) { 1030 AM_drawMline(&l, TSWALLCOLORS+::g->lightlev); 1031 } 1032 } 1033 } 1034 else if (::g->amap_plr->powers[pw_allmap]) 1035 { 1036 if (!(::g->lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3); 1037 } 1038 } 1039 } 1040 1041 1042 // 1043 // Rotation in 2D. 1044 // Used to rotate player arrow line character. 1045 // 1046 void 1047 AM_rotate 1048 ( fixed_t* x, 1049 fixed_t* y, 1050 angle_t a ) 1051 { 1052 fixed_t tmpx; 1053 1054 tmpx = 1055 FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT]) 1056 - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]); 1057 1058 *y = 1059 FixedMul(*x,finesine[a>>ANGLETOFINESHIFT]) 1060 + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]); 1061 1062 *x = tmpx; 1063 } 1064 1065 void 1066 AM_drawLineCharacter 1067 ( mline_t* lineguy, 1068 int lineguylines, 1069 fixed_t scale, 1070 angle_t angle, 1071 int color, 1072 fixed_t x, 1073 fixed_t y ) 1074 { 1075 int i; 1076 mline_t l; 1077 1078 for (i=0;i<lineguylines;i++) 1079 { 1080 l.a.x = lineguy[i].a.x; 1081 l.a.y = lineguy[i].a.y; 1082 1083 if (scale) 1084 { 1085 l.a.x = FixedMul(scale, l.a.x); 1086 l.a.y = FixedMul(scale, l.a.y); 1087 } 1088 1089 if (angle) 1090 AM_rotate(&l.a.x, &l.a.y, angle); 1091 1092 l.a.x += x; 1093 l.a.y += y; 1094 1095 l.b.x = lineguy[i].b.x; 1096 l.b.y = lineguy[i].b.y; 1097 1098 if (scale) 1099 { 1100 l.b.x = FixedMul(scale, l.b.x); 1101 l.b.y = FixedMul(scale, l.b.y); 1102 } 1103 1104 if (angle) 1105 AM_rotate(&l.b.x, &l.b.y, angle); 1106 1107 l.b.x += x; 1108 l.b.y += y; 1109 1110 AM_drawMline(&l, color); 1111 } 1112 } 1113 1114 void AM_drawPlayers(void) 1115 { 1116 int i; 1117 player_t* p; 1118 static int their_colors[] = { GREENS, GRAYS, BROWNS, REDS }; 1119 int their_color = -1; 1120 int color; 1121 1122 if (!::g->netgame) 1123 { 1124 if (::g->cheating) 1125 AM_drawLineCharacter 1126 (cheat_player_arrow, NUMCHEATPLYRLINES, 0, 1127 ::g->amap_plr->mo->angle, WHITE, ::g->amap_plr->mo->x, ::g->amap_plr->mo->y); 1128 else 1129 AM_drawLineCharacter 1130 (player_arrow, NUMPLYRLINES, 0, ::g->amap_plr->mo->angle, 1131 WHITE, ::g->amap_plr->mo->x, ::g->amap_plr->mo->y); 1132 return; 1133 } 1134 1135 for (i=0;i<MAXPLAYERS;i++) 1136 { 1137 their_color++; 1138 p = &::g->players[i]; 1139 1140 if ( (::g->deathmatch && !::g->singledemo) && p != ::g->amap_plr) 1141 continue; 1142 1143 if (!::g->playeringame[i]) 1144 continue; 1145 1146 if (p->powers[pw_invisibility]) 1147 color = 246; // *close* to black 1148 else 1149 color = their_colors[their_color]; 1150 1151 AM_drawLineCharacter 1152 (player_arrow, NUMPLYRLINES, 0, p->mo->angle, 1153 color, p->mo->x, p->mo->y); 1154 } 1155 1156 } 1157 1158 void 1159 AM_drawThings 1160 ( int colors, 1161 int colorrange) 1162 { 1163 int i; 1164 mobj_t* t; 1165 1166 for (i = 0; i < ::g->numsectors; i++) 1167 { 1168 t = ::g->sectors[i].thinglist; 1169 while (t) 1170 { 1171 AM_drawLineCharacter 1172 (thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 1173 16<<FRACBITS, t->angle, colors+::g->lightlev, t->x, t->y); 1174 t = t->snext; 1175 } 1176 } 1177 } 1178 1179 void AM_drawMarks(void) 1180 { 1181 int i, fx, fy, w, h; 1182 1183 for (i=0;i<AM_NUMMARKPOINTS;i++) 1184 { 1185 if (::g->markpoints[i].x != -1) 1186 { 1187 // w = SHORT(::g->marknums[i]->width); 1188 // h = SHORT(::g->marknums[i]->height); 1189 w = 5; // because something's wrong with the wad, i guess 1190 h = 6; // because something's wrong with the wad, i guess 1191 fx = CXMTOF(::g->markpoints[i].x); 1192 fy = CYMTOF(::g->markpoints[i].y); 1193 if (fx >= ::g->f_x && fx <= ::g->f_w - w && fy >= ::g->f_y && fy <= ::g->f_h - h) 1194 V_DrawPatch(fx/GLOBAL_IMAGE_SCALER, fy/GLOBAL_IMAGE_SCALER, FB, ::g->marknums[i]); 1195 } 1196 } 1197 1198 } 1199 1200 void AM_drawCrosshair(int color) 1201 { 1202 ::g->fb[(::g->f_w*(::g->f_h+1))/2] = color; // single point for now 1203 1204 } 1205 1206 void AM_Drawer (void) 1207 { 1208 if (!::g->automapactive) return; 1209 1210 AM_clearFB(BACKGROUND); 1211 if (::g->grid) 1212 AM_drawGrid(GRIDCOLORS); 1213 AM_drawWalls(); 1214 AM_drawPlayers(); 1215 if (::g->cheating==2) 1216 AM_drawThings(THINGCOLORS, THINGRANGE); 1217 AM_drawCrosshair(XHAIRCOLORS); 1218 1219 AM_drawMarks(); 1220 1221 V_MarkRect(::g->f_x, ::g->f_y, ::g->f_w, ::g->f_h); 1222 1223 } 1224