A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 = §ors[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 = §ors[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 = §ors[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 = §ors[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////////////////////////////////////////////////////////////////////////////