A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 3250 lines 97 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 * -Loads and initializes texture and flat animation sequences 29 * -Implements utility functions for all linedef/sector special handlers 30 * -Dispatches walkover and gun line triggers 31 * -Initializes and implements special sector types 32 * -Implements donut linedef triggers 33 * -Initializes and implements BOOM linedef triggers for 34 * Scrollers/Conveyors 35 * Friction 36 * Wind/Current 37 * 38 *-----------------------------------------------------------------------------*/ 39 40#include "doomstat.h" 41#include "p_spec.h" 42#include "p_tick.h" 43#include "p_setup.h" 44#include "m_random.h" 45#include "d_englsh.h" 46#include "m_argv.h" 47#include "w_wad.h" 48#include "r_main.h" 49#include "p_maputl.h" 50#include "p_map.h" 51#include "g_game.h" 52#include "p_inter.h" 53#include "m_swap.h" 54#include "s_sound.h" 55#include "sounds.h" 56#include "m_bbox.h" // phares 3/20/98 57#include "d_deh.h" 58#include "r_plane.h" 59#include "i_system.h" 60#include "rockmacros.h" 61// 62// Animating textures and planes 63// There is another anim_t used in wi_stuff, unrelated. 64// 65typedef struct 66{ 67 boolean istexture; 68 int picnum; 69 int basepic; 70 int numpics; 71 int speed; 72 73} anim_t; 74 75// 76// source animation definition 77// 78// 79#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC 80#pragma pack(push) 81#pragma pack(1) 82#endif //_MSC_VER 83 84#if defined(__MWERKS__) 85#pragma options align=packed 86#endif 87 88typedef struct 89{ 90 signed char istexture; //jff 3/23/98 make char for comparison // cph - make signed 91 char endname[9]; // if false, it is a flat 92 char startname[9]; 93 int speed; 94} PACKEDATTR animdef_t; //jff 3/23/98 pack to read from memory 95 96#define MAXANIMS 32 // no longer a strict limit -- killough 97 98anim_t* lastanim; 99 anim_t* anims; // new structure w/o limits -- killough 100static size_t maxanims; 101 102// killough 3/7/98: Initialize generalized scrolling 103static void P_SpawnScrollers(void); 104 105static void P_SpawnFriction(void); // phares 3/16/98 106static void P_SpawnPushers(void); // phares 3/20/98 107 108extern int allow_pushers; 109extern int variable_friction; // phares 3/20/98 110 111// 112// P_InitPicAnims 113// 114// Load the table of animation definitions, checking for existence of 115// the start and end of each frame. If the start doesn't exist the sequence 116// is skipped, if the last doesn't exist, BOOM exits. 117// 118// Wall/Flat animation sequences, defined by name of first and last frame, 119// The full animation sequence is given using all lumps between the start 120// and end entry, in the order found in the WAD file. 121// 122// This routine modified to read its data from a predefined lump or 123// PWAD lump called ANIMATED rather than a static table in this module to 124// allow wad designers to insert or modify animation sequences. 125// 126// Lump format is an array of byte packed animdef_t structures, terminated 127// by a structure with istexture == -1. The lump can be generated from a 128// text source file using SWANTBLS.EXE, distributed with the BOOM utils. 129// The standard list of switches and animations is contained in the example 130// source text file DEFSWANI.DAT also in the BOOM util distribution. 131// 132// 133void P_InitPicAnims (void) 134{ 135 int i; 136 const animdef_t *animdefs; //jff 3/23/98 pointer to animation lump 137 int lump = W_GetNumForName("ANIMATED"); // cph - new wad lump handling 138 // Init animation 139 140 //jff 3/23/98 read from predefined or wad lump instead of table 141 animdefs = (const animdef_t *)W_CacheLumpNum(lump); 142 143 lastanim = anims; 144 for (i=0 ; animdefs[i].istexture != -1 ; i++) 145 { 146 // 1/11/98 killough -- removed limit by array-doubling 147 if (lastanim >= anims + maxanims) 148 { 149 size_t newmax = maxanims ? maxanims*2 : MAXANIMS; 150 anims = realloc(anims, newmax*sizeof(*anims)); // killough 151 lastanim = anims + maxanims; 152 maxanims = newmax; 153 } 154 155 if (animdefs[i].istexture) 156 { 157 // different episode ? 158 if (R_CheckTextureNumForName(animdefs[i].startname) == -1) 159 continue; 160 161 lastanim->picnum = R_TextureNumForName (animdefs[i].endname); 162 lastanim->basepic = R_TextureNumForName (animdefs[i].startname); 163 } 164 else 165 { 166 if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98 167 continue; 168 169 lastanim->picnum = R_FlatNumForName (animdefs[i].endname); 170 lastanim->basepic = R_FlatNumForName (animdefs[i].startname); 171 } 172 173 lastanim->istexture = animdefs[i].istexture; 174 lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; 175 176 if (lastanim->numpics < 2) 177 I_Error ("P_InitPicAnims: bad cycle from %s to %s", 178 animdefs[i].startname, 179 animdefs[i].endname); 180 181 lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG() 182 lastanim++; 183 } 184 W_UnlockLumpNum(lump); 185} 186 187/////////////////////////////////////////////////////////////// 188// 189// Linedef and Sector Special Implementation Utility Functions 190// 191/////////////////////////////////////////////////////////////// 192 193// 194// getSide() 195// 196// Will return a side_t* 197// given the number of the current sector, 198// the line number, and the side (0/1) that you want. 199// 200// Note: if side=1 is specified, it must exist or results undefined 201// 202side_t* getSide 203( int currentSector, 204 int line, 205 int side ) 206{ 207 return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; 208} 209 210 211// 212// getSector() 213// 214// Will return a sector_t* 215// given the number of the current sector, 216// the line number and the side (0/1) that you want. 217// 218// Note: if side=1 is specified, it must exist or results undefined 219// 220sector_t* getSector 221( int currentSector, 222 int line, 223 int side ) 224{ 225 return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; 226} 227 228 229// 230// twoSided() 231// 232// Given the sector number and the line number, 233// it will tell you whether the line is two-sided or not. 234// 235// modified to return actual two-sidedness rather than presence 236// of 2S flag unless compatibility optioned 237// 238int twoSided 239( int sector, 240 int line ) 241{ 242 //jff 1/26/98 return what is actually needed, whether the line 243 //has two sidedefs, rather than whether the 2S flag is set 244 245 return comp[comp_model] ? 246 (sectors[sector].lines[line])->flags & ML_TWOSIDED 247 : 248 (sectors[sector].lines[line])->sidenum[1] != -1; 249} 250 251 252// 253// getNextSector() 254// 255// Return sector_t * of sector next to current across line. 256// 257// Note: returns NULL if not two-sided line, or both sides refer to sector 258// 259sector_t* getNextSector 260( line_t* line, 261 sector_t* sec ) 262{ 263 //jff 1/26/98 check unneeded since line->backsector already 264 //returns NULL if the line is not two sided, and does so from 265 //the actual two-sidedness of the line, rather than its 2S flag 266 267 if (comp[comp_model]) 268 { 269 if (!(line->flags & ML_TWOSIDED)) 270 return NULL; 271 } 272 273 if (line->frontsector == sec) { 274 if (comp[comp_model] || line->backsector!=sec) 275 return line->backsector; //jff 5/3/98 don't retn sec unless compatibility 276 else // fixes an intra-sector line breaking functions 277 return NULL; // like floor->highest floor 278 } 279 return line->frontsector; 280} 281 282 283// 284// P_FindLowestFloorSurrounding() 285// 286// Returns the fixed point value of the lowest floor height 287// in the sector passed or its surrounding sectors. 288// 289fixed_t P_FindLowestFloorSurrounding(sector_t* sec) 290{ 291 int i; 292 line_t* check; 293 sector_t* other; 294 fixed_t floor = sec->floorheight; 295 296 for (i=0 ;i < sec->linecount ; i++) 297 { 298 check = sec->lines[i]; 299 other = getNextSector(check,sec); 300 301 if (!other) 302 continue; 303 304 if (other->floorheight < floor) 305 floor = other->floorheight; 306 } 307 return floor; 308} 309 310 311// 312// P_FindHighestFloorSurrounding() 313// 314// Passed a sector, returns the fixed point value of the largest 315// floor height in the surrounding sectors, not including that passed 316// 317// NOTE: if no surrounding sector exists -32000*FRACUINT is returned 318// if compatibility then -500*FRACUNIT is the smallest return possible 319// 320fixed_t P_FindHighestFloorSurrounding(sector_t *sec) 321{ 322 int i; 323 line_t* check; 324 sector_t* other; 325 fixed_t floor = -500*FRACUNIT; 326 327 //jff 1/26/98 Fix initial value for floor to not act differently 328 //in sections of wad that are below -500 units 329 if (!comp[comp_model]) /* jff 3/12/98 avoid ovf */ 330 floor = -32000*FRACUNIT; // in height calculations 331 332 for (i=0 ;i < sec->linecount ; i++) 333 { 334 check = sec->lines[i]; 335 other = getNextSector(check,sec); 336 337 if (!other) 338 continue; 339 340 if (other->floorheight > floor) 341 floor = other->floorheight; 342 } 343 return floor; 344} 345 346 347// 348// P_FindNextHighestFloor() 349// 350// Passed a sector and a floor height, returns the fixed point value 351// of the smallest floor height in a surrounding sector larger than 352// the floor height passed. If no such height exists the floorheight 353// passed is returned. 354// 355// Rewritten by Lee Killough to avoid fixed array and to be faster 356// 357fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight) 358{ 359 sector_t *other; 360 int i; 361 362 for (i=0 ;i < sec->linecount ; i++) 363 if ((other = getNextSector(sec->lines[i],sec)) && 364 other->floorheight > currentheight) 365 { 366 int height = other->floorheight; 367 while (++i < sec->linecount) 368 if ((other = getNextSector(sec->lines[i],sec)) && 369 other->floorheight < height && 370 other->floorheight > currentheight) 371 height = other->floorheight; 372 return height; 373 } 374 return currentheight; 375} 376 377 378// 379// P_FindNextLowestFloor() 380// 381// Passed a sector and a floor height, returns the fixed point value 382// of the largest floor height in a surrounding sector smaller than 383// the floor height passed. If no such height exists the floorheight 384// passed is returned. 385// 386// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this 387// 388fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight) 389{ 390 sector_t *other; 391 int i; 392 393 for (i=0 ;i < sec->linecount ; i++) 394 if ((other = getNextSector(sec->lines[i],sec)) && 395 other->floorheight < currentheight) 396 { 397 int height = other->floorheight; 398 while (++i < sec->linecount) 399 if ((other = getNextSector(sec->lines[i],sec)) && 400 other->floorheight > height && 401 other->floorheight < currentheight) 402 height = other->floorheight; 403 return height; 404 } 405 return currentheight; 406} 407 408 409// 410// P_FindNextLowestCeiling() 411// 412// Passed a sector and a ceiling height, returns the fixed point value 413// of the largest ceiling height in a surrounding sector smaller than 414// the ceiling height passed. If no such height exists the ceiling height 415// passed is returned. 416// 417// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this 418// 419fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight) 420{ 421 sector_t *other; 422 int i; 423 424 for (i=0 ;i < sec->linecount ; i++) 425 if ((other = getNextSector(sec->lines[i],sec)) && 426 other->ceilingheight < currentheight) 427 { 428 int height = other->ceilingheight; 429 while (++i < sec->linecount) 430 if ((other = getNextSector(sec->lines[i],sec)) && 431 other->ceilingheight > height && 432 other->ceilingheight < currentheight) 433 height = other->ceilingheight; 434 return height; 435 } 436 return currentheight; 437} 438 439 440// 441// P_FindNextHighestCeiling() 442// 443// Passed a sector and a ceiling height, returns the fixed point value 444// of the smallest ceiling height in a surrounding sector larger than 445// the ceiling height passed. If no such height exists the ceiling height 446// passed is returned. 447// 448// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this 449// 450fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight) 451{ 452 sector_t *other; 453 int i; 454 455 for (i=0 ;i < sec->linecount ; i++) 456 if ((other = getNextSector(sec->lines[i],sec)) && 457 other->ceilingheight > currentheight) 458 { 459 int height = other->ceilingheight; 460 while (++i < sec->linecount) 461 if ((other = getNextSector(sec->lines[i],sec)) && 462 other->ceilingheight < height && 463 other->ceilingheight > currentheight) 464 height = other->ceilingheight; 465 return height; 466 } 467 return currentheight; 468} 469 470 471// 472// P_FindLowestCeilingSurrounding() 473// 474// Passed a sector, returns the fixed point value of the smallest 475// ceiling height in the surrounding sectors, not including that passed 476// 477// NOTE: if no surrounding sector exists 32000*FRACUINT is returned 478// but if compatibility then INT_MAX is the return 479// 480fixed_t P_FindLowestCeilingSurrounding(sector_t* sec) 481{ 482 int i; 483 line_t* check; 484 sector_t* other; 485 fixed_t height = INT_MAX; 486 487 /* jff 3/12/98 avoid ovf in height calculations */ 488 if (!comp[comp_model]) height = 32000*FRACUNIT; 489 490 for (i=0 ;i < sec->linecount ; i++) 491 { 492 check = sec->lines[i]; 493 other = getNextSector(check,sec); 494 495 if (!other) 496 continue; 497 498 if (other->ceilingheight < height) 499 height = other->ceilingheight; 500 } 501 return height; 502} 503 504 505// 506// P_FindHighestCeilingSurrounding() 507// 508// Passed a sector, returns the fixed point value of the largest 509// ceiling height in the surrounding sectors, not including that passed 510// 511// NOTE: if no surrounding sector exists -32000*FRACUINT is returned 512// but if compatibility then 0 is the smallest return possible 513// 514fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) 515{ 516 int i; 517 line_t* check; 518 sector_t* other; 519 fixed_t height = 0; 520 521 /* jff 1/26/98 Fix initial value for floor to not act differently 522 * in sections of wad that are below 0 units 523 * jff 3/12/98 avoid ovf in height calculations */ 524 if (!comp[comp_model]) height = -32000*FRACUNIT; 525 526 for (i=0 ;i < sec->linecount ; i++) 527 { 528 check = sec->lines[i]; 529 other = getNextSector(check,sec); 530 531 if (!other) 532 continue; 533 534 if (other->ceilingheight > height) 535 height = other->ceilingheight; 536 } 537 return height; 538} 539 540 541// 542// P_FindShortestTextureAround() 543// 544// Passed a sector number, returns the shortest lower texture on a 545// linedef bounding the sector. 546// 547// Note: If no lower texture exists 32000*FRACUNIT is returned. 548// but if compatibility then INT_MAX is returned 549// 550// jff 02/03/98 Add routine to find shortest lower texture 551// 552fixed_t P_FindShortestTextureAround(int secnum) 553{ 554 int minsize = INT_MAX; 555 side_t* side; 556 int i; 557 sector_t *sec = &sectors[secnum]; 558 559 if (!comp[comp_model]) 560 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow in height calcs 561 562 for (i = 0; i < sec->linecount; i++) 563 { 564 if (twoSided(secnum, i)) 565 { 566 side = getSide(secnum,i,0); 567 if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder 568 if (textureheight[side->bottomtexture] < minsize) 569 minsize = textureheight[side->bottomtexture]; 570 side = getSide(secnum,i,1); 571 if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder 572 if (textureheight[side->bottomtexture] < minsize) 573 minsize = textureheight[side->bottomtexture]; 574 } 575 } 576 return minsize; 577} 578 579 580// 581// P_FindShortestUpperAround() 582// 583// Passed a sector number, returns the shortest upper texture on a 584// linedef bounding the sector. 585// 586// Note: If no upper texture exists 32000*FRACUNIT is returned. 587// but if compatibility then INT_MAX is returned 588// 589// jff 03/20/98 Add routine to find shortest upper texture 590// 591fixed_t P_FindShortestUpperAround(int secnum) 592{ 593 int minsize = INT_MAX; 594 side_t* side; 595 int i; 596 sector_t *sec = &sectors[secnum]; 597 598 if (!comp[comp_model]) 599 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow 600 // in height calcs 601 for (i = 0; i < sec->linecount; i++) 602 { 603 if (twoSided(secnum, i)) 604 { 605 side = getSide(secnum,i,0); 606 if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder 607 if (textureheight[side->toptexture] < minsize) 608 minsize = textureheight[side->toptexture]; 609 side = getSide(secnum,i,1); 610 if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder 611 if (textureheight[side->toptexture] < minsize) 612 minsize = textureheight[side->toptexture]; 613 } 614 } 615 return minsize; 616} 617 618 619// 620// P_FindModelFloorSector() 621// 622// Passed a floor height and a sector number, return a pointer to a 623// a sector with that floor height across the lowest numbered two sided 624// line surrounding the sector. 625// 626// Note: If no sector at that height bounds the sector passed, return NULL 627// 628// jff 02/03/98 Add routine to find numeric model floor 629// around a sector specified by sector number 630// jff 3/14/98 change first parameter to plain height to allow call 631// from routine not using floormove_t 632// 633sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum) 634{ 635 int i; 636 sector_t *sec=NULL; 637 int linecount; 638 639 sec = &sectors[secnum]; //jff 3/2/98 woops! better do this 640 //jff 5/23/98 don't disturb sec->linecount while searching 641 // but allow early exit in old demos 642 linecount = sec->linecount; 643 for (i = 0; i < (demo_compatibility && sec->linecount<linecount? 644 sec->linecount : linecount); i++) 645 { 646 if ( twoSided(secnum, i) ) 647 { 648 if (getSide(secnum,i,0)->sector-sectors == secnum) 649 sec = getSector(secnum,i,1); 650 else 651 sec = getSector(secnum,i,0); 652 653 if (sec->floorheight == floordestheight) 654 return sec; 655 } 656 } 657 return NULL; 658} 659 660 661// 662// P_FindModelCeilingSector() 663// 664// Passed a ceiling height and a sector number, return a pointer to a 665// a sector with that ceiling height across the lowest numbered two sided 666// line surrounding the sector. 667// 668// Note: If no sector at that height bounds the sector passed, return NULL 669// 670// jff 02/03/98 Add routine to find numeric model ceiling 671// around a sector specified by sector number 672// used only from generalized ceiling types 673// jff 3/14/98 change first parameter to plain height to allow call 674// from routine not using ceiling_t 675// 676sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum) 677{ 678 int i; 679 sector_t *sec=NULL; 680 int linecount; 681 682 sec = &sectors[secnum]; //jff 3/2/98 woops! better do this 683 //jff 5/23/98 don't disturb sec->linecount while searching 684 // but allow early exit in old demos 685 linecount = sec->linecount; 686 for (i = 0; i < (demo_compatibility && sec->linecount<linecount? 687 sec->linecount : linecount); i++) 688 { 689 if ( twoSided(secnum, i) ) 690 { 691 if (getSide(secnum,i,0)->sector-sectors == secnum) 692 sec = getSector(secnum,i,1); 693 else 694 sec = getSector(secnum,i,0); 695 696 if (sec->ceilingheight == ceildestheight) 697 return sec; 698 } 699 } 700 return NULL; 701} 702 703// 704// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO 705// 706 707// Find the next sector with the same tag as a linedef. 708// Rewritten by Lee Killough to use chained hashing to improve speed 709 710int P_FindSectorFromLineTag(const line_t *line, int start) 711{ 712 start = start >= 0 ? sectors[start].nexttag : 713 sectors[(unsigned) line->tag % (unsigned) numsectors].firsttag; 714 while (start >= 0 && sectors[start].tag != line->tag) 715 start = sectors[start].nexttag; 716 return start; 717} 718 719// killough 4/16/98: Same thing, only for linedefs 720 721int P_FindLineFromLineTag(const line_t *line, int start) 722{ 723 start = start >= 0 ? lines[start].nexttag : 724 lines[(unsigned) line->tag % (unsigned) numlines].firsttag; 725 while (start >= 0 && lines[start].tag != line->tag) 726 start = lines[start].nexttag; 727 return start; 728} 729 730// Hash the sector tags across the sectors and linedefs. 731static void P_InitTagLists(void) 732{ 733 register int i; 734 735 for (i=numsectors; --i>=0; ) // Initially make all slots empty. 736 sectors[i].firsttag = -1; 737 for (i=numsectors; --i>=0; ) // Proceed from last to first sector 738 { // so that lower sectors appear first 739 int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func 740 sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain 741 sectors[j].firsttag = i; 742 } 743 744 // killough 4/17/98: same thing, only for linedefs 745 746 for (i=numlines; --i>=0; ) // Initially make all slots empty. 747 lines[i].firsttag = -1; 748 for (i=numlines; --i>=0; ) // Proceed from last to first linedef 749 { // so that lower linedefs appear first 750 int j = (unsigned) lines[i].tag % (unsigned) numlines; // Hash func 751 lines[i].nexttag = lines[j].firsttag; // Prepend linedef to chain 752 lines[j].firsttag = i; 753 } 754} 755 756// 757// P_FindMinSurroundingLight() 758// 759// Passed a sector and a light level, returns the smallest light level 760// in a surrounding sector less than that passed. If no smaller light 761// level exists, the light level passed is returned. 762// 763int P_FindMinSurroundingLight 764( sector_t* sector, 765 int max ) 766{ 767 int i; 768 int min; 769 line_t* line; 770 sector_t* check; 771 772 min = max; 773 for (i=0 ; i < sector->linecount ; i++) 774 { 775 line = sector->lines[i]; 776 check = getNextSector(line,sector); 777 778 if (!check) 779 continue; 780 781 if (check->lightlevel < min) 782 min = check->lightlevel; 783 } 784 return min; 785} 786 787 788// 789// P_CanUnlockGenDoor() 790// 791// Passed a generalized locked door linedef and a player, returns whether 792// the player has the keys necessary to unlock that door. 793// 794// Note: The linedef passed MUST be a generalized locked door type 795// or results are undefined. 796// 797// jff 02/05/98 routine added to test for unlockability of 798// generalized locked doors 799// 800boolean P_CanUnlockGenDoor 801( line_t* line, 802 player_t* player) 803{ 804 // does this line special distinguish between skulls and keys? 805 int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift; 806 807 // determine for each case of lock type if player's keys are adequate 808 switch((line->special & LockedKey)>>LockedKeyShift) 809 { 810 case AnyKey: 811 if 812 ( 813 !player->cards[it_redcard] && 814 !player->cards[it_redskull] && 815 !player->cards[it_bluecard] && 816 !player->cards[it_blueskull] && 817 !player->cards[it_yellowcard] && 818 !player->cards[it_yellowskull] 819 ) 820 { 821 player->message = s_PD_ANY; // Ty 03/27/98 - externalized 822 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 823 return false; 824 } 825 break; 826 case RCard: 827 if 828 ( 829 !player->cards[it_redcard] && 830 (!skulliscard || !player->cards[it_redskull]) 831 ) 832 { 833 player->message = skulliscard? s_PD_REDK : s_PD_REDC; // Ty 03/27/98 - externalized 834 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 835 return false; 836 } 837 break; 838 case BCard: 839 if 840 ( 841 !player->cards[it_bluecard] && 842 (!skulliscard || !player->cards[it_blueskull]) 843 ) 844 { 845 player->message = skulliscard? s_PD_BLUEK : s_PD_BLUEC; // Ty 03/27/98 - externalized 846 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 847 return false; 848 } 849 break; 850 case YCard: 851 if 852 ( 853 !player->cards[it_yellowcard] && 854 (!skulliscard || !player->cards[it_yellowskull]) 855 ) 856 { 857 player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWC; // Ty 03/27/98 - externalized 858 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 859 return false; 860 } 861 break; 862 case RSkull: 863 if 864 ( 865 !player->cards[it_redskull] && 866 (!skulliscard || !player->cards[it_redcard]) 867 ) 868 { 869 player->message = skulliscard? s_PD_REDK : s_PD_REDS; // Ty 03/27/98 - externalized 870 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 871 return false; 872 } 873 break; 874 case BSkull: 875 if 876 ( 877 !player->cards[it_blueskull] && 878 (!skulliscard || !player->cards[it_bluecard]) 879 ) 880 { 881 player->message = skulliscard? s_PD_BLUEK : s_PD_BLUES; // Ty 03/27/98 - externalized 882 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 883 return false; 884 } 885 break; 886 case YSkull: 887 if 888 ( 889 !player->cards[it_yellowskull] && 890 (!skulliscard || !player->cards[it_yellowcard]) 891 ) 892 { 893 player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWS; // Ty 03/27/98 - externalized 894 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 895 return false; 896 } 897 break; 898 case AllKeys: 899 if 900 ( 901 !skulliscard && 902 ( 903 !player->cards[it_redcard] || 904 !player->cards[it_redskull] || 905 !player->cards[it_bluecard] || 906 !player->cards[it_blueskull] || 907 !player->cards[it_yellowcard] || 908 !player->cards[it_yellowskull] 909 ) 910 ) 911 { 912 player->message = s_PD_ALL6; // Ty 03/27/98 - externalized 913 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 914 return false; 915 } 916 if 917 ( 918 skulliscard && 919 ( 920 (!player->cards[it_redcard] && 921 !player->cards[it_redskull]) || 922 (!player->cards[it_bluecard] && 923 !player->cards[it_blueskull]) || 924 (!player->cards[it_yellowcard] && 925 !player->cards[it_yellowskull]) 926 ) 927 ) 928 { 929 player->message = s_PD_ALL3; // Ty 03/27/98 - externalized 930 S_StartSound(player->mo,sfx_oof); // killough 3/20/98 931 return false; 932 } 933 break; 934 } 935 return true; 936} 937 938 939// 940// P_SectorActive() 941// 942// Passed a linedef special class (floor, ceiling, lighting) and a sector 943// returns whether the sector is already busy with a linedef special of the 944// same class. If old demo compatibility true, all linedef special classes 945// are the same. 946// 947// jff 2/23/98 added to prevent old demos from 948// succeeding in starting multiple specials on one sector 949// 950boolean P_SectorActive(special_e t,sector_t *sec) 951{ 952 if (demo_compatibility) // return whether any thinker is active 953 return sec->floordata || sec->ceilingdata || sec->lightingdata; 954 else 955 switch (t) // return whether thinker of same type is active 956 { 957 case floor_special: 958 return (sec->floordata!=NULL); 959 case ceiling_special: 960 return (sec->ceilingdata!=NULL); 961 case lighting_special: 962 return (sec->lightingdata!=NULL); 963 } 964 return true; // don't know which special, must be active, shouldn't be here 965} 966 967 968// 969// P_CheckTag() 970// 971// Passed a line, returns true if the tag is non-zero or the line special 972// allows no tag without harm. If compatibility, all linedef specials are 973// allowed to have zero tag. 974// 975// Note: Only line specials activated by walkover, pushing, or shooting are 976// checked by this routine. 977// 978// jff 2/27/98 Added to check for zero tag allowed for regular special types 979// 980int P_CheckTag(line_t *line) 981{ 982 /* tag not zero, allowed, or 983 * killough 11/98: compatibility option */ 984 if (comp[comp_zerotags] || line->tag) 985 return 1; 986 987 switch(line->special) 988 { 989 case 1: // Manual door specials 990 case 26: 991 case 27: 992 case 28: 993 case 31: 994 case 32: 995 case 33: 996 case 34: 997 case 117: 998 case 118: 999 1000 case 139: // Lighting specials 1001 case 170: 1002 case 79: 1003 case 35: 1004 case 138: 1005 case 171: 1006 case 81: 1007 case 13: 1008 case 192: 1009 case 169: 1010 case 80: 1011 case 12: 1012 case 194: 1013 case 173: 1014 case 157: 1015 case 104: 1016 case 193: 1017 case 172: 1018 case 156: 1019 case 17: 1020 1021 case 195: // Thing teleporters 1022 case 174: 1023 case 97: 1024 case 39: 1025 case 126: 1026 case 125: 1027 case 210: 1028 case 209: 1029 case 208: 1030 case 207: 1031 1032 case 11: // Exits 1033 case 52: 1034 case 197: 1035 case 51: 1036 case 124: 1037 case 198: 1038 1039 case 48: // Scrolling walls 1040 case 85: 1041 return 1; // zero tag allowed 1042 1043 default: 1044 break; 1045 } 1046 return 0; // zero tag not allowed 1047} 1048 1049 1050// 1051// P_IsSecret() 1052// 1053// Passed a sector, returns if the sector secret type is still active, i.e. 1054// secret type is set and the secret has not yet been obtained. 1055// 1056// jff 3/14/98 added to simplify checks for whether sector is secret 1057// in automap and other places 1058// 1059boolean P_IsSecret(sector_t *sec) 1060{ 1061 return (sec->special==9 || (sec->special&SECRET_MASK)); 1062} 1063 1064 1065// 1066// P_WasSecret() 1067// 1068// Passed a sector, returns if the sector secret type is was active, i.e. 1069// secret type was set and the secret has been obtained already. 1070// 1071// jff 3/14/98 added to simplify checks for whether sector is secret 1072// in automap and other places 1073// 1074boolean P_WasSecret(sector_t *sec) 1075{ 1076 return (sec->oldspecial==9 || (sec->oldspecial&SECRET_MASK)); 1077} 1078 1079 1080////////////////////////////////////////////////////////////////////////// 1081// 1082// Events 1083// 1084// Events are operations triggered by using, crossing, 1085// or shooting special lines, or by timed thinkers. 1086// 1087///////////////////////////////////////////////////////////////////////// 1088 1089// 1090// P_CrossSpecialLine - Walkover Trigger Dispatcher 1091// 1092// Called every time a thing origin is about 1093// to cross a line with a non 0 special, whether a walkover type or not. 1094// 1095// jff 02/12/98 all W1 lines were fixed to check the result from the EV_ 1096// function before clearing the special. This avoids losing the function 1097// of the line, should the sector already be active when the line is 1098// crossed. Change is qualified by demo_compatibility. 1099// 1100// CPhipps - take a line_t pointer instead of a line number, as in MBF 1101void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing) 1102{ 1103 int ok; 1104 1105 // Things that should never trigger lines 1106 if (!thing->player) 1107 { 1108 // Things that should NOT trigger specials... 1109 switch(thing->type) 1110 { 1111 case MT_ROCKET: 1112 case MT_PLASMA: 1113 case MT_BFG: 1114 case MT_TROOPSHOT: 1115 case MT_HEADSHOT: 1116 case MT_BRUISERSHOT: 1117 return; 1118 break; 1119 1120 default: break; 1121 } 1122 } 1123 1124 //jff 02/04/98 add check here for generalized lindef types 1125 if (!demo_compatibility) // generalized types not recognized if old demo 1126 { 1127 // pointer to line function is NULL by default, set non-null if 1128 // line special is walkover generalized linedef type 1129 int (*linefunc)(line_t *line)=NULL; 1130 1131 // check each range of generalized linedefs 1132 if ((unsigned)line->special >= GenEnd) 1133 { 1134 // Out of range for GenFloors 1135 } 1136 else if ((unsigned)line->special >= GenFloorBase) 1137 { 1138 if (!thing->player) 1139 if ((line->special & FloorChange) || !(line->special & FloorModel)) 1140 return; // FloorModel is "Allow Monsters" if FloorChange is 0 1141 if (!line->tag) //jff 2/27/98 all walk generalized types require tag 1142 return; 1143 linefunc = EV_DoGenFloor; 1144 } 1145 else if ((unsigned)line->special >= GenCeilingBase) 1146 { 1147 if (!thing->player) 1148 if ((line->special & CeilingChange) || !(line->special & CeilingModel)) 1149 return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 1150 if (!line->tag) //jff 2/27/98 all walk generalized types require tag 1151 return; 1152 linefunc = EV_DoGenCeiling; 1153 } 1154 else if ((unsigned)line->special >= GenDoorBase) 1155 { 1156 if (!thing->player) 1157 { 1158 if (!(line->special & DoorMonster)) 1159 return; // monsters disallowed from this door 1160 if (line->flags & ML_SECRET) // they can't open secret doors either 1161 return; 1162 } 1163 if (!line->tag) //3/2/98 move outside the monster check 1164 return; 1165 linefunc = EV_DoGenDoor; 1166 } 1167 else if ((unsigned)line->special >= GenLockedBase) 1168 { 1169 if (!thing->player) 1170 return; // monsters disallowed from unlocking doors 1171 if (((line->special&TriggerType)==WalkOnce) || ((line->special&TriggerType)==WalkMany)) 1172 { //jff 4/1/98 check for being a walk type before reporting door type 1173 if (!P_CanUnlockGenDoor(line,thing->player)) 1174 return; 1175 } 1176 else 1177 return; 1178 linefunc = EV_DoGenLockedDoor; 1179 } 1180 else if ((unsigned)line->special >= GenLiftBase) 1181 { 1182 if (!thing->player) 1183 if (!(line->special & LiftMonster)) 1184 return; // monsters disallowed 1185 if (!line->tag) //jff 2/27/98 all walk generalized types require tag 1186 return; 1187 linefunc = EV_DoGenLift; 1188 } 1189 else if ((unsigned)line->special >= GenStairsBase) 1190 { 1191 if (!thing->player) 1192 if (!(line->special & StairMonster)) 1193 return; // monsters disallowed 1194 if (!line->tag) //jff 2/27/98 all walk generalized types require tag 1195 return; 1196 linefunc = EV_DoGenStairs; 1197 } 1198 1199 if (linefunc) // if it was a valid generalized type 1200 switch((line->special & TriggerType) >> TriggerTypeShift) 1201 { 1202 case WalkOnce: 1203 if (linefunc(line)) 1204 line->special = 0; // clear special if a walk once type 1205 return; 1206 case WalkMany: 1207 linefunc(line); 1208 return; 1209 default: // if not a walk type, do nothing here 1210 return; 1211 } 1212 } 1213 1214 if (!thing->player) 1215 { 1216 ok = 0; 1217 switch(line->special) 1218 { 1219 case 39: // teleport trigger 1220 case 97: // teleport retrigger 1221 case 125: // teleport monsteronly trigger 1222 case 126: // teleport monsteronly retrigger 1223 case 4: // raise door 1224 case 10: // plat down-wait-up-stay trigger 1225 case 88: // plat down-wait-up-stay retrigger 1226 //jff 3/5/98 add ability of monsters etc. to use teleporters 1227 case 208: //silent thing teleporters 1228 case 207: 1229 case 243: //silent line-line teleporter 1230 case 244: //jff 3/6/98 make fit within DCK's 256 linedef types 1231 case 262: //jff 4/14/98 add monster only 1232 case 263: //jff 4/14/98 silent thing,line,line rev types 1233 case 264: //jff 4/14/98 plus player/monster silent line 1234 case 265: // reversed types 1235 case 266: 1236 case 267: 1237 case 268: 1238 case 269: 1239 ok = 1; 1240 break; 1241 } 1242 if (!ok) 1243 return; 1244 } 1245 1246 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types 1247 return; 1248 1249 // Dispatch on the line special value to the line's action routine 1250 // If a once only function, and successful, clear the line special 1251 1252 switch (line->special) 1253 { 1254 // Regular walk once triggers 1255 1256 case 2: 1257 // Open Door 1258 if (EV_DoDoor(line,p_open) || demo_compatibility) 1259 line->special = 0; 1260 break; 1261 1262 case 3: 1263 // Close Door 1264 if (EV_DoDoor(line,p_close) || demo_compatibility) 1265 line->special = 0; 1266 break; 1267 1268 case 4: 1269 // Raise Door 1270 if (EV_DoDoor(line,normal) || demo_compatibility) 1271 line->special = 0; 1272 break; 1273 1274 case 5: 1275 // Raise Floor 1276 if (EV_DoFloor(line,raiseFloor) || demo_compatibility) 1277 line->special = 0; 1278 break; 1279 1280 case 6: 1281 // Fast Ceiling Crush & Raise 1282 if (EV_DoCeiling(line,fastCrushAndRaise) || demo_compatibility) 1283 line->special = 0; 1284 break; 1285 1286 case 8: 1287 // Build Stairs 1288 if (EV_BuildStairs(line,build8) || demo_compatibility) 1289 line->special = 0; 1290 break; 1291 1292 case 10: 1293 // PlatDownWaitUp 1294 if (EV_DoPlat(line,downWaitUpStay,0) || demo_compatibility) 1295 line->special = 0; 1296 break; 1297 1298 case 12: 1299 // Light Turn On - brightest near 1300 if (EV_LightTurnOn(line,0) || demo_compatibility) 1301 line->special = 0; 1302 break; 1303 1304 case 13: 1305 // Light Turn On 255 1306 if (EV_LightTurnOn(line,255) || demo_compatibility) 1307 line->special = 0; 1308 break; 1309 1310 case 16: 1311 // Close Door 30 1312 if (EV_DoDoor(line,close30ThenOpen) || demo_compatibility) 1313 line->special = 0; 1314 break; 1315 1316 case 17: 1317 // Start Light Strobing 1318 if (EV_StartLightStrobing(line) || demo_compatibility) 1319 line->special = 0; 1320 break; 1321 1322 case 19: 1323 // Lower Floor 1324 if (EV_DoFloor(line,lowerFloor) || demo_compatibility) 1325 line->special = 0; 1326 break; 1327 1328 case 22: 1329 // Raise floor to nearest height and change texture 1330 if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) 1331 line->special = 0; 1332 break; 1333 1334 case 25: 1335 // Ceiling Crush and Raise 1336 if (EV_DoCeiling(line,crushAndRaise) || demo_compatibility) 1337 line->special = 0; 1338 break; 1339 1340 case 30: 1341 // Raise floor to shortest texture height 1342 // on either side of lines. 1343 if (EV_DoFloor(line,raiseToTexture) || demo_compatibility) 1344 line->special = 0; 1345 break; 1346 1347 case 35: 1348 // Lights Very Dark 1349 if (EV_LightTurnOn(line,35) || demo_compatibility) 1350 line->special = 0; 1351 break; 1352 1353 case 36: 1354 // Lower Floor (TURBO) 1355 if (EV_DoFloor(line,turboLower) || demo_compatibility) 1356 line->special = 0; 1357 break; 1358 1359 case 37: 1360 // LowerAndChange 1361 if (EV_DoFloor(line,lowerAndChange) || demo_compatibility) 1362 line->special = 0; 1363 break; 1364 1365 case 38: 1366 // Lower Floor To Lowest 1367 if (EV_DoFloor(line, lowerFloorToLowest) || demo_compatibility) 1368 line->special = 0; 1369 break; 1370 1371 case 39: 1372 // TELEPORT! //jff 02/09/98 fix using up with wrong side crossing 1373 if (EV_Teleport(line, side, thing) || demo_compatibility) 1374 line->special = 0; 1375 break; 1376 1377 case 40: 1378 // RaiseCeilingLowerFloor 1379 if (demo_compatibility) 1380 { 1381 EV_DoCeiling( line, raiseToHighest ); 1382 EV_DoFloor( line, lowerFloorToLowest ); //jff 02/12/98 doesn't work 1383 line->special = 0; 1384 } 1385 else 1386 if (EV_DoCeiling(line, raiseToHighest)) 1387 line->special = 0; 1388 break; 1389 1390 case 44: 1391 // Ceiling Crush 1392 if (EV_DoCeiling(line, lowerAndCrush) || demo_compatibility) 1393 line->special = 0; 1394 break; 1395 1396 case 52: 1397 // EXIT! 1398 // killough 10/98: prevent zombies from exiting levels 1399 if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) 1400 G_ExitLevel (); 1401 break; 1402 1403 case 53: 1404 // Perpetual Platform Raise 1405 if (EV_DoPlat(line,perpetualRaise,0) || demo_compatibility) 1406 line->special = 0; 1407 break; 1408 1409 case 54: 1410 // Platform Stop 1411 if (EV_StopPlat(line) || demo_compatibility) 1412 line->special = 0; 1413 break; 1414 1415 case 56: 1416 // Raise Floor Crush 1417 if (EV_DoFloor(line,raiseFloorCrush) || demo_compatibility) 1418 line->special = 0; 1419 break; 1420 1421 case 57: 1422 // Ceiling Crush Stop 1423 if (EV_CeilingCrushStop(line) || demo_compatibility) 1424 line->special = 0; 1425 break; 1426 1427 case 58: 1428 // Raise Floor 24 1429 if (EV_DoFloor(line,raiseFloor24) || demo_compatibility) 1430 line->special = 0; 1431 break; 1432 1433 case 59: 1434 // Raise Floor 24 And Change 1435 if (EV_DoFloor(line,raiseFloor24AndChange) || demo_compatibility) 1436 line->special = 0; 1437 break; 1438 1439 case 100: 1440 // Build Stairs Turbo 16 1441 if (EV_BuildStairs(line,turbo16) || demo_compatibility) 1442 line->special = 0; 1443 break; 1444 1445 case 104: 1446 // Turn lights off in sector(tag) 1447 if (EV_TurnTagLightsOff(line) || demo_compatibility) 1448 line->special = 0; 1449 break; 1450 1451 case 108: 1452 // Blazing Door Raise (faster than TURBO!) 1453 if (EV_DoDoor(line,blazeRaise) || demo_compatibility) 1454 line->special = 0; 1455 break; 1456 1457 case 109: 1458 // Blazing Door Open (faster than TURBO!) 1459 if (EV_DoDoor (line,blazeOpen) || demo_compatibility) 1460 line->special = 0; 1461 break; 1462 1463 case 110: 1464 // Blazing Door Close (faster than TURBO!) 1465 if (EV_DoDoor (line,blazeClose) || demo_compatibility) 1466 line->special = 0; 1467 break; 1468 1469 case 119: 1470 // Raise floor to nearest surr. floor 1471 if (EV_DoFloor(line,raiseFloorToNearest) || demo_compatibility) 1472 line->special = 0; 1473 break; 1474 1475 case 121: 1476 // Blazing PlatDownWaitUpStay 1477 if (EV_DoPlat(line,blazeDWUS,0) || demo_compatibility) 1478 line->special = 0; 1479 break; 1480 1481 case 124: 1482 // Secret EXIT 1483 // killough 10/98: prevent zombies from exiting levels 1484 // CPhipps - change for lxdoom's compatibility handling 1485 if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) 1486 G_SecretExitLevel (); 1487 break; 1488 1489 case 125: 1490 // TELEPORT MonsterONLY 1491 if (!thing->player && 1492 (EV_Teleport(line, side, thing) || demo_compatibility)) 1493 line->special = 0; 1494 break; 1495 1496 case 130: 1497 // Raise Floor Turbo 1498 if (EV_DoFloor(line,raiseFloorTurbo) || demo_compatibility) 1499 line->special = 0; 1500 break; 1501 1502 case 141: 1503 // Silent Ceiling Crush & Raise 1504 if (EV_DoCeiling(line,silentCrushAndRaise) || demo_compatibility) 1505 line->special = 0; 1506 break; 1507 1508 // Regular walk many retriggerable 1509 1510 case 72: 1511 // Ceiling Crush 1512 EV_DoCeiling( line, lowerAndCrush ); 1513 break; 1514 1515 case 73: 1516 // Ceiling Crush and Raise 1517 EV_DoCeiling(line,crushAndRaise); 1518 break; 1519 1520 case 74: 1521 // Ceiling Crush Stop 1522 EV_CeilingCrushStop(line); 1523 break; 1524 1525 case 75: 1526 // Close Door 1527 EV_DoDoor(line,p_close); 1528 break; 1529 1530 case 76: 1531 // Close Door 30 1532 EV_DoDoor(line,close30ThenOpen); 1533 break; 1534 1535 case 77: 1536 // Fast Ceiling Crush & Raise 1537 EV_DoCeiling(line,fastCrushAndRaise); 1538 break; 1539 1540 case 79: 1541 // Lights Very Dark 1542 EV_LightTurnOn(line,35); 1543 break; 1544 1545 case 80: 1546 // Light Turn On - brightest near 1547 EV_LightTurnOn(line,0); 1548 break; 1549 1550 case 81: 1551 // Light Turn On 255 1552 EV_LightTurnOn(line,255); 1553 break; 1554 1555 case 82: 1556 // Lower Floor To Lowest 1557 EV_DoFloor( line, lowerFloorToLowest ); 1558 break; 1559 1560 case 83: 1561 // Lower Floor 1562 EV_DoFloor(line,lowerFloor); 1563 break; 1564 1565 case 84: 1566 // LowerAndChange 1567 EV_DoFloor(line,lowerAndChange); 1568 break; 1569 1570 case 86: 1571 // Open Door 1572 EV_DoDoor(line,p_open); 1573 break; 1574 1575 case 87: 1576 // Perpetual Platform Raise 1577 EV_DoPlat(line,perpetualRaise,0); 1578 break; 1579 1580 case 88: 1581 // PlatDownWaitUp 1582 EV_DoPlat(line,downWaitUpStay,0); 1583 break; 1584 1585 case 89: 1586 // Platform Stop 1587 EV_StopPlat(line); 1588 break; 1589 1590 case 90: 1591 // Raise Door 1592 EV_DoDoor(line,normal); 1593 break; 1594 1595 case 91: 1596 // Raise Floor 1597 EV_DoFloor(line,raiseFloor); 1598 break; 1599 1600 case 92: 1601 // Raise Floor 24 1602 EV_DoFloor(line,raiseFloor24); 1603 break; 1604 1605 case 93: 1606 // Raise Floor 24 And Change 1607 EV_DoFloor(line,raiseFloor24AndChange); 1608 break; 1609 1610 case 94: 1611 // Raise Floor Crush 1612 EV_DoFloor(line,raiseFloorCrush); 1613 break; 1614 1615 case 95: 1616 // Raise floor to nearest height 1617 // and change texture. 1618 EV_DoPlat(line,raiseToNearestAndChange,0); 1619 break; 1620 1621 case 96: 1622 // Raise floor to shortest texture height 1623 // on either side of lines. 1624 EV_DoFloor(line,raiseToTexture); 1625 break; 1626 1627 case 97: 1628 // TELEPORT! 1629 EV_Teleport( line, side, thing ); 1630 break; 1631 1632 case 98: 1633 // Lower Floor (TURBO) 1634 EV_DoFloor(line,turboLower); 1635 break; 1636 1637 case 105: 1638 // Blazing Door Raise (faster than TURBO!) 1639 EV_DoDoor (line,blazeRaise); 1640 break; 1641 1642 case 106: 1643 // Blazing Door Open (faster than TURBO!) 1644 EV_DoDoor (line,blazeOpen); 1645 break; 1646 1647 case 107: 1648 // Blazing Door Close (faster than TURBO!) 1649 EV_DoDoor (line,blazeClose); 1650 break; 1651 1652 case 120: 1653 // Blazing PlatDownWaitUpStay. 1654 EV_DoPlat(line,blazeDWUS,0); 1655 break; 1656 1657 case 126: 1658 // TELEPORT MonsterONLY. 1659 if (!thing->player) 1660 EV_Teleport( line, side, thing ); 1661 break; 1662 1663 case 128: 1664 // Raise To Nearest Floor 1665 EV_DoFloor(line,raiseFloorToNearest); 1666 break; 1667 1668 case 129: 1669 // Raise Floor Turbo 1670 EV_DoFloor(line,raiseFloorTurbo); 1671 break; 1672 1673 // Extended walk triggers 1674 1675 // jff 1/29/98 added new linedef types to fill all functions out so that 1676 // all have varieties SR, S1, WR, W1 1677 1678 // killough 1/31/98: "factor out" compatibility test, by 1679 // adding inner switch qualified by compatibility flag. 1680 // relax test to demo_compatibility 1681 1682 // killough 2/16/98: Fix problems with W1 types being cleared too early 1683 1684 default: 1685 if (!demo_compatibility) 1686 switch (line->special) 1687 { 1688 // Extended walk once triggers 1689 1690 case 142: 1691 // Raise Floor 512 1692 // 142 W1 EV_DoFloor(raiseFloor512) 1693 if (EV_DoFloor(line,raiseFloor512)) 1694 line->special = 0; 1695 break; 1696 1697 case 143: 1698 // Raise Floor 24 and change 1699 // 143 W1 EV_DoPlat(raiseAndChange,24) 1700 if (EV_DoPlat(line,raiseAndChange,24)) 1701 line->special = 0; 1702 break; 1703 1704 case 144: 1705 // Raise Floor 32 and change 1706 // 144 W1 EV_DoPlat(raiseAndChange,32) 1707 if (EV_DoPlat(line,raiseAndChange,32)) 1708 line->special = 0; 1709 break; 1710 1711 case 145: 1712 // Lower Ceiling to Floor 1713 // 145 W1 EV_DoCeiling(lowerToFloor) 1714 if (EV_DoCeiling( line, lowerToFloor )) 1715 line->special = 0; 1716 break; 1717 1718 case 146: 1719 // Lower Pillar, Raise Donut 1720 // 146 W1 EV_DoDonut() 1721 if (EV_DoDonut(line)) 1722 line->special = 0; 1723 break; 1724 1725 case 199: 1726 // Lower ceiling to lowest surrounding ceiling 1727 // 199 W1 EV_DoCeiling(lowerToLowest) 1728 if (EV_DoCeiling(line,lowerToLowest)) 1729 line->special = 0; 1730 break; 1731 1732 case 200: 1733 // Lower ceiling to highest surrounding floor 1734 // 200 W1 EV_DoCeiling(lowerToMaxFloor) 1735 if (EV_DoCeiling(line,lowerToMaxFloor)) 1736 line->special = 0; 1737 break; 1738 1739 case 207: 1740 // killough 2/16/98: W1 silent teleporter (normal kind) 1741 if (EV_SilentTeleport(line, side, thing)) 1742 line->special = 0; 1743 break; 1744 1745 //jff 3/16/98 renumber 215->153 1746 case 153: //jff 3/15/98 create texture change no motion type 1747 // Texture/Type Change Only (Trig) 1748 // 153 W1 Change Texture/Type Only 1749 if (EV_DoChange(line,trigChangeOnly)) 1750 line->special = 0; 1751 break; 1752 1753 case 239: //jff 3/15/98 create texture change no motion type 1754 // Texture/Type Change Only (Numeric) 1755 // 239 W1 Change Texture/Type Only 1756 if (EV_DoChange(line,numChangeOnly)) 1757 line->special = 0; 1758 break; 1759 1760 case 219: 1761 // Lower floor to next lower neighbor 1762 // 219 W1 Lower Floor Next Lower Neighbor 1763 if (EV_DoFloor(line,lowerFloorToNearest)) 1764 line->special = 0; 1765 break; 1766 1767 case 227: 1768 // Raise elevator next floor 1769 // 227 W1 Raise Elevator next floor 1770 if (EV_DoElevator(line,elevateUp)) 1771 line->special = 0; 1772 break; 1773 1774 case 231: 1775 // Lower elevator next floor 1776 // 231 W1 Lower Elevator next floor 1777 if (EV_DoElevator(line,elevateDown)) 1778 line->special = 0; 1779 break; 1780 1781 case 235: 1782 // Elevator to current floor 1783 // 235 W1 Elevator to current floor 1784 if (EV_DoElevator(line,elevateCurrent)) 1785 line->special = 0; 1786 break; 1787 1788 case 243: //jff 3/6/98 make fit within DCK's 256 linedef types 1789 // killough 2/16/98: W1 silent teleporter (linedef-linedef kind) 1790 if (EV_SilentLineTeleport(line, side, thing, false)) 1791 line->special = 0; 1792 break; 1793 1794 case 262: //jff 4/14/98 add silent line-line reversed 1795 if (EV_SilentLineTeleport(line, side, thing, true)) 1796 line->special = 0; 1797 break; 1798 1799 case 264: //jff 4/14/98 add monster-only silent line-line reversed 1800 if (!thing->player && 1801 EV_SilentLineTeleport(line, side, thing, true)) 1802 line->special = 0; 1803 break; 1804 1805 case 266: //jff 4/14/98 add monster-only silent line-line 1806 if (!thing->player && 1807 EV_SilentLineTeleport(line, side, thing, false)) 1808 line->special = 0; 1809 break; 1810 1811 case 268: //jff 4/14/98 add monster-only silent 1812 if (!thing->player && EV_SilentTeleport(line, side, thing)) 1813 line->special = 0; 1814 break; 1815 1816 //jff 1/29/98 end of added W1 linedef types 1817 1818 // Extended walk many retriggerable 1819 1820 //jff 1/29/98 added new linedef types to fill all functions 1821 //out so that all have varieties SR, S1, WR, W1 1822 1823 case 147: 1824 // Raise Floor 512 1825 // 147 WR EV_DoFloor(raiseFloor512) 1826 EV_DoFloor(line,raiseFloor512); 1827 break; 1828 1829 case 148: 1830 // Raise Floor 24 and Change 1831 // 148 WR EV_DoPlat(raiseAndChange,24) 1832 EV_DoPlat(line,raiseAndChange,24); 1833 break; 1834 1835 case 149: 1836 // Raise Floor 32 and Change 1837 // 149 WR EV_DoPlat(raiseAndChange,32) 1838 EV_DoPlat(line,raiseAndChange,32); 1839 break; 1840 1841 case 150: 1842 // Start slow silent crusher 1843 // 150 WR EV_DoCeiling(silentCrushAndRaise) 1844 EV_DoCeiling(line,silentCrushAndRaise); 1845 break; 1846 1847 case 151: 1848 // RaiseCeilingLowerFloor 1849 // 151 WR EV_DoCeiling(raiseToHighest), 1850 // EV_DoFloor(lowerFloortoLowest) 1851 EV_DoCeiling( line, raiseToHighest ); 1852 EV_DoFloor( line, lowerFloorToLowest ); 1853 break; 1854 1855 case 152: 1856 // Lower Ceiling to Floor 1857 // 152 WR EV_DoCeiling(lowerToFloor) 1858 EV_DoCeiling( line, lowerToFloor ); 1859 break; 1860 1861 //jff 3/16/98 renumber 153->256 1862 case 256: 1863 // Build stairs, step 8 1864 // 256 WR EV_BuildStairs(build8) 1865 EV_BuildStairs(line,build8); 1866 break; 1867 1868 //jff 3/16/98 renumber 154->257 1869 case 257: 1870 // Build stairs, step 16 1871 // 257 WR EV_BuildStairs(turbo16) 1872 EV_BuildStairs(line,turbo16); 1873 break; 1874 1875 case 155: 1876 // Lower Pillar, Raise Donut 1877 // 155 WR EV_DoDonut() 1878 EV_DoDonut(line); 1879 break; 1880 1881 case 156: 1882 // Start lights strobing 1883 // 156 WR Lights EV_StartLightStrobing() 1884 EV_StartLightStrobing(line); 1885 break; 1886 1887 case 157: 1888 // Lights to dimmest near 1889 // 157 WR Lights EV_TurnTagLightsOff() 1890 EV_TurnTagLightsOff(line); 1891 break; 1892 1893 case 201: 1894 // Lower ceiling to lowest surrounding ceiling 1895 // 201 WR EV_DoCeiling(lowerToLowest) 1896 EV_DoCeiling(line,lowerToLowest); 1897 break; 1898 1899 case 202: 1900 // Lower ceiling to highest surrounding floor 1901 // 202 WR EV_DoCeiling(lowerToMaxFloor) 1902 EV_DoCeiling(line,lowerToMaxFloor); 1903 break; 1904 1905 case 208: 1906 // killough 2/16/98: WR silent teleporter (normal kind) 1907 EV_SilentTeleport(line, side, thing); 1908 break; 1909 1910 case 212: //jff 3/14/98 create instant toggle floor type 1911 // Toggle floor between C and F instantly 1912 // 212 WR Instant Toggle Floor 1913 EV_DoPlat(line,toggleUpDn,0); 1914 break; 1915 1916 //jff 3/16/98 renumber 216->154 1917 case 154: //jff 3/15/98 create texture change no motion type 1918 // Texture/Type Change Only (Trigger) 1919 // 154 WR Change Texture/Type Only 1920 EV_DoChange(line,trigChangeOnly); 1921 break; 1922 1923 case 240: //jff 3/15/98 create texture change no motion type 1924 // Texture/Type Change Only (Numeric) 1925 // 240 WR Change Texture/Type Only 1926 EV_DoChange(line,numChangeOnly); 1927 break; 1928 1929 case 220: 1930 // Lower floor to next lower neighbor 1931 // 220 WR Lower Floor Next Lower Neighbor 1932 EV_DoFloor(line,lowerFloorToNearest); 1933 break; 1934 1935 case 228: 1936 // Raise elevator next floor 1937 // 228 WR Raise Elevator next floor 1938 EV_DoElevator(line,elevateUp); 1939 break; 1940 1941 case 232: 1942 // Lower elevator next floor 1943 // 232 WR Lower Elevator next floor 1944 EV_DoElevator(line,elevateDown); 1945 break; 1946 1947 case 236: 1948 // Elevator to current floor 1949 // 236 WR Elevator to current floor 1950 EV_DoElevator(line,elevateCurrent); 1951 break; 1952 1953 case 244: //jff 3/6/98 make fit within DCK's 256 linedef types 1954 // killough 2/16/98: WR silent teleporter (linedef-linedef kind) 1955 EV_SilentLineTeleport(line, side, thing, false); 1956 break; 1957 1958 case 263: //jff 4/14/98 add silent line-line reversed 1959 EV_SilentLineTeleport(line, side, thing, true); 1960 break; 1961 1962 case 265: //jff 4/14/98 add monster-only silent line-line reversed 1963 if (!thing->player) 1964 EV_SilentLineTeleport(line, side, thing, true); 1965 break; 1966 1967 case 267: //jff 4/14/98 add monster-only silent line-line 1968 if (!thing->player) 1969 EV_SilentLineTeleport(line, side, thing, false); 1970 break; 1971 1972 case 269: //jff 4/14/98 add monster-only silent 1973 if (!thing->player) 1974 EV_SilentTeleport(line, side, thing); 1975 break; 1976 1977 //jff 1/29/98 end of added WR linedef types 1978 } 1979 break; 1980 } 1981} 1982 1983// 1984// P_ShootSpecialLine - Gun trigger special dispatcher 1985// 1986// Called when a thing shoots a special line with bullet, shell, saw, or fist. 1987// 1988// jff 02/12/98 all G1 lines were fixed to check the result from the EV_ 1989// function before clearing the special. This avoids losing the function 1990// of the line, should the sector already be in motion when the line is 1991// impacted. Change is qualified by demo_compatibility. 1992// 1993void P_ShootSpecialLine 1994( mobj_t* thing, 1995 line_t* line ) 1996{ 1997 //jff 02/04/98 add check here for generalized linedef 1998 if (!demo_compatibility) 1999 { 2000 // pointer to line function is NULL by default, set non-null if 2001 // line special is gun triggered generalized linedef type 2002 int (*linefunc)(line_t *line)=NULL; 2003 2004 // check each range of generalized linedefs 2005 if ((unsigned)line->special >= GenEnd) 2006 { 2007 // Out of range for GenFloors 2008 } 2009 else if ((unsigned)line->special >= GenFloorBase) 2010 { 2011 if (!thing->player) 2012 if ((line->special & FloorChange) || !(line->special & FloorModel)) 2013 return; // FloorModel is "Allow Monsters" if FloorChange is 0 2014 if (!line->tag) //jff 2/27/98 all gun generalized types require tag 2015 return; 2016 2017 linefunc = EV_DoGenFloor; 2018 } 2019 else if ((unsigned)line->special >= GenCeilingBase) 2020 { 2021 if (!thing->player) 2022 if ((line->special & CeilingChange) || !(line->special & CeilingModel)) 2023 return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 2024 if (!line->tag) //jff 2/27/98 all gun generalized types require tag 2025 return; 2026 linefunc = EV_DoGenCeiling; 2027 } 2028 else if ((unsigned)line->special >= GenDoorBase) 2029 { 2030 if (!thing->player) 2031 { 2032 if (!(line->special & DoorMonster)) 2033 return; // monsters disallowed from this door 2034 if (line->flags & ML_SECRET) // they can't open secret doors either 2035 return; 2036 } 2037 if (!line->tag) //jff 3/2/98 all gun generalized types require tag 2038 return; 2039 linefunc = EV_DoGenDoor; 2040 } 2041 else if ((unsigned)line->special >= GenLockedBase) 2042 { 2043 if (!thing->player) 2044 return; // monsters disallowed from unlocking doors 2045 if (((line->special&TriggerType)==GunOnce) || ((line->special&TriggerType)==GunMany)) 2046 { //jff 4/1/98 check for being a gun type before reporting door type 2047 if (!P_CanUnlockGenDoor(line,thing->player)) 2048 return; 2049 } 2050 else 2051 return; 2052 if (!line->tag) //jff 2/27/98 all gun generalized types require tag 2053 return; 2054 2055 linefunc = EV_DoGenLockedDoor; 2056 } 2057 else if ((unsigned)line->special >= GenLiftBase) 2058 { 2059 if (!thing->player) 2060 if (!(line->special & LiftMonster)) 2061 return; // monsters disallowed 2062 linefunc = EV_DoGenLift; 2063 } 2064 else if ((unsigned)line->special >= GenStairsBase) 2065 { 2066 if (!thing->player) 2067 if (!(line->special & StairMonster)) 2068 return; // monsters disallowed 2069 if (!line->tag) //jff 2/27/98 all gun generalized types require tag 2070 return; 2071 linefunc = EV_DoGenStairs; 2072 } 2073 else if ((unsigned)line->special >= GenCrusherBase) 2074 { 2075 if (!thing->player) 2076 if (!(line->special & StairMonster)) 2077 return; // monsters disallowed 2078 if (!line->tag) //jff 2/27/98 all gun generalized types require tag 2079 return; 2080 linefunc = EV_DoGenCrusher; 2081 } 2082 2083 if (linefunc) 2084 switch((line->special & TriggerType) >> TriggerTypeShift) 2085 { 2086 case GunOnce: 2087 if (linefunc(line)) 2088 P_ChangeSwitchTexture(line,0); 2089 return; 2090 case GunMany: 2091 if (linefunc(line)) 2092 P_ChangeSwitchTexture(line,1); 2093 return; 2094 default: // if not a gun type, do nothing here 2095 return; 2096 } 2097 } 2098 2099 // Impacts that other things can activate. 2100 if (!thing->player) 2101 { 2102 int ok = 0; 2103 switch(line->special) 2104 { 2105 case 46: 2106 // 46 GR Open door on impact weapon is monster activatable 2107 ok = 1; 2108 break; 2109 } 2110 if (!ok) 2111 return; 2112 } 2113 2114 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types 2115 return; 2116 2117 switch(line->special) 2118 { 2119 case 24: 2120 // 24 G1 raise floor to highest adjacent 2121 if (EV_DoFloor(line,raiseFloor) || demo_compatibility) 2122 P_ChangeSwitchTexture(line,0); 2123 break; 2124 2125 case 46: 2126 // 46 GR open door, stay open 2127 EV_DoDoor(line,p_open); 2128 P_ChangeSwitchTexture(line,1); 2129 break; 2130 2131 case 47: 2132 // 47 G1 raise floor to nearest and change texture and type 2133 if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) 2134 P_ChangeSwitchTexture(line,0); 2135 break; 2136 2137 //jff 1/30/98 added new gun linedefs here 2138 // killough 1/31/98: added demo_compatibility check, added inner switch 2139 2140 default: 2141 if (!demo_compatibility) 2142 switch (line->special) 2143 { 2144 case 197: 2145 // Exit to next level 2146 // killough 10/98: prevent zombies from exiting levels 2147 if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) 2148 break; 2149 P_ChangeSwitchTexture(line,0); 2150 G_ExitLevel(); 2151 break; 2152 2153 case 198: 2154 // Exit to secret level 2155 // killough 10/98: prevent zombies from exiting levels 2156 if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) 2157 break; 2158 P_ChangeSwitchTexture(line,0); 2159 G_SecretExitLevel(); 2160 break; 2161 //jff end addition of new gun linedefs 2162 } 2163 break; 2164 } 2165} 2166 2167 2168// 2169// P_PlayerInSpecialSector() 2170// 2171// Called every tick frame 2172// that the player origin is in a special sector 2173// 2174// Changed to ignore sector types the engine does not recognize 2175// 2176void P_PlayerInSpecialSector (player_t* player) 2177{ 2178 sector_t* sector; 2179 2180 sector = player->mo->subsector->sector; 2181 2182 // Falling, not all the way down yet? 2183 // Sector specials don't apply in mid-air 2184 if (player->mo->z != sector->floorheight) 2185 return; 2186 2187 // Has hit ground. 2188 //jff add if to handle old vs generalized types 2189 if (sector->special<32) // regular sector specials 2190 { 2191 switch (sector->special) 2192 { 2193 case 5: 2194 // 5/10 unit damage per 31 ticks 2195 if (!player->powers[pw_ironfeet]) 2196 if (!(leveltime&0x1f)) 2197 P_DamageMobj (player->mo, NULL, NULL, 10); 2198 break; 2199 2200 case 7: 2201 // 2/5 unit damage per 31 ticks 2202 if (!player->powers[pw_ironfeet]) 2203 if (!(leveltime&0x1f)) 2204 P_DamageMobj (player->mo, NULL, NULL, 5); 2205 break; 2206 2207 case 16: 2208 // 10/20 unit damage per 31 ticks 2209 case 4: 2210 // 10/20 unit damage plus blinking light (light already spawned) 2211 if (!player->powers[pw_ironfeet] 2212 || (P_Random(pr_slimehurt)<5) ) // even with suit, take damage 2213 { 2214 if (!(leveltime&0x1f)) 2215 P_DamageMobj (player->mo, NULL, NULL, 20); 2216 } 2217 break; 2218 2219 case 9: 2220 // Tally player in secret sector, clear secret special 2221 player->secretcount++; 2222 sector->special = 0; 2223 break; 2224 2225 case 11: 2226 // Exit on health < 11, take 10/20 damage per 31 ticks 2227 if (comp[comp_god]) /* killough 2/21/98: add compatibility switch */ 2228 player->cheats &= ~CF_GODMODE; // on godmode cheat clearing 2229 // does not affect invulnerability 2230 if (!(leveltime&0x1f)) 2231 P_DamageMobj (player->mo, NULL, NULL, 20); 2232 2233 if (player->health <= 10) 2234 G_ExitLevel(); 2235 break; 2236 2237 default: 2238 //jff 1/24/98 Don't exit as DOOM2 did, just ignore 2239 break; 2240 }; 2241 } 2242 else //jff 3/14/98 handle extended sector types for secrets and damage 2243 { 2244 switch ((sector->special&DAMAGE_MASK)>>DAMAGE_SHIFT) 2245 { 2246 case 0: // no damage 2247 break; 2248 case 1: // 2/5 damage per 31 ticks 2249 if (!player->powers[pw_ironfeet]) 2250 if (!(leveltime&0x1f)) 2251 P_DamageMobj (player->mo, NULL, NULL, 5); 2252 break; 2253 case 2: // 5/10 damage per 31 ticks 2254 if (!player->powers[pw_ironfeet]) 2255 if (!(leveltime&0x1f)) 2256 P_DamageMobj (player->mo, NULL, NULL, 10); 2257 break; 2258 case 3: // 10/20 damage per 31 ticks 2259 if (!player->powers[pw_ironfeet] 2260 || (P_Random(pr_slimehurt)<5)) // take damage even with suit 2261 { 2262 if (!(leveltime&0x1f)) 2263 P_DamageMobj (player->mo, NULL, NULL, 20); 2264 } 2265 break; 2266 } 2267 if (sector->special&SECRET_MASK) 2268 { 2269 player->secretcount++; 2270 sector->special &= ~SECRET_MASK; 2271 if (sector->special<32) // if all extended bits clear, 2272 sector->special=0; // sector is not special anymore 2273 } 2274 2275 // phares 3/19/98: 2276 // 2277 // If FRICTION_MASK or PUSH_MASK is set, we don't care at this 2278 // point, since the code to deal with those situations is 2279 // handled by Thinkers. 2280 2281 } 2282} 2283 2284// 2285// P_UpdateSpecials() 2286// 2287// Check level timer, frag counter, 2288// animate flats, scroll walls, 2289// change button textures 2290// 2291// Reads and modifies globals: 2292// levelTimer, levelTimeCount, 2293// levelFragLimit, levelFragLimitCount 2294// 2295 2296boolean levelTimer; 2297int levelTimeCount; 2298boolean levelFragLimit; // Ty 03/18/98 Added -frags support 2299int levelFragLimitCount; // Ty 03/18/98 Added -frags support 2300 2301void P_UpdateSpecials (void) 2302{ 2303 anim_t* anim; 2304 int pic; 2305 int i; 2306 2307 // Downcount level timer, exit level if elapsed 2308 if (levelTimer == true) 2309 { 2310 levelTimeCount--; 2311 if (!levelTimeCount) 2312 G_ExitLevel(); 2313 } 2314 2315 // Check frag counters, if frag limit reached, exit level // Ty 03/18/98 2316 // Seems like the total frags should be kept in a simple 2317 // array somewhere, but until they are... 2318 if (levelFragLimit == true) // we used -frags so compare count 2319 { 2320 int k,m,fragcount,exitflag=false; 2321 for (k=0;k<MAXPLAYERS;k++) 2322 { 2323 if (!playeringame[k]) continue; 2324 fragcount = 0; 2325 for (m=0;m<MAXPLAYERS;m++) 2326 { 2327 if (!playeringame[m]) continue; 2328 fragcount += (m!=k)? players[k].frags[m] : -players[k].frags[m]; 2329 } 2330 if (fragcount >= levelFragLimitCount) exitflag = true; 2331 if (exitflag == true) break; // skip out of the loop--we're done 2332 } 2333 if (exitflag == true) 2334 G_ExitLevel(); 2335 } 2336 2337 // Animate flats and textures globally 2338 for (anim = anims ; anim < lastanim ; anim++) 2339 { 2340 for (i=anim->basepic ; i<anim->basepic+anim->numpics ; i++) 2341 { 2342 pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); 2343 if (anim->istexture) 2344 texturetranslation[i] = pic; 2345 else 2346 flattranslation[i] = pic; 2347 } 2348 } 2349 2350 // Check buttons (retriggerable switches) and change texture on timeout 2351 for (i = 0; i < MAXBUTTONS; i++) 2352 if (buttonlist[i].btimer) 2353 { 2354 buttonlist[i].btimer--; 2355 if (!buttonlist[i].btimer) 2356 { 2357 switch(buttonlist[i].where) 2358 { 2359 case top: 2360 sides[buttonlist[i].line->sidenum[0]].toptexture = 2361 buttonlist[i].btexture; 2362 break; 2363 2364 case middle: 2365 sides[buttonlist[i].line->sidenum[0]].midtexture = 2366 buttonlist[i].btexture; 2367 break; 2368 2369 case bottom: 2370 sides[buttonlist[i].line->sidenum[0]].bottomtexture = 2371 buttonlist[i].btexture; 2372 break; 2373 } 2374 S_StartSound((mobj_t *)&buttonlist[i].soundorg,sfx_swtchn); 2375 memset(&buttonlist[i],0,sizeof(button_t)); 2376 } 2377 } 2378} 2379 2380////////////////////////////////////////////////////////////////////// 2381// 2382// Sector and Line special thinker spawning at level startup 2383// 2384////////////////////////////////////////////////////////////////////// 2385 2386// 2387// P_SpawnSpecials 2388// After the map has been loaded, 2389// scan for specials that spawn thinkers 2390// 2391 2392// Parses command line parameters. 2393void P_SpawnSpecials (void) 2394{ 2395 sector_t* sector; 2396 int i; 2397 2398 // See if -timer needs to be used. 2399 levelTimer = false; 2400 2401 i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play 2402 if (i && deathmatch) 2403 { 2404 levelTimer = true; 2405 levelTimeCount = 20 * 60 * TICRATE; 2406 } 2407 2408 i = M_CheckParm("-timer"); // user defined timer on game play 2409 if (i && deathmatch) 2410 { 2411 int time; 2412 time = atoi(myargv[i+1]) * 60 * TICRATE; 2413 levelTimer = true; 2414 levelTimeCount = time; 2415 } 2416 2417 // See if -frags has been used 2418 levelFragLimit = false; 2419 i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support 2420 if (i && deathmatch) 2421 { 2422 int frags; 2423 frags = atoi(myargv[i+1]); 2424 if (frags <= 0) frags = 10; // default 10 if no count provided 2425 levelFragLimit = true; 2426 levelFragLimitCount = frags; 2427 } 2428 2429 2430 // Init special sectors. 2431 sector = sectors; 2432 for (i=0 ; i<numsectors ; i++, sector++) 2433 { 2434 if (!sector->special) 2435 continue; 2436 2437 if (sector->special&SECRET_MASK) //jff 3/15/98 count extended 2438 totalsecret++; // secret sectors too 2439 2440 switch (sector->special&31) 2441 { 2442 case 1: 2443 // random off 2444 P_SpawnLightFlash (sector); 2445 break; 2446 2447 case 2: 2448 // strobe fast 2449 P_SpawnStrobeFlash(sector,FASTDARK,0); 2450 break; 2451 2452 case 3: 2453 // strobe slow 2454 P_SpawnStrobeFlash(sector,SLOWDARK,0); 2455 break; 2456 2457 case 4: 2458 // strobe fast/death slime 2459 P_SpawnStrobeFlash(sector,FASTDARK,0); 2460 sector->special |= 3<<DAMAGE_SHIFT; //jff 3/14/98 put damage bits in 2461 break; 2462 2463 case 8: 2464 // glowing light 2465 P_SpawnGlowingLight(sector); 2466 break; 2467 case 9: 2468 // secret sector 2469 if (sector->special<32) //jff 3/14/98 bits don't count unless not 2470 totalsecret++; // a generalized sector type 2471 break; 2472 2473 case 10: 2474 // door close in 30 seconds 2475 P_SpawnDoorCloseIn30 (sector); 2476 break; 2477 2478 case 12: 2479 // sync strobe slow 2480 P_SpawnStrobeFlash (sector, SLOWDARK, 1); 2481 break; 2482 2483 case 13: 2484 // sync strobe fast 2485 P_SpawnStrobeFlash (sector, FASTDARK, 1); 2486 break; 2487 2488 case 14: 2489 // door raise in 5 minutes 2490 P_SpawnDoorRaiseIn5Mins (sector, i); 2491 break; 2492 2493 case 17: 2494 // fire flickering 2495 P_SpawnFireFlicker(sector); 2496 break; 2497 } 2498 } 2499 2500 P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme 2501 2502 P_RemoveAllActivePlats(); // killough 2503 2504 for (i = 0;i < MAXBUTTONS;i++) 2505 memset(&buttonlist[i],0,sizeof(button_t)); 2506 2507 // P_InitTagLists() must be called before P_FindSectorFromLineTag() 2508 // or P_FindLineFromLineTag() can be called. 2509 2510 P_InitTagLists(); // killough 1/30/98: Create xref tables for tags 2511 2512 P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers 2513 2514 P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs 2515 2516 P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs 2517 2518 for (i=0; i<numlines; i++) 2519 switch (lines[i].special) 2520 { 2521 int s, sec; 2522 2523 // killough 3/7/98: 2524 // support for drawn heights coming from different sector 2525 case 242: 2526 sec = sides[*lines[i].sidenum].sector-sectors; 2527 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) 2528 sectors[s].heightsec = sec; 2529 break; 2530 2531 // killough 3/16/98: Add support for setting 2532 // floor lighting independently (e.g. lava) 2533 case 213: 2534 sec = sides[*lines[i].sidenum].sector-sectors; 2535 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) 2536 sectors[s].floorlightsec = sec; 2537 break; 2538 2539 // killough 4/11/98: Add support for setting 2540 // ceiling lighting independently 2541 case 261: 2542 sec = sides[*lines[i].sidenum].sector-sectors; 2543 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) 2544 sectors[s].ceilinglightsec = sec; 2545 break; 2546 2547 // killough 10/98: 2548 // 2549 // Support for sky textures being transferred from sidedefs. 2550 // Allows scrolling and other effects (but if scrolling is 2551 // used, then the same sector tag needs to be used for the 2552 // sky sector, the sky-transfer linedef, and the scroll-effect 2553 // linedef). Still requires user to use F_SKY1 for the floor 2554 // or ceiling texture, to distinguish floor and ceiling sky. 2555 2556 case 271: // Regular sky 2557 case 272: // Same, only flipped 2558 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) 2559 sectors[s].sky = i | PL_SKYFLAT; 2560 break; 2561 } 2562} 2563 2564// killough 2/28/98: 2565// 2566// This function, with the help of r_plane.c and r_bsp.c, supports generalized 2567// scrolling floors and walls, with optional mobj-carrying properties, e.g. 2568// conveyor belts, rivers, etc. A linedef with a special type affects all 2569// tagged sectors the same way, by creating scrolling and/or object-carrying 2570// properties. Multiple linedefs may be used on the same sector and are 2571// cumulative, although the special case of scrolling a floor and carrying 2572// things on it, requires only one linedef. The linedef's direction determines 2573// the scrolling direction, and the linedef's length determines the scrolling 2574// speed. This was designed so that an edge around the sector could be used to 2575// control the direction of the sector's scrolling, which is usually what is 2576// desired. 2577// 2578// Process the active scrollers. 2579// 2580// This is the main scrolling code 2581// killough 3/7/98 2582 2583void T_Scroll(scroll_t *s) 2584{ 2585 fixed_t dx = s->dx, dy = s->dy; 2586 2587 if (s->control != -1) 2588 { // compute scroll amounts based on a sector's height changes 2589 fixed_t height = sectors[s->control].floorheight + 2590 sectors[s->control].ceilingheight; 2591 fixed_t delta = height - s->last_height; 2592 s->last_height = height; 2593 dx = FixedMul(dx, delta); 2594 dy = FixedMul(dy, delta); 2595 } 2596 2597 // killough 3/14/98: Add acceleration 2598 if (s->accel) 2599 { 2600 s->vdx = dx += s->vdx; 2601 s->vdy = dy += s->vdy; 2602 } 2603 2604 if (!(dx | dy)) // no-op if both (x,y) offsets 0 2605 return; 2606 2607 switch (s->type) 2608 { 2609 side_t *side; 2610 sector_t *sec; 2611 fixed_t height, waterheight; // killough 4/4/98: add waterheight 2612 msecnode_t *node; 2613 mobj_t *thing; 2614 2615 case sc_side: // killough 3/7/98: Scroll wall texture 2616 side = sides + s->affectee; 2617 side->textureoffset += dx; 2618 side->rowoffset += dy; 2619 break; 2620 2621 case sc_floor: // killough 3/7/98: Scroll floor texture 2622 sec = sectors + s->affectee; 2623 sec->floor_xoffs += dx; 2624 sec->floor_yoffs += dy; 2625 break; 2626 2627 case sc_ceiling: // killough 3/7/98: Scroll ceiling texture 2628 sec = sectors + s->affectee; 2629 sec->ceiling_xoffs += dx; 2630 sec->ceiling_yoffs += dy; 2631 break; 2632 2633 case sc_carry: 2634 2635 // killough 3/7/98: Carry things on floor 2636 // killough 3/20/98: use new sector list which reflects true members 2637 // killough 3/27/98: fix carrier bug 2638 // killough 4/4/98: Underwater, carry things even w/o gravity 2639 2640 sec = sectors + s->affectee; 2641 height = sec->floorheight; 2642 waterheight = sec->heightsec != -1 && 2643 sectors[sec->heightsec].floorheight > height ? 2644 sectors[sec->heightsec].floorheight : INT_MIN; 2645 2646 for (node = sec->touching_thinglist; node; node = node->m_snext) 2647 if (!((thing = node->m_thing)->flags & MF_NOCLIP) && 2648 (!(thing->flags & MF_NOGRAVITY || thing->z > height) || 2649 thing->z < waterheight)) 2650 { 2651 // Move objects only if on floor or underwater, 2652 // non-floating, and clipped. 2653 thing->momx += dx; 2654 thing->momy += dy; 2655 } 2656 break; 2657 2658 case sc_carry_ceiling: // to be added later 2659 break; 2660 } 2661} 2662 2663// 2664// Add_Scroller() 2665// 2666// Add a generalized scroller to the thinker list. 2667// 2668// type: the enumerated type of scrolling: floor, ceiling, floor carrier, 2669// wall, floor carrier & scroller 2670// 2671// (dx,dy): the direction and speed of the scrolling or its acceleration 2672// 2673// control: the sector whose heights control this scroller's effect 2674// remotely, or -1 if no control sector 2675// 2676// affectee: the index of the affected object (sector or sidedef) 2677// 2678// accel: non-zero if this is an accelerative effect 2679// 2680 2681static void Add_Scroller(int type, fixed_t dx, fixed_t dy, 2682 int control, int affectee, int accel) 2683{ 2684 scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0); 2685 s->thinker.function = T_Scroll; 2686 s->type = type; 2687 s->dx = dx; 2688 s->dy = dy; 2689 s->accel = accel; 2690 s->vdx = s->vdy = 0; 2691 if ((s->control = control) != -1) 2692 s->last_height = 2693 sectors[control].floorheight + sectors[control].ceilingheight; 2694 s->affectee = affectee; 2695 P_AddThinker(&s->thinker); 2696} 2697 2698// Adds wall scroller. Scroll amount is rotated with respect to wall's 2699// linedef first, so that scrolling towards the wall in a perpendicular 2700// direction is translated into vertical motion, while scrolling along 2701// the wall in a parallel direction is translated into horizontal motion. 2702// 2703// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff 2704// 2705// killough 10/98: 2706// fix scrolling aliasing problems, caused by long linedefs causing overflowing 2707 2708static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l, 2709 int control, int accel) 2710{ 2711 fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d; 2712 if (y > x) 2713 d = x, x = y, y = d; 2714 d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90) 2715 >> ANGLETOFINESHIFT]); 2716 2717 // CPhipps - Import scroller calc overflow fix, compatibility optioned 2718 if (compatibility_level >= lxdoom_1_compatibility) { 2719 x = (fixed_t)(((int_64_t)dy * -(int_64_t)l->dy - (int_64_t)dx * (int_64_t)l->dx) / (int_64_t)d); // killough 10/98: 2720 y = (fixed_t)(((int_64_t)dy * (int_64_t)l->dx - (int_64_t)dx * (int_64_t)l->dy) / (int_64_t)d); // Use long long arithmetic 2721 } else { 2722 x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); 2723 y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); 2724 } 2725 Add_Scroller(sc_side, x, y, control, *l->sidenum, accel); 2726} 2727 2728// Amount (dx,dy) vector linedef is shifted right to get scroll amount 2729#define SCROLL_SHIFT 5 2730 2731// Factor to scale scrolling effect into mobj-carrying properties = 3/32. 2732// (This is so scrolling floors and objects on them can move at same speed.) 2733#define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375)) 2734 2735// Initialize the scrollers 2736static void P_SpawnScrollers(void) 2737{ 2738 int i; 2739 line_t *l = lines; 2740 2741 for (i=0;i<numlines;i++,l++) 2742 { 2743 fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling 2744 fixed_t dy = l->dy >> SCROLL_SHIFT; 2745 int control = -1, accel = 0; // no control sector or acceleration 2746 int special = l->special; 2747 2748 // killough 3/7/98: Types 245-249 are same as 250-254 except that the 2749 // first side's sector's heights cause scrolling when they change, and 2750 // this linedef controls the direction and speed of the scrolling. The 2751 // most complicated linedef since donuts, but powerful :) 2752 // 2753 // killough 3/15/98: Add acceleration. Types 214-218 are the same but 2754 // are accelerative. 2755 2756 if (special >= 245 && special <= 249) // displacement scrollers 2757 { 2758 special += 250-245; 2759 control = sides[*l->sidenum].sector - sectors; 2760 } 2761 else 2762 if (special >= 214 && special <= 218) // accelerative scrollers 2763 { 2764 accel = 1; 2765 special += 250-214; 2766 control = sides[*l->sidenum].sector - sectors; 2767 } 2768 2769 switch (special) 2770 { 2771 register int s; 2772 2773 case 250: // scroll effect ceiling 2774 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) 2775 Add_Scroller(sc_ceiling, -dx, dy, control, s, accel); 2776 break; 2777 2778 case 251: // scroll effect floor 2779 case 253: // scroll and carry objects on floor 2780 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) 2781 Add_Scroller(sc_floor, -dx, dy, control, s, accel); 2782 if (special != 253) 2783 break; 2784 2785 case 252: // carry objects on floor 2786 dx = FixedMul(dx,CARRYFACTOR); 2787 dy = FixedMul(dy,CARRYFACTOR); 2788 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) 2789 Add_Scroller(sc_carry, dx, dy, control, s, accel); 2790 break; 2791 2792 // killough 3/1/98: scroll wall according to linedef 2793 // (same direction and speed as scrolling floors) 2794 case 254: 2795 for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;) 2796 if (s != i) 2797 Add_WallScroller(dx, dy, lines+s, control, accel); 2798 break; 2799 2800 case 255: // killough 3/2/98: scroll according to sidedef offsets 2801 s = lines[i].sidenum[0]; 2802 Add_Scroller(sc_side, -sides[s].textureoffset, 2803 sides[s].rowoffset, -1, s, accel); 2804 break; 2805 2806 case 48: // scroll first side 2807 Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel); 2808 break; 2809 2810 case 85: // jff 1/30/98 2-way scroll 2811 Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel); 2812 break; 2813 } 2814 } 2815} 2816 2817// killough 3/7/98 -- end generalized scroll effects 2818 2819//////////////////////////////////////////////////////////////////////////// 2820// 2821// FRICTION EFFECTS 2822// 2823// phares 3/12/98: Start of friction effects 2824// 2825// As the player moves, friction is applied by decreasing the x and y 2826// momentum values on each tic. By varying the percentage of decrease, 2827// we can simulate muddy or icy conditions. In mud, the player slows 2828// down faster. In ice, the player slows down more slowly. 2829// 2830// The amount of friction change is controlled by the length of a linedef 2831// with type 223. A length < 100 gives you mud. A length > 100 gives you ice. 2832// 2833// Also, each sector where these effects are to take place is given a 2834// new special type _______. Changing the type value at runtime allows 2835// these effects to be turned on or off. 2836// 2837// Sector boundaries present problems. The player should experience these 2838// friction changes only when his feet are touching the sector floor. At 2839// sector boundaries where floor height changes, the player can find 2840// himself still 'in' one sector, but with his feet at the floor level 2841// of the next sector (steps up or down). To handle this, Thinkers are used 2842// in icy/muddy sectors. These thinkers examine each object that is touching 2843// their sectors, looking for players whose feet are at the same level as 2844// their floors. Players satisfying this condition are given new friction 2845// values that are applied by the player movement code later. 2846// 2847// killough 8/28/98: 2848// 2849// Completely redid code, which did not need thinkers, and which put a heavy 2850// drag on CPU. Friction is now a property of sectors, NOT objects inside 2851// them. All objects, not just players, are affected by it, if they touch 2852// the sector's floor. Code simpler and faster, only calling on friction 2853// calculations when an object needs friction considered, instead of doing 2854// friction calculations on every sector during every tic. 2855// 2856// Although this -might- ruin Boom demo sync involving friction, it's the only 2857// way, short of code explosion, to fix the original design bug. Fixing the 2858// design bug in Boom's original friction code, while maintaining demo sync 2859// under every conceivable circumstance, would double or triple code size, and 2860// would require maintenance of buggy legacy code which is only useful for old 2861// demos. Doom demos, which are more important IMO, are not affected by this 2862// change. 2863// 2864///////////////////////////// 2865// 2866// Initialize the sectors where friction is increased or decreased 2867 2868static void P_SpawnFriction(void) 2869{ 2870 int i; 2871 line_t *l = lines; 2872 2873 // killough 8/28/98: initialize all sectors to normal friction first 2874 for (i = 0; i < numsectors; i++) 2875 { 2876 sectors[i].friction = ORIG_FRICTION; 2877 sectors[i].movefactor = ORIG_FRICTION_FACTOR; 2878 } 2879 2880 for (i = 0 ; i < numlines ; i++,l++) 2881 if (l->special == 223) 2882 { 2883 int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS; 2884 int friction = (0x1EB8*length)/0x80 + 0xD000; 2885 int movefactor, s; 2886 2887 // The following check might seem odd. At the time of movement, 2888 // the move distance is multiplied by 'friction/0x10000', so a 2889 // higher friction value actually means 'less friction'. 2890 2891 if (friction > ORIG_FRICTION) // ice 2892 movefactor = ((0x10092 - friction)*(0x70))/0x158; 2893 else 2894 movefactor = ((friction - 0xDB34)*(0xA))/0x80; 2895 2896 if (mbf_features) 2897 { // killough 8/28/98: prevent odd situations 2898 if (friction > FRACUNIT) 2899 friction = FRACUNIT; 2900 if (friction < 0) 2901 friction = 0; 2902 if (movefactor < 32) 2903 movefactor = 32; 2904 } 2905 2906 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) 2907 { 2908 // killough 8/28/98: 2909 // 2910 // Instead of spawning thinkers, which are slow and expensive, 2911 // modify the sector's own friction values. Friction should be 2912 // a property of sectors, not objects which reside inside them. 2913 // Original code scanned every object in every friction sector 2914 // on every tic, adjusting its friction, putting unnecessary 2915 // drag on CPU. New code adjusts friction of sector only once 2916 // at level startup, and then uses this friction value. 2917 2918 sectors[s].friction = friction; 2919 sectors[s].movefactor = movefactor; 2920 } 2921 } 2922} 2923 2924// 2925// phares 3/12/98: End of friction effects 2926// 2927//////////////////////////////////////////////////////////////////////////// 2928 2929//////////////////////////////////////////////////////////////////////////// 2930// 2931// PUSH/PULL EFFECT 2932// 2933// phares 3/20/98: Start of push/pull effects 2934// 2935// This is where push/pull effects are applied to objects in the sectors. 2936// 2937// There are four kinds of push effects 2938// 2939// 1) Pushing Away 2940// 2941// Pushes you away from a point source defined by the location of an 2942// MT_PUSH Thing. The force decreases linearly with distance from the 2943// source. This force crosses sector boundaries and is felt w/in a circle 2944// whose center is at the MT_PUSH. The force is felt only if the point 2945// MT_PUSH can see the target object. 2946// 2947// 2) Pulling toward 2948// 2949// Same as Pushing Away except you're pulled toward an MT_PULL point 2950// source. This force crosses sector boundaries and is felt w/in a circle 2951// whose center is at the MT_PULL. The force is felt only if the point 2952// MT_PULL can see the target object. 2953// 2954// 3) Wind 2955// 2956// Pushes you in a constant direction. Full force above ground, half 2957// force on the ground, nothing if you're below it (water). 2958// 2959// 4) Current 2960// 2961// Pushes you in a constant direction. No force above ground, full 2962// force if on the ground or below it (water). 2963// 2964// The magnitude of the force is controlled by the length of a controlling 2965// linedef. The force vector for types 3 & 4 is determined by the angle 2966// of the linedef, and is constant. 2967// 2968// For each sector where these effects occur, the sector special type has 2969// to have the PUSH_MASK bit set. If this bit is turned off by a switch 2970// at run-time, the effect will not occur. The controlling sector for 2971// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing. 2972 2973 2974#define PUSH_FACTOR 7 2975 2976///////////////////////////// 2977// 2978// Add a push thinker to the thinker list 2979 2980static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee) 2981{ 2982 pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0); 2983 2984 p->thinker.function = T_Pusher; 2985 p->source = source; 2986 p->type = type; 2987 p->x_mag = x_mag>>FRACBITS; 2988 p->y_mag = y_mag>>FRACBITS; 2989 p->magnitude = P_AproxDistance(p->x_mag,p->y_mag); 2990 if (source) // point source exist? 2991 { 2992 p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero 2993 p->x = p->source->x; 2994 p->y = p->source->y; 2995 } 2996 p->affectee = affectee; 2997 P_AddThinker(&p->thinker); 2998} 2999 3000///////////////////////////// 3001// 3002// PIT_PushThing determines the angle and magnitude of the effect. 3003// The object's x and y momentum values are changed. 3004// 3005// tmpusher belongs to the point source (MT_PUSH/MT_PULL). 3006// 3007// killough 10/98: allow to affect things besides players 3008 3009pusher_t* tmpusher; // pusher structure for blockmap searches 3010 3011boolean PIT_PushThing(mobj_t* thing) 3012{ 3013 /* killough 10/98: made more general */ 3014 if (!mbf_features ? 3015 thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) : 3016 (sentient(thing) || thing->flags & MF_SHOOTABLE) && 3017 !(thing->flags & MF_NOCLIP)) 3018 { 3019 angle_t pushangle; 3020 fixed_t speed; 3021 fixed_t sx = tmpusher->x; 3022 fixed_t sy = tmpusher->y; 3023 3024 speed = (tmpusher->magnitude - 3025 ((P_AproxDistance(thing->x - sx,thing->y - sy) 3026 >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); 3027 3028 // killough 10/98: make magnitude decrease with square 3029 // of distance, making it more in line with real nature, 3030 // so long as it's still in range with original formula. 3031 // 3032 // Removes angular distortion, and makes effort required 3033 // to stay close to source, grow increasingly hard as you 3034 // get closer, as expected. Still, it doesn't consider z :( 3035 3036 if (speed > 0 && mbf_features) 3037 { 3038 int x = (thing->x-sx) >> FRACBITS; 3039 int y = (thing->y-sy) >> FRACBITS; 3040 speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1)); 3041 } 3042 3043 // If speed <= 0, you're outside the effective radius. You also have 3044 // to be able to see the push/pull source point. 3045 3046 if (speed > 0 && P_CheckSight(thing,tmpusher->source)) 3047 { 3048 pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy); 3049 if (tmpusher->source->type == MT_PUSH) 3050 pushangle += ANG180; // away 3051 pushangle >>= ANGLETOFINESHIFT; 3052 thing->momx += FixedMul(speed,finecosine[pushangle]); 3053 thing->momy += FixedMul(speed,finesine[pushangle]); 3054 } 3055 } 3056 return true; 3057} 3058 3059///////////////////////////// 3060// 3061// T_Pusher looks for all objects that are inside the radius of 3062// the effect. 3063// 3064 3065void T_Pusher(pusher_t *p) 3066{ 3067 sector_t *sec; 3068 mobj_t *thing; 3069 msecnode_t* node; 3070 int xspeed,yspeed; 3071 int xl,xh,yl,yh,bx,by; 3072 int radius; 3073 int ht = 0; 3074 3075 if (!allow_pushers) 3076 return; 3077 3078 sec = sectors + p->affectee; 3079 3080 // Be sure the special sector type is still turned on. If so, proceed. 3081 // Else, bail out; the sector type has been changed on us. 3082 3083 if (!(sec->special & PUSH_MASK)) 3084 return; 3085 3086 // For constant pushers (wind/current) there are 3 situations: 3087 // 3088 // 1) Affected Thing is above the floor. 3089 // 3090 // Apply the full force if wind, no force if current. 3091 // 3092 // 2) Affected Thing is on the ground. 3093 // 3094 // Apply half force if wind, full force if current. 3095 // 3096 // 3) Affected Thing is below the ground (underwater effect). 3097 // 3098 // Apply no force if wind, full force if current. 3099 3100 if (p->type == p_push) 3101 { 3102 3103 // Seek out all pushable things within the force radius of this 3104 // point pusher. Crosses sectors, so use blockmap. 3105 3106 tmpusher = p; // MT_PUSH/MT_PULL point source 3107 radius = p->radius; // where force goes to zero 3108 tmbbox[BOXTOP] = p->y + radius; 3109 tmbbox[BOXBOTTOM] = p->y - radius; 3110 tmbbox[BOXRIGHT] = p->x + radius; 3111 tmbbox[BOXLEFT] = p->x - radius; 3112 3113 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; 3114 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; 3115 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; 3116 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; 3117 for (bx=xl ; bx<=xh ; bx++) 3118 for (by=yl ; by<=yh ; by++) 3119 P_BlockThingsIterator(bx,by,PIT_PushThing); 3120 return; 3121 } 3122 3123 // constant pushers p_wind and p_current 3124 3125 if (sec->heightsec != -1) // special water sector? 3126 ht = sectors[sec->heightsec].floorheight; 3127 node = sec->touching_thinglist; // things touching this sector 3128 for ( ; node ; node = node->m_snext) 3129 { 3130 thing = node->m_thing; 3131 if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) 3132 continue; 3133 if (p->type == p_wind) 3134 { 3135 if (sec->heightsec == -1) // NOT special water sector 3136 if (thing->z > thing->floorz) // above ground 3137 { 3138 xspeed = p->x_mag; // full force 3139 yspeed = p->y_mag; 3140 } 3141 else // on ground 3142 { 3143 xspeed = (p->x_mag)>>1; // half force 3144 yspeed = (p->y_mag)>>1; 3145 } 3146 else // special water sector 3147 { 3148 if (thing->z > ht) // above ground 3149 { 3150 xspeed = p->x_mag; // full force 3151 yspeed = p->y_mag; 3152 } 3153 else if (thing->player->viewz < ht) // underwater 3154 xspeed = yspeed = 0; // no force 3155 else // wading in water 3156 { 3157 xspeed = (p->x_mag)>>1; // half force 3158 yspeed = (p->y_mag)>>1; 3159 } 3160 } 3161 } 3162 else // p_current 3163 { 3164 if (sec->heightsec == -1) // NOT special water sector 3165 if (thing->z > sec->floorheight) // above ground 3166 xspeed = yspeed = 0; // no force 3167 else // on ground 3168 { 3169 xspeed = p->x_mag; // full force 3170 yspeed = p->y_mag; 3171 } 3172 else // special water sector 3173 if (thing->z > ht) // above ground 3174 xspeed = yspeed = 0; // no force 3175 else // underwater 3176 { 3177 xspeed = p->x_mag; // full force 3178 yspeed = p->y_mag; 3179 } 3180 } 3181 thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR); 3182 thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR); 3183 } 3184} 3185 3186///////////////////////////// 3187// 3188// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, 3189// NULL otherwise. 3190 3191mobj_t* P_GetPushThing(int s) 3192{ 3193 mobj_t* thing; 3194 sector_t* sec; 3195 3196 sec = sectors + s; 3197 thing = sec->thinglist; 3198 while (thing) 3199 { 3200 switch(thing->type) 3201 { 3202 case MT_PUSH: 3203 case MT_PULL: 3204 return thing; 3205 default: 3206 break; 3207 } 3208 thing = thing->snext; 3209 } 3210 return NULL; 3211} 3212 3213///////////////////////////// 3214// 3215// Initialize the sectors where pushers are present 3216// 3217 3218static void P_SpawnPushers(void) 3219{ 3220 int i; 3221 line_t *l = lines; 3222 register int s; 3223 mobj_t* thing; 3224 3225 for (i = 0 ; i < numlines ; i++,l++) 3226 switch(l->special) 3227 { 3228 case 224: // wind 3229 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) 3230 Add_Pusher(p_wind,l->dx,l->dy,NULL,s); 3231 break; 3232 case 225: // current 3233 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) 3234 Add_Pusher(p_current,l->dx,l->dy,NULL,s); 3235 break; 3236 case 226: // push/pull 3237 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) 3238 { 3239 thing = P_GetPushThing(s); 3240 if (thing) // No MT_P* means no effect 3241 Add_Pusher(p_push,l->dx,l->dy,thing,s); 3242 } 3243 break; 3244 } 3245} 3246 3247// 3248// phares 3/20/98: End of Pusher effects 3249// 3250////////////////////////////////////////////////////////////////////////////