Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / apps / plugins / doom / p_spec.c
blobf2757f8399049a69c2d9323edcf46c69d29dd010
1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
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.
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.
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.
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
38 *-----------------------------------------------------------------------------*/
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"
62 // Animating textures and planes
63 // There is another anim_t used in wi_stuff, unrelated.
65 typedef struct
67 boolean istexture;
68 int picnum;
69 int basepic;
70 int numpics;
71 int speed;
73 } anim_t;
76 // source animation definition
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
84 #if defined(__MWERKS__)
85 #pragma options align=packed
86 #endif
88 typedef struct
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
96 #define MAXANIMS 32 // no longer a strict limit -- killough
98 anim_t* lastanim;
99 anim_t* anims; // new structure w/o limits -- killough
100 static size_t maxanims;
102 // killough 3/7/98: Initialize generalized scrolling
103 static void P_SpawnScrollers(void);
105 static void P_SpawnFriction(void); // phares 3/16/98
106 static void P_SpawnPushers(void); // phares 3/20/98
108 extern int allow_pushers;
109 extern int variable_friction; // phares 3/20/98
112 // P_InitPicAnims
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.
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.
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.
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.
133 void P_InitPicAnims (void)
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
140 //jff 3/23/98 read from predefined or wad lump instead of table
141 animdefs = (const animdef_t *)W_CacheLumpNum(lump);
143 lastanim = anims;
144 for (i=0 ; animdefs[i].istexture != -1 ; i++)
146 // 1/11/98 killough -- removed limit by array-doubling
147 if (lastanim >= anims + maxanims)
149 size_t newmax = maxanims ? maxanims*2 : MAXANIMS;
150 anims = realloc(anims, newmax*sizeof(*anims)); // killough
151 lastanim = anims + maxanims;
152 maxanims = newmax;
155 if (animdefs[i].istexture)
157 // different episode ?
158 if (R_CheckTextureNumForName(animdefs[i].startname) == -1)
159 continue;
161 lastanim->picnum = R_TextureNumForName (animdefs[i].endname);
162 lastanim->basepic = R_TextureNumForName (animdefs[i].startname);
164 else
166 if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98
167 continue;
169 lastanim->picnum = R_FlatNumForName (animdefs[i].endname);
170 lastanim->basepic = R_FlatNumForName (animdefs[i].startname);
173 lastanim->istexture = animdefs[i].istexture;
174 lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
176 if (lastanim->numpics < 2)
177 I_Error ("P_InitPicAnims: bad cycle from %s to %s",
178 animdefs[i].startname,
179 animdefs[i].endname);
181 lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG()
182 lastanim++;
184 W_UnlockLumpNum(lump);
187 ///////////////////////////////////////////////////////////////
189 // Linedef and Sector Special Implementation Utility Functions
191 ///////////////////////////////////////////////////////////////
194 // getSide()
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.
200 // Note: if side=1 is specified, it must exist or results undefined
202 side_t* getSide
203 ( int currentSector,
204 int line,
205 int side )
207 return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
212 // getSector()
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.
218 // Note: if side=1 is specified, it must exist or results undefined
220 sector_t* getSector
221 ( int currentSector,
222 int line,
223 int side )
225 return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
230 // twoSided()
232 // Given the sector number and the line number,
233 // it will tell you whether the line is two-sided or not.
235 // modified to return actual two-sidedness rather than presence
236 // of 2S flag unless compatibility optioned
238 int twoSided
239 ( int sector,
240 int line )
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
245 return comp[comp_model] ?
246 (sectors[sector].lines[line])->flags & ML_TWOSIDED
248 (sectors[sector].lines[line])->sidenum[1] != -1;
253 // getNextSector()
255 // Return sector_t * of sector next to current across line.
257 // Note: returns NULL if not two-sided line, or both sides refer to sector
259 sector_t* getNextSector
260 ( line_t* line,
261 sector_t* sec )
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
267 if (comp[comp_model])
269 if (!(line->flags & ML_TWOSIDED))
270 return NULL;
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
279 return line->frontsector;
284 // P_FindLowestFloorSurrounding()
286 // Returns the fixed point value of the lowest floor height
287 // in the sector passed or its surrounding sectors.
289 fixed_t P_FindLowestFloorSurrounding(sector_t* sec)
291 int i;
292 line_t* check;
293 sector_t* other;
294 fixed_t floor = sec->floorheight;
296 for (i=0 ;i < sec->linecount ; i++)
298 check = sec->lines[i];
299 other = getNextSector(check,sec);
301 if (!other)
302 continue;
304 if (other->floorheight < floor)
305 floor = other->floorheight;
307 return floor;
312 // P_FindHighestFloorSurrounding()
314 // Passed a sector, returns the fixed point value of the largest
315 // floor height in the surrounding sectors, not including that passed
317 // NOTE: if no surrounding sector exists -32000*FRACUINT is returned
318 // if compatibility then -500*FRACUNIT is the smallest return possible
320 fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
322 int i;
323 line_t* check;
324 sector_t* other;
325 fixed_t floor = -500*FRACUNIT;
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
332 for (i=0 ;i < sec->linecount ; i++)
334 check = sec->lines[i];
335 other = getNextSector(check,sec);
337 if (!other)
338 continue;
340 if (other->floorheight > floor)
341 floor = other->floorheight;
343 return floor;
348 // P_FindNextHighestFloor()
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.
355 // Rewritten by Lee Killough to avoid fixed array and to be faster
357 fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight)
359 sector_t *other;
360 int i;
362 for (i=0 ;i < sec->linecount ; i++)
363 if ((other = getNextSector(sec->lines[i],sec)) &&
364 other->floorheight > currentheight)
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;
374 return currentheight;
379 // P_FindNextLowestFloor()
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.
386 // jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
388 fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight)
390 sector_t *other;
391 int i;
393 for (i=0 ;i < sec->linecount ; i++)
394 if ((other = getNextSector(sec->lines[i],sec)) &&
395 other->floorheight < currentheight)
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;
405 return currentheight;
410 // P_FindNextLowestCeiling()
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.
417 // jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
419 fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight)
421 sector_t *other;
422 int i;
424 for (i=0 ;i < sec->linecount ; i++)
425 if ((other = getNextSector(sec->lines[i],sec)) &&
426 other->ceilingheight < currentheight)
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;
436 return currentheight;
441 // P_FindNextHighestCeiling()
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.
448 // jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
450 fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight)
452 sector_t *other;
453 int i;
455 for (i=0 ;i < sec->linecount ; i++)
456 if ((other = getNextSector(sec->lines[i],sec)) &&
457 other->ceilingheight > currentheight)
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;
467 return currentheight;
472 // P_FindLowestCeilingSurrounding()
474 // Passed a sector, returns the fixed point value of the smallest
475 // ceiling height in the surrounding sectors, not including that passed
477 // NOTE: if no surrounding sector exists 32000*FRACUINT is returned
478 // but if compatibility then INT_MAX is the return
480 fixed_t P_FindLowestCeilingSurrounding(sector_t* sec)
482 int i;
483 line_t* check;
484 sector_t* other;
485 fixed_t height = INT_MAX;
487 /* jff 3/12/98 avoid ovf in height calculations */
488 if (!comp[comp_model]) height = 32000*FRACUNIT;
490 for (i=0 ;i < sec->linecount ; i++)
492 check = sec->lines[i];
493 other = getNextSector(check,sec);
495 if (!other)
496 continue;
498 if (other->ceilingheight < height)
499 height = other->ceilingheight;
501 return height;
506 // P_FindHighestCeilingSurrounding()
508 // Passed a sector, returns the fixed point value of the largest
509 // ceiling height in the surrounding sectors, not including that passed
511 // NOTE: if no surrounding sector exists -32000*FRACUINT is returned
512 // but if compatibility then 0 is the smallest return possible
514 fixed_t P_FindHighestCeilingSurrounding(sector_t* sec)
516 int i;
517 line_t* check;
518 sector_t* other;
519 fixed_t height = 0;
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;
526 for (i=0 ;i < sec->linecount ; i++)
528 check = sec->lines[i];
529 other = getNextSector(check,sec);
531 if (!other)
532 continue;
534 if (other->ceilingheight > height)
535 height = other->ceilingheight;
537 return height;
542 // P_FindShortestTextureAround()
544 // Passed a sector number, returns the shortest lower texture on a
545 // linedef bounding the sector.
547 // Note: If no lower texture exists 32000*FRACUNIT is returned.
548 // but if compatibility then INT_MAX is returned
550 // jff 02/03/98 Add routine to find shortest lower texture
552 fixed_t P_FindShortestTextureAround(int secnum)
554 int minsize = INT_MAX;
555 side_t* side;
556 int i;
557 sector_t *sec = &sectors[secnum];
559 if (!comp[comp_model])
560 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow in height calcs
562 for (i = 0; i < sec->linecount; i++)
564 if (twoSided(secnum, i))
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];
576 return minsize;
581 // P_FindShortestUpperAround()
583 // Passed a sector number, returns the shortest upper texture on a
584 // linedef bounding the sector.
586 // Note: If no upper texture exists 32000*FRACUNIT is returned.
587 // but if compatibility then INT_MAX is returned
589 // jff 03/20/98 Add routine to find shortest upper texture
591 fixed_t P_FindShortestUpperAround(int secnum)
593 int minsize = INT_MAX;
594 side_t* side;
595 int i;
596 sector_t *sec = &sectors[secnum];
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++)
603 if (twoSided(secnum, i))
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];
615 return minsize;
620 // P_FindModelFloorSector()
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.
626 // Note: If no sector at that height bounds the sector passed, return NULL
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
633 sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum)
635 int i;
636 sector_t *sec=NULL;
637 int linecount;
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++)
646 if ( twoSided(secnum, i) )
648 if (getSide(secnum,i,0)->sector-sectors == secnum)
649 sec = getSector(secnum,i,1);
650 else
651 sec = getSector(secnum,i,0);
653 if (sec->floorheight == floordestheight)
654 return sec;
657 return NULL;
662 // P_FindModelCeilingSector()
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.
668 // Note: If no sector at that height bounds the sector passed, return NULL
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
676 sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum)
678 int i;
679 sector_t *sec=NULL;
680 int linecount;
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++)
689 if ( twoSided(secnum, i) )
691 if (getSide(secnum,i,0)->sector-sectors == secnum)
692 sec = getSector(secnum,i,1);
693 else
694 sec = getSector(secnum,i,0);
696 if (sec->ceilingheight == ceildestheight)
697 return sec;
700 return NULL;
704 // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
707 // Find the next sector with the same tag as a linedef.
708 // Rewritten by Lee Killough to use chained hashing to improve speed
710 int P_FindSectorFromLineTag(const line_t *line, int start)
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;
719 // killough 4/16/98: Same thing, only for linedefs
721 int P_FindLineFromLineTag(const line_t *line, int start)
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;
730 // Hash the sector tags across the sectors and linedefs.
731 static void P_InitTagLists(void)
733 register int i;
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;
744 // killough 4/17/98: same thing, only for linedefs
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;
757 // P_FindMinSurroundingLight()
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.
763 int P_FindMinSurroundingLight
764 ( sector_t* sector,
765 int max )
767 int i;
768 int min;
769 line_t* line;
770 sector_t* check;
772 min = max;
773 for (i=0 ; i < sector->linecount ; i++)
775 line = sector->lines[i];
776 check = getNextSector(line,sector);
778 if (!check)
779 continue;
781 if (check->lightlevel < min)
782 min = check->lightlevel;
784 return min;
789 // P_CanUnlockGenDoor()
791 // Passed a generalized locked door linedef and a player, returns whether
792 // the player has the keys necessary to unlock that door.
794 // Note: The linedef passed MUST be a generalized locked door type
795 // or results are undefined.
797 // jff 02/05/98 routine added to test for unlockability of
798 // generalized locked doors
800 boolean P_CanUnlockGenDoor
801 ( line_t* line,
802 player_t* player)
804 // does this line special distinguish between skulls and keys?
805 int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift;
807 // determine for each case of lock type if player's keys are adequate
808 switch((line->special & LockedKey)>>LockedKeyShift)
810 case AnyKey:
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]
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;
825 break;
826 case RCard:
829 !player->cards[it_redcard] &&
830 (!skulliscard || !player->cards[it_redskull])
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;
837 break;
838 case BCard:
841 !player->cards[it_bluecard] &&
842 (!skulliscard || !player->cards[it_blueskull])
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;
849 break;
850 case YCard:
853 !player->cards[it_yellowcard] &&
854 (!skulliscard || !player->cards[it_yellowskull])
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;
861 break;
862 case RSkull:
865 !player->cards[it_redskull] &&
866 (!skulliscard || !player->cards[it_redcard])
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;
873 break;
874 case BSkull:
877 !player->cards[it_blueskull] &&
878 (!skulliscard || !player->cards[it_bluecard])
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;
885 break;
886 case YSkull:
889 !player->cards[it_yellowskull] &&
890 (!skulliscard || !player->cards[it_yellowcard])
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;
897 break;
898 case AllKeys:
901 !skulliscard &&
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]
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;
918 skulliscard &&
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])
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;
933 break;
935 return true;
940 // P_SectorActive()
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.
947 // jff 2/23/98 added to prevent old demos from
948 // succeeding in starting multiple specials on one sector
950 boolean P_SectorActive(special_e t,sector_t *sec)
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
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);
964 return true; // don't know which special, must be active, shouldn't be here
969 // P_CheckTag()
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.
975 // Note: Only line specials activated by walkover, pushing, or shooting are
976 // checked by this routine.
978 // jff 2/27/98 Added to check for zero tag allowed for regular special types
980 int P_CheckTag(line_t *line)
982 /* tag not zero, allowed, or
983 * killough 11/98: compatibility option */
984 if (comp[comp_zerotags] || line->tag)
985 return 1;
987 switch(line->special)
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:
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:
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:
1032 case 11: // Exits
1033 case 52:
1034 case 197:
1035 case 51:
1036 case 124:
1037 case 198:
1039 case 48: // Scrolling walls
1040 case 85:
1041 return 1; // zero tag allowed
1043 default:
1044 break;
1046 return 0; // zero tag not allowed
1051 // P_IsSecret()
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.
1056 // jff 3/14/98 added to simplify checks for whether sector is secret
1057 // in automap and other places
1059 boolean P_IsSecret(sector_t *sec)
1061 return (sec->special==9 || (sec->special&SECRET_MASK));
1066 // P_WasSecret()
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.
1071 // jff 3/14/98 added to simplify checks for whether sector is secret
1072 // in automap and other places
1074 boolean P_WasSecret(sector_t *sec)
1076 return (sec->oldspecial==9 || (sec->oldspecial&SECRET_MASK));
1080 //////////////////////////////////////////////////////////////////////////
1082 // Events
1084 // Events are operations triggered by using, crossing,
1085 // or shooting special lines, or by timed thinkers.
1087 /////////////////////////////////////////////////////////////////////////
1090 // P_CrossSpecialLine - Walkover Trigger Dispatcher
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.
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.
1100 // CPhipps - take a line_t pointer instead of a line number, as in MBF
1101 void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing)
1103 int ok;
1105 // Things that should never trigger lines
1106 if (!thing->player)
1108 // Things that should NOT trigger specials...
1109 switch(thing->type)
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;
1120 default: break;
1124 //jff 02/04/98 add check here for generalized lindef types
1125 if (!demo_compatibility) // generalized types not recognized if old demo
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;
1131 // check each range of generalized linedefs
1132 if ((unsigned)line->special >= GenEnd)
1134 // Out of range for GenFloors
1136 else if ((unsigned)line->special >= GenFloorBase)
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;
1145 else if ((unsigned)line->special >= GenCeilingBase)
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;
1154 else if ((unsigned)line->special >= GenDoorBase)
1156 if (!thing->player)
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;
1163 if (!line->tag) //3/2/98 move outside the monster check
1164 return;
1165 linefunc = EV_DoGenDoor;
1167 else if ((unsigned)line->special >= GenLockedBase)
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;
1176 else
1177 return;
1178 linefunc = EV_DoGenLockedDoor;
1180 else if ((unsigned)line->special >= GenLiftBase)
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;
1189 else if ((unsigned)line->special >= GenStairsBase)
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;
1199 if (linefunc) // if it was a valid generalized type
1200 switch((line->special & TriggerType) >> TriggerTypeShift)
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;
1214 if (!thing->player)
1216 ok = 0;
1217 switch(line->special)
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;
1242 if (!ok)
1243 return;
1246 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types
1247 return;
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
1252 switch (line->special)
1254 // Regular walk once triggers
1256 case 2:
1257 // Open Door
1258 if (EV_DoDoor(line,p_open) || demo_compatibility)
1259 line->special = 0;
1260 break;
1262 case 3:
1263 // Close Door
1264 if (EV_DoDoor(line,p_close) || demo_compatibility)
1265 line->special = 0;
1266 break;
1268 case 4:
1269 // Raise Door
1270 if (EV_DoDoor(line,normal) || demo_compatibility)
1271 line->special = 0;
1272 break;
1274 case 5:
1275 // Raise Floor
1276 if (EV_DoFloor(line,raiseFloor) || demo_compatibility)
1277 line->special = 0;
1278 break;
1280 case 6:
1281 // Fast Ceiling Crush & Raise
1282 if (EV_DoCeiling(line,fastCrushAndRaise) || demo_compatibility)
1283 line->special = 0;
1284 break;
1286 case 8:
1287 // Build Stairs
1288 if (EV_BuildStairs(line,build8) || demo_compatibility)
1289 line->special = 0;
1290 break;
1292 case 10:
1293 // PlatDownWaitUp
1294 if (EV_DoPlat(line,downWaitUpStay,0) || demo_compatibility)
1295 line->special = 0;
1296 break;
1298 case 12:
1299 // Light Turn On - brightest near
1300 if (EV_LightTurnOn(line,0) || demo_compatibility)
1301 line->special = 0;
1302 break;
1304 case 13:
1305 // Light Turn On 255
1306 if (EV_LightTurnOn(line,255) || demo_compatibility)
1307 line->special = 0;
1308 break;
1310 case 16:
1311 // Close Door 30
1312 if (EV_DoDoor(line,close30ThenOpen) || demo_compatibility)
1313 line->special = 0;
1314 break;
1316 case 17:
1317 // Start Light Strobing
1318 if (EV_StartLightStrobing(line) || demo_compatibility)
1319 line->special = 0;
1320 break;
1322 case 19:
1323 // Lower Floor
1324 if (EV_DoFloor(line,lowerFloor) || demo_compatibility)
1325 line->special = 0;
1326 break;
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;
1334 case 25:
1335 // Ceiling Crush and Raise
1336 if (EV_DoCeiling(line,crushAndRaise) || demo_compatibility)
1337 line->special = 0;
1338 break;
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;
1347 case 35:
1348 // Lights Very Dark
1349 if (EV_LightTurnOn(line,35) || demo_compatibility)
1350 line->special = 0;
1351 break;
1353 case 36:
1354 // Lower Floor (TURBO)
1355 if (EV_DoFloor(line,turboLower) || demo_compatibility)
1356 line->special = 0;
1357 break;
1359 case 37:
1360 // LowerAndChange
1361 if (EV_DoFloor(line,lowerAndChange) || demo_compatibility)
1362 line->special = 0;
1363 break;
1365 case 38:
1366 // Lower Floor To Lowest
1367 if (EV_DoFloor(line, lowerFloorToLowest) || demo_compatibility)
1368 line->special = 0;
1369 break;
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;
1377 case 40:
1378 // RaiseCeilingLowerFloor
1379 if (demo_compatibility)
1381 EV_DoCeiling( line, raiseToHighest );
1382 EV_DoFloor( line, lowerFloorToLowest ); //jff 02/12/98 doesn't work
1383 line->special = 0;
1385 else
1386 if (EV_DoCeiling(line, raiseToHighest))
1387 line->special = 0;
1388 break;
1390 case 44:
1391 // Ceiling Crush
1392 if (EV_DoCeiling(line, lowerAndCrush) || demo_compatibility)
1393 line->special = 0;
1394 break;
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;
1403 case 53:
1404 // Perpetual Platform Raise
1405 if (EV_DoPlat(line,perpetualRaise,0) || demo_compatibility)
1406 line->special = 0;
1407 break;
1409 case 54:
1410 // Platform Stop
1411 if (EV_StopPlat(line) || demo_compatibility)
1412 line->special = 0;
1413 break;
1415 case 56:
1416 // Raise Floor Crush
1417 if (EV_DoFloor(line,raiseFloorCrush) || demo_compatibility)
1418 line->special = 0;
1419 break;
1421 case 57:
1422 // Ceiling Crush Stop
1423 if (EV_CeilingCrushStop(line) || demo_compatibility)
1424 line->special = 0;
1425 break;
1427 case 58:
1428 // Raise Floor 24
1429 if (EV_DoFloor(line,raiseFloor24) || demo_compatibility)
1430 line->special = 0;
1431 break;
1433 case 59:
1434 // Raise Floor 24 And Change
1435 if (EV_DoFloor(line,raiseFloor24AndChange) || demo_compatibility)
1436 line->special = 0;
1437 break;
1439 case 100:
1440 // Build Stairs Turbo 16
1441 if (EV_BuildStairs(line,turbo16) || demo_compatibility)
1442 line->special = 0;
1443 break;
1445 case 104:
1446 // Turn lights off in sector(tag)
1447 if (EV_TurnTagLightsOff(line) || demo_compatibility)
1448 line->special = 0;
1449 break;
1451 case 108:
1452 // Blazing Door Raise (faster than TURBO!)
1453 if (EV_DoDoor(line,blazeRaise) || demo_compatibility)
1454 line->special = 0;
1455 break;
1457 case 109:
1458 // Blazing Door Open (faster than TURBO!)
1459 if (EV_DoDoor (line,blazeOpen) || demo_compatibility)
1460 line->special = 0;
1461 break;
1463 case 110:
1464 // Blazing Door Close (faster than TURBO!)
1465 if (EV_DoDoor (line,blazeClose) || demo_compatibility)
1466 line->special = 0;
1467 break;
1469 case 119:
1470 // Raise floor to nearest surr. floor
1471 if (EV_DoFloor(line,raiseFloorToNearest) || demo_compatibility)
1472 line->special = 0;
1473 break;
1475 case 121:
1476 // Blazing PlatDownWaitUpStay
1477 if (EV_DoPlat(line,blazeDWUS,0) || demo_compatibility)
1478 line->special = 0;
1479 break;
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;
1489 case 125:
1490 // TELEPORT MonsterONLY
1491 if (!thing->player &&
1492 (EV_Teleport(line, side, thing) || demo_compatibility))
1493 line->special = 0;
1494 break;
1496 case 130:
1497 // Raise Floor Turbo
1498 if (EV_DoFloor(line,raiseFloorTurbo) || demo_compatibility)
1499 line->special = 0;
1500 break;
1502 case 141:
1503 // Silent Ceiling Crush & Raise
1504 if (EV_DoCeiling(line,silentCrushAndRaise) || demo_compatibility)
1505 line->special = 0;
1506 break;
1508 // Regular walk many retriggerable
1510 case 72:
1511 // Ceiling Crush
1512 EV_DoCeiling( line, lowerAndCrush );
1513 break;
1515 case 73:
1516 // Ceiling Crush and Raise
1517 EV_DoCeiling(line,crushAndRaise);
1518 break;
1520 case 74:
1521 // Ceiling Crush Stop
1522 EV_CeilingCrushStop(line);
1523 break;
1525 case 75:
1526 // Close Door
1527 EV_DoDoor(line,p_close);
1528 break;
1530 case 76:
1531 // Close Door 30
1532 EV_DoDoor(line,close30ThenOpen);
1533 break;
1535 case 77:
1536 // Fast Ceiling Crush & Raise
1537 EV_DoCeiling(line,fastCrushAndRaise);
1538 break;
1540 case 79:
1541 // Lights Very Dark
1542 EV_LightTurnOn(line,35);
1543 break;
1545 case 80:
1546 // Light Turn On - brightest near
1547 EV_LightTurnOn(line,0);
1548 break;
1550 case 81:
1551 // Light Turn On 255
1552 EV_LightTurnOn(line,255);
1553 break;
1555 case 82:
1556 // Lower Floor To Lowest
1557 EV_DoFloor( line, lowerFloorToLowest );
1558 break;
1560 case 83:
1561 // Lower Floor
1562 EV_DoFloor(line,lowerFloor);
1563 break;
1565 case 84:
1566 // LowerAndChange
1567 EV_DoFloor(line,lowerAndChange);
1568 break;
1570 case 86:
1571 // Open Door
1572 EV_DoDoor(line,p_open);
1573 break;
1575 case 87:
1576 // Perpetual Platform Raise
1577 EV_DoPlat(line,perpetualRaise,0);
1578 break;
1580 case 88:
1581 // PlatDownWaitUp
1582 EV_DoPlat(line,downWaitUpStay,0);
1583 break;
1585 case 89:
1586 // Platform Stop
1587 EV_StopPlat(line);
1588 break;
1590 case 90:
1591 // Raise Door
1592 EV_DoDoor(line,normal);
1593 break;
1595 case 91:
1596 // Raise Floor
1597 EV_DoFloor(line,raiseFloor);
1598 break;
1600 case 92:
1601 // Raise Floor 24
1602 EV_DoFloor(line,raiseFloor24);
1603 break;
1605 case 93:
1606 // Raise Floor 24 And Change
1607 EV_DoFloor(line,raiseFloor24AndChange);
1608 break;
1610 case 94:
1611 // Raise Floor Crush
1612 EV_DoFloor(line,raiseFloorCrush);
1613 break;
1615 case 95:
1616 // Raise floor to nearest height
1617 // and change texture.
1618 EV_DoPlat(line,raiseToNearestAndChange,0);
1619 break;
1621 case 96:
1622 // Raise floor to shortest texture height
1623 // on either side of lines.
1624 EV_DoFloor(line,raiseToTexture);
1625 break;
1627 case 97:
1628 // TELEPORT!
1629 EV_Teleport( line, side, thing );
1630 break;
1632 case 98:
1633 // Lower Floor (TURBO)
1634 EV_DoFloor(line,turboLower);
1635 break;
1637 case 105:
1638 // Blazing Door Raise (faster than TURBO!)
1639 EV_DoDoor (line,blazeRaise);
1640 break;
1642 case 106:
1643 // Blazing Door Open (faster than TURBO!)
1644 EV_DoDoor (line,blazeOpen);
1645 break;
1647 case 107:
1648 // Blazing Door Close (faster than TURBO!)
1649 EV_DoDoor (line,blazeClose);
1650 break;
1652 case 120:
1653 // Blazing PlatDownWaitUpStay.
1654 EV_DoPlat(line,blazeDWUS,0);
1655 break;
1657 case 126:
1658 // TELEPORT MonsterONLY.
1659 if (!thing->player)
1660 EV_Teleport( line, side, thing );
1661 break;
1663 case 128:
1664 // Raise To Nearest Floor
1665 EV_DoFloor(line,raiseFloorToNearest);
1666 break;
1668 case 129:
1669 // Raise Floor Turbo
1670 EV_DoFloor(line,raiseFloorTurbo);
1671 break;
1673 // Extended walk triggers
1675 // jff 1/29/98 added new linedef types to fill all functions out so that
1676 // all have varieties SR, S1, WR, W1
1678 // killough 1/31/98: "factor out" compatibility test, by
1679 // adding inner switch qualified by compatibility flag.
1680 // relax test to demo_compatibility
1682 // killough 2/16/98: Fix problems with W1 types being cleared too early
1684 default:
1685 if (!demo_compatibility)
1686 switch (line->special)
1688 // Extended walk once triggers
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;
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;
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;
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;
1718 case 146:
1719 // Lower Pillar, Raise Donut
1720 // 146 W1 EV_DoDonut()
1721 if (EV_DoDonut(line))
1722 line->special = 0;
1723 break;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1816 //jff 1/29/98 end of added W1 linedef types
1818 // Extended walk many retriggerable
1820 //jff 1/29/98 added new linedef types to fill all functions
1821 //out so that all have varieties SR, S1, WR, W1
1823 case 147:
1824 // Raise Floor 512
1825 // 147 WR EV_DoFloor(raiseFloor512)
1826 EV_DoFloor(line,raiseFloor512);
1827 break;
1829 case 148:
1830 // Raise Floor 24 and Change
1831 // 148 WR EV_DoPlat(raiseAndChange,24)
1832 EV_DoPlat(line,raiseAndChange,24);
1833 break;
1835 case 149:
1836 // Raise Floor 32 and Change
1837 // 149 WR EV_DoPlat(raiseAndChange,32)
1838 EV_DoPlat(line,raiseAndChange,32);
1839 break;
1841 case 150:
1842 // Start slow silent crusher
1843 // 150 WR EV_DoCeiling(silentCrushAndRaise)
1844 EV_DoCeiling(line,silentCrushAndRaise);
1845 break;
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;
1855 case 152:
1856 // Lower Ceiling to Floor
1857 // 152 WR EV_DoCeiling(lowerToFloor)
1858 EV_DoCeiling( line, lowerToFloor );
1859 break;
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;
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;
1875 case 155:
1876 // Lower Pillar, Raise Donut
1877 // 155 WR EV_DoDonut()
1878 EV_DoDonut(line);
1879 break;
1881 case 156:
1882 // Start lights strobing
1883 // 156 WR Lights EV_StartLightStrobing()
1884 EV_StartLightStrobing(line);
1885 break;
1887 case 157:
1888 // Lights to dimmest near
1889 // 157 WR Lights EV_TurnTagLightsOff()
1890 EV_TurnTagLightsOff(line);
1891 break;
1893 case 201:
1894 // Lower ceiling to lowest surrounding ceiling
1895 // 201 WR EV_DoCeiling(lowerToLowest)
1896 EV_DoCeiling(line,lowerToLowest);
1897 break;
1899 case 202:
1900 // Lower ceiling to highest surrounding floor
1901 // 202 WR EV_DoCeiling(lowerToMaxFloor)
1902 EV_DoCeiling(line,lowerToMaxFloor);
1903 break;
1905 case 208:
1906 // killough 2/16/98: WR silent teleporter (normal kind)
1907 EV_SilentTeleport(line, side, thing);
1908 break;
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;
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;
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;
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;
1935 case 228:
1936 // Raise elevator next floor
1937 // 228 WR Raise Elevator next floor
1938 EV_DoElevator(line,elevateUp);
1939 break;
1941 case 232:
1942 // Lower elevator next floor
1943 // 232 WR Lower Elevator next floor
1944 EV_DoElevator(line,elevateDown);
1945 break;
1947 case 236:
1948 // Elevator to current floor
1949 // 236 WR Elevator to current floor
1950 EV_DoElevator(line,elevateCurrent);
1951 break;
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;
1958 case 263: //jff 4/14/98 add silent line-line reversed
1959 EV_SilentLineTeleport(line, side, thing, true);
1960 break;
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;
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;
1972 case 269: //jff 4/14/98 add monster-only silent
1973 if (!thing->player)
1974 EV_SilentTeleport(line, side, thing);
1975 break;
1977 //jff 1/29/98 end of added WR linedef types
1979 break;
1984 // P_ShootSpecialLine - Gun trigger special dispatcher
1986 // Called when a thing shoots a special line with bullet, shell, saw, or fist.
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.
1993 void P_ShootSpecialLine
1994 ( mobj_t* thing,
1995 line_t* line )
1997 //jff 02/04/98 add check here for generalized linedef
1998 if (!demo_compatibility)
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;
2004 // check each range of generalized linedefs
2005 if ((unsigned)line->special >= GenEnd)
2007 // Out of range for GenFloors
2009 else if ((unsigned)line->special >= GenFloorBase)
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;
2017 linefunc = EV_DoGenFloor;
2019 else if ((unsigned)line->special >= GenCeilingBase)
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;
2028 else if ((unsigned)line->special >= GenDoorBase)
2030 if (!thing->player)
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;
2037 if (!line->tag) //jff 3/2/98 all gun generalized types require tag
2038 return;
2039 linefunc = EV_DoGenDoor;
2041 else if ((unsigned)line->special >= GenLockedBase)
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;
2050 else
2051 return;
2052 if (!line->tag) //jff 2/27/98 all gun generalized types require tag
2053 return;
2055 linefunc = EV_DoGenLockedDoor;
2057 else if ((unsigned)line->special >= GenLiftBase)
2059 if (!thing->player)
2060 if (!(line->special & LiftMonster))
2061 return; // monsters disallowed
2062 linefunc = EV_DoGenLift;
2064 else if ((unsigned)line->special >= GenStairsBase)
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;
2073 else if ((unsigned)line->special >= GenCrusherBase)
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;
2083 if (linefunc)
2084 switch((line->special & TriggerType) >> TriggerTypeShift)
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;
2099 // Impacts that other things can activate.
2100 if (!thing->player)
2102 int ok = 0;
2103 switch(line->special)
2105 case 46:
2106 // 46 GR Open door on impact weapon is monster activatable
2107 ok = 1;
2108 break;
2110 if (!ok)
2111 return;
2114 if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types
2115 return;
2117 switch(line->special)
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;
2125 case 46:
2126 // 46 GR open door, stay open
2127 EV_DoDoor(line,p_open);
2128 P_ChangeSwitchTexture(line,1);
2129 break;
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;
2137 //jff 1/30/98 added new gun linedefs here
2138 // killough 1/31/98: added demo_compatibility check, added inner switch
2140 default:
2141 if (!demo_compatibility)
2142 switch (line->special)
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;
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
2163 break;
2169 // P_PlayerInSpecialSector()
2171 // Called every tick frame
2172 // that the player origin is in a special sector
2174 // Changed to ignore sector types the engine does not recognize
2176 void P_PlayerInSpecialSector (player_t* player)
2178 sector_t* sector;
2180 sector = player->mo->subsector->sector;
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;
2187 // Has hit ground.
2188 //jff add if to handle old vs generalized types
2189 if (sector->special<32) // regular sector specials
2191 switch (sector->special)
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;
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;
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
2214 if (!(leveltime&0x1f))
2215 P_DamageMobj (player->mo, NULL, NULL, 20);
2217 break;
2219 case 9:
2220 // Tally player in secret sector, clear secret special
2221 player->secretcount++;
2222 sector->special = 0;
2223 break;
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);
2233 if (player->health <= 10)
2234 G_ExitLevel();
2235 break;
2237 default:
2238 //jff 1/24/98 Don't exit as DOOM2 did, just ignore
2239 break;
2242 else //jff 3/14/98 handle extended sector types for secrets and damage
2244 switch ((sector->special&DAMAGE_MASK)>>DAMAGE_SHIFT)
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
2262 if (!(leveltime&0x1f))
2263 P_DamageMobj (player->mo, NULL, NULL, 20);
2265 break;
2267 if (sector->special&SECRET_MASK)
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
2275 // phares 3/19/98:
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.
2285 // P_UpdateSpecials()
2287 // Check level timer, frag counter,
2288 // animate flats, scroll walls,
2289 // change button textures
2291 // Reads and modifies globals:
2292 // levelTimer, levelTimeCount,
2293 // levelFragLimit, levelFragLimitCount
2296 boolean levelTimer;
2297 int levelTimeCount;
2298 boolean levelFragLimit; // Ty 03/18/98 Added -frags support
2299 int levelFragLimitCount; // Ty 03/18/98 Added -frags support
2301 void P_UpdateSpecials (void)
2303 anim_t* anim;
2304 int pic;
2305 int i;
2307 // Downcount level timer, exit level if elapsed
2308 if (levelTimer == true)
2310 levelTimeCount--;
2311 if (!levelTimeCount)
2312 G_ExitLevel();
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
2320 int k,m,fragcount,exitflag=false;
2321 for (k=0;k<MAXPLAYERS;k++)
2323 if (!playeringame[k]) continue;
2324 fragcount = 0;
2325 for (m=0;m<MAXPLAYERS;m++)
2327 if (!playeringame[m]) continue;
2328 fragcount += (m!=k)? players[k].frags[m] : -players[k].frags[m];
2330 if (fragcount >= levelFragLimitCount) exitflag = true;
2331 if (exitflag == true) break; // skip out of the loop--we're done
2333 if (exitflag == true)
2334 G_ExitLevel();
2337 // Animate flats and textures globally
2338 for (anim = anims ; anim < lastanim ; anim++)
2340 for (i=anim->basepic ; i<anim->basepic+anim->numpics ; i++)
2342 pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics );
2343 if (anim->istexture)
2344 texturetranslation[i] = pic;
2345 else
2346 flattranslation[i] = pic;
2350 // Check buttons (retriggerable switches) and change texture on timeout
2351 for (i = 0; i < MAXBUTTONS; i++)
2352 if (buttonlist[i].btimer)
2354 buttonlist[i].btimer--;
2355 if (!buttonlist[i].btimer)
2357 switch(buttonlist[i].where)
2359 case top:
2360 sides[buttonlist[i].line->sidenum[0]].toptexture =
2361 buttonlist[i].btexture;
2362 break;
2364 case middle:
2365 sides[buttonlist[i].line->sidenum[0]].midtexture =
2366 buttonlist[i].btexture;
2367 break;
2369 case bottom:
2370 sides[buttonlist[i].line->sidenum[0]].bottomtexture =
2371 buttonlist[i].btexture;
2372 break;
2374 S_StartSound((mobj_t *)&buttonlist[i].soundorg,sfx_swtchn);
2375 memset(&buttonlist[i],0,sizeof(button_t));
2380 //////////////////////////////////////////////////////////////////////
2382 // Sector and Line special thinker spawning at level startup
2384 //////////////////////////////////////////////////////////////////////
2387 // P_SpawnSpecials
2388 // After the map has been loaded,
2389 // scan for specials that spawn thinkers
2392 // Parses command line parameters.
2393 void P_SpawnSpecials (void)
2395 sector_t* sector;
2396 int i;
2397 int episode;
2399 episode = 1;
2400 if (W_CheckNumForName("texture2") >= 0)
2401 episode = 2;
2403 // See if -timer needs to be used.
2404 levelTimer = false;
2406 i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play
2407 if (i && deathmatch)
2409 levelTimer = true;
2410 levelTimeCount = 20 * 60 * TICRATE;
2413 i = M_CheckParm("-timer"); // user defined timer on game play
2414 if (i && deathmatch)
2416 int time;
2417 time = atoi(myargv[i+1]) * 60 * TICRATE;
2418 levelTimer = true;
2419 levelTimeCount = time;
2422 // See if -frags has been used
2423 levelFragLimit = false;
2424 i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support
2425 if (i && deathmatch)
2427 int frags;
2428 frags = atoi(myargv[i+1]);
2429 if (frags <= 0) frags = 10; // default 10 if no count provided
2430 levelFragLimit = true;
2431 levelFragLimitCount = frags;
2435 // Init special sectors.
2436 sector = sectors;
2437 for (i=0 ; i<numsectors ; i++, sector++)
2439 if (!sector->special)
2440 continue;
2442 if (sector->special&SECRET_MASK) //jff 3/15/98 count extended
2443 totalsecret++; // secret sectors too
2445 switch (sector->special&31)
2447 case 1:
2448 // random off
2449 P_SpawnLightFlash (sector);
2450 break;
2452 case 2:
2453 // strobe fast
2454 P_SpawnStrobeFlash(sector,FASTDARK,0);
2455 break;
2457 case 3:
2458 // strobe slow
2459 P_SpawnStrobeFlash(sector,SLOWDARK,0);
2460 break;
2462 case 4:
2463 // strobe fast/death slime
2464 P_SpawnStrobeFlash(sector,FASTDARK,0);
2465 sector->special |= 3<<DAMAGE_SHIFT; //jff 3/14/98 put damage bits in
2466 break;
2468 case 8:
2469 // glowing light
2470 P_SpawnGlowingLight(sector);
2471 break;
2472 case 9:
2473 // secret sector
2474 if (sector->special<32) //jff 3/14/98 bits don't count unless not
2475 totalsecret++; // a generalized sector type
2476 break;
2478 case 10:
2479 // door close in 30 seconds
2480 P_SpawnDoorCloseIn30 (sector);
2481 break;
2483 case 12:
2484 // sync strobe slow
2485 P_SpawnStrobeFlash (sector, SLOWDARK, 1);
2486 break;
2488 case 13:
2489 // sync strobe fast
2490 P_SpawnStrobeFlash (sector, FASTDARK, 1);
2491 break;
2493 case 14:
2494 // door raise in 5 minutes
2495 P_SpawnDoorRaiseIn5Mins (sector, i);
2496 break;
2498 case 17:
2499 // fire flickering
2500 P_SpawnFireFlicker(sector);
2501 break;
2505 P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme
2507 P_RemoveAllActivePlats(); // killough
2509 for (i = 0;i < MAXBUTTONS;i++)
2510 memset(&buttonlist[i],0,sizeof(button_t));
2512 // P_InitTagLists() must be called before P_FindSectorFromLineTag()
2513 // or P_FindLineFromLineTag() can be called.
2515 P_InitTagLists(); // killough 1/30/98: Create xref tables for tags
2517 P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers
2519 P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs
2521 P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
2523 for (i=0; i<numlines; i++)
2524 switch (lines[i].special)
2526 int s, sec;
2528 // killough 3/7/98:
2529 // support for drawn heights coming from different sector
2530 case 242:
2531 sec = sides[*lines[i].sidenum].sector-sectors;
2532 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2533 sectors[s].heightsec = sec;
2534 break;
2536 // killough 3/16/98: Add support for setting
2537 // floor lighting independently (e.g. lava)
2538 case 213:
2539 sec = sides[*lines[i].sidenum].sector-sectors;
2540 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2541 sectors[s].floorlightsec = sec;
2542 break;
2544 // killough 4/11/98: Add support for setting
2545 // ceiling lighting independently
2546 case 261:
2547 sec = sides[*lines[i].sidenum].sector-sectors;
2548 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2549 sectors[s].ceilinglightsec = sec;
2550 break;
2552 // killough 10/98:
2554 // Support for sky textures being transferred from sidedefs.
2555 // Allows scrolling and other effects (but if scrolling is
2556 // used, then the same sector tag needs to be used for the
2557 // sky sector, the sky-transfer linedef, and the scroll-effect
2558 // linedef). Still requires user to use F_SKY1 for the floor
2559 // or ceiling texture, to distinguish floor and ceiling sky.
2561 case 271: // Regular sky
2562 case 272: // Same, only flipped
2563 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2564 sectors[s].sky = i | PL_SKYFLAT;
2565 break;
2569 // killough 2/28/98:
2571 // This function, with the help of r_plane.c and r_bsp.c, supports generalized
2572 // scrolling floors and walls, with optional mobj-carrying properties, e.g.
2573 // conveyor belts, rivers, etc. A linedef with a special type affects all
2574 // tagged sectors the same way, by creating scrolling and/or object-carrying
2575 // properties. Multiple linedefs may be used on the same sector and are
2576 // cumulative, although the special case of scrolling a floor and carrying
2577 // things on it, requires only one linedef. The linedef's direction determines
2578 // the scrolling direction, and the linedef's length determines the scrolling
2579 // speed. This was designed so that an edge around the sector could be used to
2580 // control the direction of the sector's scrolling, which is usually what is
2581 // desired.
2583 // Process the active scrollers.
2585 // This is the main scrolling code
2586 // killough 3/7/98
2588 void T_Scroll(scroll_t *s)
2590 fixed_t dx = s->dx, dy = s->dy;
2592 if (s->control != -1)
2593 { // compute scroll amounts based on a sector's height changes
2594 fixed_t height = sectors[s->control].floorheight +
2595 sectors[s->control].ceilingheight;
2596 fixed_t delta = height - s->last_height;
2597 s->last_height = height;
2598 dx = FixedMul(dx, delta);
2599 dy = FixedMul(dy, delta);
2602 // killough 3/14/98: Add acceleration
2603 if (s->accel)
2605 s->vdx = dx += s->vdx;
2606 s->vdy = dy += s->vdy;
2609 if (!(dx | dy)) // no-op if both (x,y) offsets 0
2610 return;
2612 switch (s->type)
2614 side_t *side;
2615 sector_t *sec;
2616 fixed_t height, waterheight; // killough 4/4/98: add waterheight
2617 msecnode_t *node;
2618 mobj_t *thing;
2620 case sc_side: // killough 3/7/98: Scroll wall texture
2621 side = sides + s->affectee;
2622 side->textureoffset += dx;
2623 side->rowoffset += dy;
2624 break;
2626 case sc_floor: // killough 3/7/98: Scroll floor texture
2627 sec = sectors + s->affectee;
2628 sec->floor_xoffs += dx;
2629 sec->floor_yoffs += dy;
2630 break;
2632 case sc_ceiling: // killough 3/7/98: Scroll ceiling texture
2633 sec = sectors + s->affectee;
2634 sec->ceiling_xoffs += dx;
2635 sec->ceiling_yoffs += dy;
2636 break;
2638 case sc_carry:
2640 // killough 3/7/98: Carry things on floor
2641 // killough 3/20/98: use new sector list which reflects true members
2642 // killough 3/27/98: fix carrier bug
2643 // killough 4/4/98: Underwater, carry things even w/o gravity
2645 sec = sectors + s->affectee;
2646 height = sec->floorheight;
2647 waterheight = sec->heightsec != -1 &&
2648 sectors[sec->heightsec].floorheight > height ?
2649 sectors[sec->heightsec].floorheight : INT_MIN;
2651 for (node = sec->touching_thinglist; node; node = node->m_snext)
2652 if (!((thing = node->m_thing)->flags & MF_NOCLIP) &&
2653 (!(thing->flags & MF_NOGRAVITY || thing->z > height) ||
2654 thing->z < waterheight))
2656 // Move objects only if on floor or underwater,
2657 // non-floating, and clipped.
2658 thing->momx += dx;
2659 thing->momy += dy;
2661 break;
2663 case sc_carry_ceiling: // to be added later
2664 break;
2669 // Add_Scroller()
2671 // Add a generalized scroller to the thinker list.
2673 // type: the enumerated type of scrolling: floor, ceiling, floor carrier,
2674 // wall, floor carrier & scroller
2676 // (dx,dy): the direction and speed of the scrolling or its acceleration
2678 // control: the sector whose heights control this scroller's effect
2679 // remotely, or -1 if no control sector
2681 // affectee: the index of the affected object (sector or sidedef)
2683 // accel: non-zero if this is an accelerative effect
2686 static void Add_Scroller(int type, fixed_t dx, fixed_t dy,
2687 int control, int affectee, int accel)
2689 scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0);
2690 s->thinker.function = T_Scroll;
2691 s->type = type;
2692 s->dx = dx;
2693 s->dy = dy;
2694 s->accel = accel;
2695 s->vdx = s->vdy = 0;
2696 if ((s->control = control) != -1)
2697 s->last_height =
2698 sectors[control].floorheight + sectors[control].ceilingheight;
2699 s->affectee = affectee;
2700 P_AddThinker(&s->thinker);
2703 // Adds wall scroller. Scroll amount is rotated with respect to wall's
2704 // linedef first, so that scrolling towards the wall in a perpendicular
2705 // direction is translated into vertical motion, while scrolling along
2706 // the wall in a parallel direction is translated into horizontal motion.
2708 // killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff
2710 // killough 10/98:
2711 // fix scrolling aliasing problems, caused by long linedefs causing overflowing
2713 static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l,
2714 int control, int accel)
2716 fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d;
2717 if (y > x)
2718 d = x, x = y, y = d;
2719 d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90)
2720 >> ANGLETOFINESHIFT]);
2722 // CPhipps - Import scroller calc overflow fix, compatibility optioned
2723 if (compatibility_level >= lxdoom_1_compatibility) {
2724 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:
2725 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
2726 } else {
2727 x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d);
2728 y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d);
2730 Add_Scroller(sc_side, x, y, control, *l->sidenum, accel);
2733 // Amount (dx,dy) vector linedef is shifted right to get scroll amount
2734 #define SCROLL_SHIFT 5
2736 // Factor to scale scrolling effect into mobj-carrying properties = 3/32.
2737 // (This is so scrolling floors and objects on them can move at same speed.)
2738 #define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375))
2740 // Initialize the scrollers
2741 static void P_SpawnScrollers(void)
2743 int i;
2744 line_t *l = lines;
2746 for (i=0;i<numlines;i++,l++)
2748 fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling
2749 fixed_t dy = l->dy >> SCROLL_SHIFT;
2750 int control = -1, accel = 0; // no control sector or acceleration
2751 int special = l->special;
2753 // killough 3/7/98: Types 245-249 are same as 250-254 except that the
2754 // first side's sector's heights cause scrolling when they change, and
2755 // this linedef controls the direction and speed of the scrolling. The
2756 // most complicated linedef since donuts, but powerful :)
2758 // killough 3/15/98: Add acceleration. Types 214-218 are the same but
2759 // are accelerative.
2761 if (special >= 245 && special <= 249) // displacement scrollers
2763 special += 250-245;
2764 control = sides[*l->sidenum].sector - sectors;
2766 else
2767 if (special >= 214 && special <= 218) // accelerative scrollers
2769 accel = 1;
2770 special += 250-214;
2771 control = sides[*l->sidenum].sector - sectors;
2774 switch (special)
2776 register int s;
2778 case 250: // scroll effect ceiling
2779 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2780 Add_Scroller(sc_ceiling, -dx, dy, control, s, accel);
2781 break;
2783 case 251: // scroll effect floor
2784 case 253: // scroll and carry objects on floor
2785 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2786 Add_Scroller(sc_floor, -dx, dy, control, s, accel);
2787 if (special != 253)
2788 break;
2790 case 252: // carry objects on floor
2791 dx = FixedMul(dx,CARRYFACTOR);
2792 dy = FixedMul(dy,CARRYFACTOR);
2793 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2794 Add_Scroller(sc_carry, dx, dy, control, s, accel);
2795 break;
2797 // killough 3/1/98: scroll wall according to linedef
2798 // (same direction and speed as scrolling floors)
2799 case 254:
2800 for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;)
2801 if (s != i)
2802 Add_WallScroller(dx, dy, lines+s, control, accel);
2803 break;
2805 case 255: // killough 3/2/98: scroll according to sidedef offsets
2806 s = lines[i].sidenum[0];
2807 Add_Scroller(sc_side, -sides[s].textureoffset,
2808 sides[s].rowoffset, -1, s, accel);
2809 break;
2811 case 48: // scroll first side
2812 Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel);
2813 break;
2815 case 85: // jff 1/30/98 2-way scroll
2816 Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel);
2817 break;
2822 // killough 3/7/98 -- end generalized scroll effects
2824 ////////////////////////////////////////////////////////////////////////////
2826 // FRICTION EFFECTS
2828 // phares 3/12/98: Start of friction effects
2830 // As the player moves, friction is applied by decreasing the x and y
2831 // momentum values on each tic. By varying the percentage of decrease,
2832 // we can simulate muddy or icy conditions. In mud, the player slows
2833 // down faster. In ice, the player slows down more slowly.
2835 // The amount of friction change is controlled by the length of a linedef
2836 // with type 223. A length < 100 gives you mud. A length > 100 gives you ice.
2838 // Also, each sector where these effects are to take place is given a
2839 // new special type _______. Changing the type value at runtime allows
2840 // these effects to be turned on or off.
2842 // Sector boundaries present problems. The player should experience these
2843 // friction changes only when his feet are touching the sector floor. At
2844 // sector boundaries where floor height changes, the player can find
2845 // himself still 'in' one sector, but with his feet at the floor level
2846 // of the next sector (steps up or down). To handle this, Thinkers are used
2847 // in icy/muddy sectors. These thinkers examine each object that is touching
2848 // their sectors, looking for players whose feet are at the same level as
2849 // their floors. Players satisfying this condition are given new friction
2850 // values that are applied by the player movement code later.
2852 // killough 8/28/98:
2854 // Completely redid code, which did not need thinkers, and which put a heavy
2855 // drag on CPU. Friction is now a property of sectors, NOT objects inside
2856 // them. All objects, not just players, are affected by it, if they touch
2857 // the sector's floor. Code simpler and faster, only calling on friction
2858 // calculations when an object needs friction considered, instead of doing
2859 // friction calculations on every sector during every tic.
2861 // Although this -might- ruin Boom demo sync involving friction, it's the only
2862 // way, short of code explosion, to fix the original design bug. Fixing the
2863 // design bug in Boom's original friction code, while maintaining demo sync
2864 // under every conceivable circumstance, would double or triple code size, and
2865 // would require maintenance of buggy legacy code which is only useful for old
2866 // demos. Doom demos, which are more important IMO, are not affected by this
2867 // change.
2869 /////////////////////////////
2871 // Initialize the sectors where friction is increased or decreased
2873 static void P_SpawnFriction(void)
2875 int i;
2876 line_t *l = lines;
2878 // killough 8/28/98: initialize all sectors to normal friction first
2879 for (i = 0; i < numsectors; i++)
2881 sectors[i].friction = ORIG_FRICTION;
2882 sectors[i].movefactor = ORIG_FRICTION_FACTOR;
2885 for (i = 0 ; i < numlines ; i++,l++)
2886 if (l->special == 223)
2888 int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS;
2889 int friction = (0x1EB8*length)/0x80 + 0xD000;
2890 int movefactor, s;
2892 // The following check might seem odd. At the time of movement,
2893 // the move distance is multiplied by 'friction/0x10000', so a
2894 // higher friction value actually means 'less friction'.
2896 if (friction > ORIG_FRICTION) // ice
2897 movefactor = ((0x10092 - friction)*(0x70))/0x158;
2898 else
2899 movefactor = ((friction - 0xDB34)*(0xA))/0x80;
2901 if (mbf_features)
2902 { // killough 8/28/98: prevent odd situations
2903 if (friction > FRACUNIT)
2904 friction = FRACUNIT;
2905 if (friction < 0)
2906 friction = 0;
2907 if (movefactor < 32)
2908 movefactor = 32;
2911 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
2913 // killough 8/28/98:
2915 // Instead of spawning thinkers, which are slow and expensive,
2916 // modify the sector's own friction values. Friction should be
2917 // a property of sectors, not objects which reside inside them.
2918 // Original code scanned every object in every friction sector
2919 // on every tic, adjusting its friction, putting unnecessary
2920 // drag on CPU. New code adjusts friction of sector only once
2921 // at level startup, and then uses this friction value.
2923 sectors[s].friction = friction;
2924 sectors[s].movefactor = movefactor;
2930 // phares 3/12/98: End of friction effects
2932 ////////////////////////////////////////////////////////////////////////////
2934 ////////////////////////////////////////////////////////////////////////////
2936 // PUSH/PULL EFFECT
2938 // phares 3/20/98: Start of push/pull effects
2940 // This is where push/pull effects are applied to objects in the sectors.
2942 // There are four kinds of push effects
2944 // 1) Pushing Away
2946 // Pushes you away from a point source defined by the location of an
2947 // MT_PUSH Thing. The force decreases linearly with distance from the
2948 // source. This force crosses sector boundaries and is felt w/in a circle
2949 // whose center is at the MT_PUSH. The force is felt only if the point
2950 // MT_PUSH can see the target object.
2952 // 2) Pulling toward
2954 // Same as Pushing Away except you're pulled toward an MT_PULL point
2955 // source. This force crosses sector boundaries and is felt w/in a circle
2956 // whose center is at the MT_PULL. The force is felt only if the point
2957 // MT_PULL can see the target object.
2959 // 3) Wind
2961 // Pushes you in a constant direction. Full force above ground, half
2962 // force on the ground, nothing if you're below it (water).
2964 // 4) Current
2966 // Pushes you in a constant direction. No force above ground, full
2967 // force if on the ground or below it (water).
2969 // The magnitude of the force is controlled by the length of a controlling
2970 // linedef. The force vector for types 3 & 4 is determined by the angle
2971 // of the linedef, and is constant.
2973 // For each sector where these effects occur, the sector special type has
2974 // to have the PUSH_MASK bit set. If this bit is turned off by a switch
2975 // at run-time, the effect will not occur. The controlling sector for
2976 // types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing.
2979 #define PUSH_FACTOR 7
2981 /////////////////////////////
2983 // Add a push thinker to the thinker list
2985 static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee)
2987 pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0);
2989 p->thinker.function = T_Pusher;
2990 p->source = source;
2991 p->type = type;
2992 p->x_mag = x_mag>>FRACBITS;
2993 p->y_mag = y_mag>>FRACBITS;
2994 p->magnitude = P_AproxDistance(p->x_mag,p->y_mag);
2995 if (source) // point source exist?
2997 p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero
2998 p->x = p->source->x;
2999 p->y = p->source->y;
3001 p->affectee = affectee;
3002 P_AddThinker(&p->thinker);
3005 /////////////////////////////
3007 // PIT_PushThing determines the angle and magnitude of the effect.
3008 // The object's x and y momentum values are changed.
3010 // tmpusher belongs to the point source (MT_PUSH/MT_PULL).
3012 // killough 10/98: allow to affect things besides players
3014 pusher_t* tmpusher; // pusher structure for blockmap searches
3016 boolean PIT_PushThing(mobj_t* thing)
3018 /* killough 10/98: made more general */
3019 if (!mbf_features ?
3020 thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) :
3021 (sentient(thing) || thing->flags & MF_SHOOTABLE) &&
3022 !(thing->flags & MF_NOCLIP))
3024 angle_t pushangle;
3025 fixed_t speed;
3026 fixed_t sx = tmpusher->x;
3027 fixed_t sy = tmpusher->y;
3029 speed = (tmpusher->magnitude -
3030 ((P_AproxDistance(thing->x - sx,thing->y - sy)
3031 >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1);
3033 // killough 10/98: make magnitude decrease with square
3034 // of distance, making it more in line with real nature,
3035 // so long as it's still in range with original formula.
3037 // Removes angular distortion, and makes effort required
3038 // to stay close to source, grow increasingly hard as you
3039 // get closer, as expected. Still, it doesn't consider z :(
3041 if (speed > 0 && mbf_features)
3043 int x = (thing->x-sx) >> FRACBITS;
3044 int y = (thing->y-sy) >> FRACBITS;
3045 speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1));
3048 // If speed <= 0, you're outside the effective radius. You also have
3049 // to be able to see the push/pull source point.
3051 if (speed > 0 && P_CheckSight(thing,tmpusher->source))
3053 pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy);
3054 if (tmpusher->source->type == MT_PUSH)
3055 pushangle += ANG180; // away
3056 pushangle >>= ANGLETOFINESHIFT;
3057 thing->momx += FixedMul(speed,finecosine[pushangle]);
3058 thing->momy += FixedMul(speed,finesine[pushangle]);
3061 return true;
3064 /////////////////////////////
3066 // T_Pusher looks for all objects that are inside the radius of
3067 // the effect.
3070 void T_Pusher(pusher_t *p)
3072 sector_t *sec;
3073 mobj_t *thing;
3074 msecnode_t* node;
3075 int xspeed,yspeed;
3076 int xl,xh,yl,yh,bx,by;
3077 int radius;
3078 int ht = 0;
3080 if (!allow_pushers)
3081 return;
3083 sec = sectors + p->affectee;
3085 // Be sure the special sector type is still turned on. If so, proceed.
3086 // Else, bail out; the sector type has been changed on us.
3088 if (!(sec->special & PUSH_MASK))
3089 return;
3091 // For constant pushers (wind/current) there are 3 situations:
3093 // 1) Affected Thing is above the floor.
3095 // Apply the full force if wind, no force if current.
3097 // 2) Affected Thing is on the ground.
3099 // Apply half force if wind, full force if current.
3101 // 3) Affected Thing is below the ground (underwater effect).
3103 // Apply no force if wind, full force if current.
3105 if (p->type == p_push)
3108 // Seek out all pushable things within the force radius of this
3109 // point pusher. Crosses sectors, so use blockmap.
3111 tmpusher = p; // MT_PUSH/MT_PULL point source
3112 radius = p->radius; // where force goes to zero
3113 tmbbox[BOXTOP] = p->y + radius;
3114 tmbbox[BOXBOTTOM] = p->y - radius;
3115 tmbbox[BOXRIGHT] = p->x + radius;
3116 tmbbox[BOXLEFT] = p->x - radius;
3118 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
3119 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
3120 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
3121 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
3122 for (bx=xl ; bx<=xh ; bx++)
3123 for (by=yl ; by<=yh ; by++)
3124 P_BlockThingsIterator(bx,by,PIT_PushThing);
3125 return;
3128 // constant pushers p_wind and p_current
3130 if (sec->heightsec != -1) // special water sector?
3131 ht = sectors[sec->heightsec].floorheight;
3132 node = sec->touching_thinglist; // things touching this sector
3133 for ( ; node ; node = node->m_snext)
3135 thing = node->m_thing;
3136 if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)))
3137 continue;
3138 if (p->type == p_wind)
3140 if (sec->heightsec == -1) // NOT special water sector
3141 if (thing->z > thing->floorz) // above ground
3143 xspeed = p->x_mag; // full force
3144 yspeed = p->y_mag;
3146 else // on ground
3148 xspeed = (p->x_mag)>>1; // half force
3149 yspeed = (p->y_mag)>>1;
3151 else // special water sector
3153 if (thing->z > ht) // above ground
3155 xspeed = p->x_mag; // full force
3156 yspeed = p->y_mag;
3158 else if (thing->player->viewz < ht) // underwater
3159 xspeed = yspeed = 0; // no force
3160 else // wading in water
3162 xspeed = (p->x_mag)>>1; // half force
3163 yspeed = (p->y_mag)>>1;
3167 else // p_current
3169 if (sec->heightsec == -1) // NOT special water sector
3170 if (thing->z > sec->floorheight) // above ground
3171 xspeed = yspeed = 0; // no force
3172 else // on ground
3174 xspeed = p->x_mag; // full force
3175 yspeed = p->y_mag;
3177 else // special water sector
3178 if (thing->z > ht) // above ground
3179 xspeed = yspeed = 0; // no force
3180 else // underwater
3182 xspeed = p->x_mag; // full force
3183 yspeed = p->y_mag;
3186 thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR);
3187 thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR);
3191 /////////////////////////////
3193 // P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
3194 // NULL otherwise.
3196 mobj_t* P_GetPushThing(int s)
3198 mobj_t* thing;
3199 sector_t* sec;
3201 sec = sectors + s;
3202 thing = sec->thinglist;
3203 while (thing)
3205 switch(thing->type)
3207 case MT_PUSH:
3208 case MT_PULL:
3209 return thing;
3210 default:
3211 break;
3213 thing = thing->snext;
3215 return NULL;
3218 /////////////////////////////
3220 // Initialize the sectors where pushers are present
3223 static void P_SpawnPushers(void)
3225 int i;
3226 line_t *l = lines;
3227 register int s;
3228 mobj_t* thing;
3230 for (i = 0 ; i < numlines ; i++,l++)
3231 switch(l->special)
3233 case 224: // wind
3234 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3235 Add_Pusher(p_wind,l->dx,l->dy,NULL,s);
3236 break;
3237 case 225: // current
3238 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3239 Add_Pusher(p_current,l->dx,l->dy,NULL,s);
3240 break;
3241 case 226: // push/pull
3242 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3244 thing = P_GetPushThing(s);
3245 if (thing) // No MT_P* means no effect
3246 Add_Pusher(p_push,l->dx,l->dy,thing,s);
3248 break;
3253 // phares 3/20/98: End of Pusher effects
3255 ////////////////////////////////////////////////////////////////////////////