summaryrefslogtreecommitdiff
path: root/apps/plugins/doom/p_spec.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/doom/p_spec.c')
-rw-r--r--apps/plugins/doom/p_spec.c3255
1 files changed, 3255 insertions, 0 deletions
diff --git a/apps/plugins/doom/p_spec.c b/apps/plugins/doom/p_spec.c
new file mode 100644
index 0000000000..2876b7f4e5
--- /dev/null
+++ b/apps/plugins/doom/p_spec.c
@@ -0,0 +1,3255 @@
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
98static anim_t* lastanim;
99static anim_t* anims; // new structure w/o limits -- killough
100static size_t maxanims;
101
102// killough 3/7/98: Initialize generalized scrolling
103static void P_SpawnScrollers(void);
104
105static void P_SpawnFriction(void); // phares 3/16/98
106static void P_SpawnPushers(void); // phares 3/20/98
107
108extern int allow_pushers;
109extern int variable_friction; // phares 3/20/98
110
111//
112// P_InitPicAnims
113//
114// Load the table of animation definitions, checking for existence of
115// the start and end of each frame. If the start doesn't exist the sequence
116// is skipped, if the last doesn't exist, BOOM exits.
117//
118// Wall/Flat animation sequences, defined by name of first and last frame,
119// The full animation sequence is given using all lumps between the start
120// and end entry, in the order found in the WAD file.
121//
122// This routine modified to read its data from a predefined lump or
123// PWAD lump called ANIMATED rather than a static table in this module to
124// allow wad designers to insert or modify animation sequences.
125//
126// Lump format is an array of byte packed animdef_t structures, terminated
127// by a structure with istexture == -1. The lump can be generated from a
128// text source file using SWANTBLS.EXE, distributed with the BOOM utils.
129// The standard list of switches and animations is contained in the example
130// source text file DEFSWANI.DAT also in the BOOM util distribution.
131//
132//
133void P_InitPicAnims (void)
134{
135 int i;
136 const animdef_t *animdefs; //jff 3/23/98 pointer to animation lump
137 int lump = W_GetNumForName("ANIMATED"); // cph - new wad lump handling
138 // Init animation
139
140 //jff 3/23/98 read from predefined or wad lump instead of table
141 animdefs = (const animdef_t *)W_CacheLumpNum(lump);
142
143 lastanim = anims;
144 for (i=0 ; animdefs[i].istexture != -1 ; i++)
145 {
146 // 1/11/98 killough -- removed limit by array-doubling
147 if (lastanim >= anims + maxanims)
148 {
149 size_t newmax = maxanims ? maxanims*2 : MAXANIMS;
150 anims = realloc(anims, newmax*sizeof(*anims)); // killough
151 lastanim = anims + maxanims;
152 maxanims = newmax;
153 }
154
155 if (animdefs[i].istexture)
156 {
157 // different episode ?
158 if (R_CheckTextureNumForName(animdefs[i].startname) == -1)
159 continue;
160
161 lastanim->picnum = R_TextureNumForName (animdefs[i].endname);
162 lastanim->basepic = R_TextureNumForName (animdefs[i].startname);
163 }
164 else
165 {
166 if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98
167 continue;
168
169 lastanim->picnum = R_FlatNumForName (animdefs[i].endname);
170 lastanim->basepic = R_FlatNumForName (animdefs[i].startname);
171 }
172
173 lastanim->istexture = animdefs[i].istexture;
174 lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
175
176 if (lastanim->numpics < 2)
177 I_Error ("P_InitPicAnims: bad cycle from %s to %s",
178 animdefs[i].startname,
179 animdefs[i].endname);
180
181 lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG()
182 lastanim++;
183 }
184 W_UnlockLumpNum(lump);
185}
186
187///////////////////////////////////////////////////////////////
188//
189// Linedef and Sector Special Implementation Utility Functions
190//
191///////////////////////////////////////////////////////////////
192
193//
194// getSide()
195//
196// Will return a side_t*
197// given the number of the current sector,
198// the line number, and the side (0/1) that you want.
199//
200// Note: if side=1 is specified, it must exist or results undefined
201//
202side_t* getSide
203( int currentSector,
204 int line,
205 int side )
206{
207 return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
208}
209
210
211//
212// getSector()
213//
214// Will return a sector_t*
215// given the number of the current sector,
216// the line number and the side (0/1) that you want.
217//
218// Note: if side=1 is specified, it must exist or results undefined
219//
220sector_t* getSector
221( int currentSector,
222 int line,
223 int side )
224{
225 return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
226}
227
228
229//
230// twoSided()
231//
232// Given the sector number and the line number,
233// it will tell you whether the line is two-sided or not.
234//
235// modified to return actual two-sidedness rather than presence
236// of 2S flag unless compatibility optioned
237//
238int twoSided
239( int sector,
240 int line )
241{
242 //jff 1/26/98 return what is actually needed, whether the line
243 //has two sidedefs, rather than whether the 2S flag is set
244
245 return comp[comp_model] ?
246 (sectors[sector].lines[line])->flags & ML_TWOSIDED
247 :
248 (sectors[sector].lines[line])->sidenum[1] != -1;
249}
250
251
252//
253// getNextSector()
254//
255// Return sector_t * of sector next to current across line.
256//
257// Note: returns NULL if not two-sided line, or both sides refer to sector
258//
259sector_t* getNextSector
260( line_t* line,
261 sector_t* sec )
262{
263 //jff 1/26/98 check unneeded since line->backsector already
264 //returns NULL if the line is not two sided, and does so from
265 //the actual two-sidedness of the line, rather than its 2S flag
266
267 if (comp[comp_model])
268 {
269 if (!(line->flags & ML_TWOSIDED))
270 return NULL;
271 }
272
273 if (line->frontsector == sec) {
274 if (comp[comp_model] || line->backsector!=sec)
275 return line->backsector; //jff 5/3/98 don't retn sec unless compatibility
276 else // fixes an intra-sector line breaking functions
277 return NULL; // like floor->highest floor
278 }
279 return line->frontsector;
280}
281
282
283//
284// P_FindLowestFloorSurrounding()
285//
286// Returns the fixed point value of the lowest floor height
287// in the sector passed or its surrounding sectors.
288//
289fixed_t P_FindLowestFloorSurrounding(sector_t* sec)
290{
291 int i;
292 line_t* check;
293 sector_t* other;
294 fixed_t floor = sec->floorheight;
295
296 for (i=0 ;i < sec->linecount ; i++)
297 {
298 check = sec->lines[i];
299 other = getNextSector(check,sec);
300
301 if (!other)
302 continue;
303
304 if (other->floorheight < floor)
305 floor = other->floorheight;
306 }
307 return floor;
308}
309
310
311//
312// P_FindHighestFloorSurrounding()
313//
314// Passed a sector, returns the fixed point value of the largest
315// floor height in the surrounding sectors, not including that passed
316//
317// NOTE: if no surrounding sector exists -32000*FRACUINT is returned
318// if compatibility then -500*FRACUNIT is the smallest return possible
319//
320fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
321{
322 int i;
323 line_t* check;
324 sector_t* other;
325 fixed_t floor = -500*FRACUNIT;
326
327 //jff 1/26/98 Fix initial value for floor to not act differently
328 //in sections of wad that are below -500 units
329 if (!comp[comp_model]) /* jff 3/12/98 avoid ovf */
330 floor = -32000*FRACUNIT; // in height calculations
331
332 for (i=0 ;i < sec->linecount ; i++)
333 {
334 check = sec->lines[i];
335 other = getNextSector(check,sec);
336
337 if (!other)
338 continue;
339
340 if (other->floorheight > floor)
341 floor = other->floorheight;
342 }
343 return floor;
344}
345
346
347//
348// P_FindNextHighestFloor()
349//
350// Passed a sector and a floor height, returns the fixed point value
351// of the smallest floor height in a surrounding sector larger than
352// the floor height passed. If no such height exists the floorheight
353// passed is returned.
354//
355// Rewritten by Lee Killough to avoid fixed array and to be faster
356//
357fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight)
358{
359 sector_t *other;
360 int i;
361
362 for (i=0 ;i < sec->linecount ; i++)
363 if ((other = getNextSector(sec->lines[i],sec)) &&
364 other->floorheight > currentheight)
365 {
366 int height = other->floorheight;
367 while (++i < sec->linecount)
368 if ((other = getNextSector(sec->lines[i],sec)) &&
369 other->floorheight < height &&
370 other->floorheight > currentheight)
371 height = other->floorheight;
372 return height;
373 }
374 return currentheight;
375}
376
377
378//
379// P_FindNextLowestFloor()
380//
381// Passed a sector and a floor height, returns the fixed point value
382// of the largest floor height in a surrounding sector smaller than
383// the floor height passed. If no such height exists the floorheight
384// passed is returned.
385//
386// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
387//
388fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight)
389{
390 sector_t *other;
391 int i;
392
393 for (i=0 ;i < sec->linecount ; i++)
394 if ((other = getNextSector(sec->lines[i],sec)) &&
395 other->floorheight < currentheight)
396 {
397 int height = other->floorheight;
398 while (++i < sec->linecount)
399 if ((other = getNextSector(sec->lines[i],sec)) &&
400 other->floorheight > height &&
401 other->floorheight < currentheight)
402 height = other->floorheight;
403 return height;
404 }
405 return currentheight;
406}
407
408
409//
410// P_FindNextLowestCeiling()
411//
412// Passed a sector and a ceiling height, returns the fixed point value
413// of the largest ceiling height in a surrounding sector smaller than
414// the ceiling height passed. If no such height exists the ceiling height
415// passed is returned.
416//
417// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
418//
419fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight)
420{
421 sector_t *other;
422 int i;
423
424 for (i=0 ;i < sec->linecount ; i++)
425 if ((other = getNextSector(sec->lines[i],sec)) &&
426 other->ceilingheight < currentheight)
427 {
428 int height = other->ceilingheight;
429 while (++i < sec->linecount)
430 if ((other = getNextSector(sec->lines[i],sec)) &&
431 other->ceilingheight > height &&
432 other->ceilingheight < currentheight)
433 height = other->ceilingheight;
434 return height;
435 }
436 return currentheight;
437}
438
439
440//
441// P_FindNextHighestCeiling()
442//
443// Passed a sector and a ceiling height, returns the fixed point value
444// of the smallest ceiling height in a surrounding sector larger than
445// the ceiling height passed. If no such height exists the ceiling height
446// passed is returned.
447//
448// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
449//
450fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight)
451{
452 sector_t *other;
453 int i;
454
455 for (i=0 ;i < sec->linecount ; i++)
456 if ((other = getNextSector(sec->lines[i],sec)) &&
457 other->ceilingheight > currentheight)
458 {
459 int height = other->ceilingheight;
460 while (++i < sec->linecount)
461 if ((other = getNextSector(sec->lines[i],sec)) &&
462 other->ceilingheight < height &&
463 other->ceilingheight > currentheight)
464 height = other->ceilingheight;
465 return height;
466 }
467 return currentheight;
468}
469
470
471//
472// P_FindLowestCeilingSurrounding()
473//
474// Passed a sector, returns the fixed point value of the smallest
475// ceiling height in the surrounding sectors, not including that passed
476//
477// NOTE: if no surrounding sector exists 32000*FRACUINT is returned
478// but if compatibility then INT_MAX is the return
479//
480fixed_t P_FindLowestCeilingSurrounding(sector_t* sec)
481{
482 int i;
483 line_t* check;
484 sector_t* other;
485 fixed_t height = INT_MAX;
486
487 /* jff 3/12/98 avoid ovf in height calculations */
488 if (!comp[comp_model]) height = 32000*FRACUNIT;
489
490 for (i=0 ;i < sec->linecount ; i++)
491 {
492 check = sec->lines[i];
493 other = getNextSector(check,sec);
494
495 if (!other)
496 continue;
497
498 if (other->ceilingheight < height)
499 height = other->ceilingheight;
500 }
501 return height;
502}
503
504
505//
506// P_FindHighestCeilingSurrounding()
507//
508// Passed a sector, returns the fixed point value of the largest
509// ceiling height in the surrounding sectors, not including that passed
510//
511// NOTE: if no surrounding sector exists -32000*FRACUINT is returned
512// but if compatibility then 0 is the smallest return possible
513//
514fixed_t P_FindHighestCeilingSurrounding(sector_t* sec)
515{
516 int i;
517 line_t* check;
518 sector_t* other;
519 fixed_t height = 0;
520
521 /* jff 1/26/98 Fix initial value for floor to not act differently
522 * in sections of wad that are below 0 units
523 * jff 3/12/98 avoid ovf in height calculations */
524 if (!comp[comp_model]) height = -32000*FRACUNIT;
525
526 for (i=0 ;i < sec->linecount ; i++)
527 {
528 check = sec->lines[i];
529 other = getNextSector(check,sec);
530
531 if (!other)
532 continue;
533
534 if (other->ceilingheight > height)
535 height = other->ceilingheight;
536 }
537 return height;
538}
539
540
541//
542// P_FindShortestTextureAround()
543//
544// Passed a sector number, returns the shortest lower texture on a
545// linedef bounding the sector.
546//
547// Note: If no lower texture exists 32000*FRACUNIT is returned.
548// but if compatibility then INT_MAX is returned
549//
550// jff 02/03/98 Add routine to find shortest lower texture
551//
552fixed_t P_FindShortestTextureAround(int secnum)
553{
554 int minsize = INT_MAX;
555 side_t* side;
556 int i;
557 sector_t *sec = &sectors[secnum];
558
559 if (!comp[comp_model])
560 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow in height calcs
561
562 for (i = 0; i < sec->linecount; i++)
563 {
564 if (twoSided(secnum, i))
565 {
566 side = getSide(secnum,i,0);
567 if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder
568 if (textureheight[side->bottomtexture] < minsize)
569 minsize = textureheight[side->bottomtexture];
570 side = getSide(secnum,i,1);
571 if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder
572 if (textureheight[side->bottomtexture] < minsize)
573 minsize = textureheight[side->bottomtexture];
574 }
575 }
576 return minsize;
577}
578
579
580//
581// P_FindShortestUpperAround()
582//
583// Passed a sector number, returns the shortest upper texture on a
584// linedef bounding the sector.
585//
586// Note: If no upper texture exists 32000*FRACUNIT is returned.
587// but if compatibility then INT_MAX is returned
588//
589// jff 03/20/98 Add routine to find shortest upper texture
590//
591fixed_t P_FindShortestUpperAround(int secnum)
592{
593 int minsize = INT_MAX;
594 side_t* side;
595 int i;
596 sector_t *sec = &sectors[secnum];
597
598 if (!comp[comp_model])
599 minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow
600 // in height calcs
601 for (i = 0; i < sec->linecount; i++)
602 {
603 if (twoSided(secnum, i))
604 {
605 side = getSide(secnum,i,0);
606 if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder
607 if (textureheight[side->toptexture] < minsize)
608 minsize = textureheight[side->toptexture];
609 side = getSide(secnum,i,1);
610 if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder
611 if (textureheight[side->toptexture] < minsize)
612 minsize = textureheight[side->toptexture];
613 }
614 }
615 return minsize;
616}
617
618
619//
620// P_FindModelFloorSector()
621//
622// Passed a floor height and a sector number, return a pointer to a
623// a sector with that floor height across the lowest numbered two sided
624// line surrounding the sector.
625//
626// Note: If no sector at that height bounds the sector passed, return NULL
627//
628// jff 02/03/98 Add routine to find numeric model floor
629// around a sector specified by sector number
630// jff 3/14/98 change first parameter to plain height to allow call
631// from routine not using floormove_t
632//
633sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum)
634{
635 int i;
636 sector_t *sec=NULL;
637 int linecount;
638
639 sec = &sectors[secnum]; //jff 3/2/98 woops! better do this
640 //jff 5/23/98 don't disturb sec->linecount while searching
641 // but allow early exit in old demos
642 linecount = sec->linecount;
643 for (i = 0; i < (demo_compatibility && sec->linecount<linecount?
644 sec->linecount : linecount); i++)
645 {
646 if ( twoSided(secnum, i) )
647 {
648 if (getSide(secnum,i,0)->sector-sectors == secnum)
649 sec = getSector(secnum,i,1);
650 else
651 sec = getSector(secnum,i,0);
652
653 if (sec->floorheight == floordestheight)
654 return sec;
655 }
656 }
657 return NULL;
658}
659
660
661//
662// P_FindModelCeilingSector()
663//
664// Passed a ceiling height and a sector number, return a pointer to a
665// a sector with that ceiling height across the lowest numbered two sided
666// line surrounding the sector.
667//
668// Note: If no sector at that height bounds the sector passed, return NULL
669//
670// jff 02/03/98 Add routine to find numeric model ceiling
671// around a sector specified by sector number
672// used only from generalized ceiling types
673// jff 3/14/98 change first parameter to plain height to allow call
674// from routine not using ceiling_t
675//
676sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum)
677{
678 int i;
679 sector_t *sec=NULL;
680 int linecount;
681
682 sec = &sectors[secnum]; //jff 3/2/98 woops! better do this
683 //jff 5/23/98 don't disturb sec->linecount while searching
684 // but allow early exit in old demos
685 linecount = sec->linecount;
686 for (i = 0; i < (demo_compatibility && sec->linecount<linecount?
687 sec->linecount : linecount); i++)
688 {
689 if ( twoSided(secnum, i) )
690 {
691 if (getSide(secnum,i,0)->sector-sectors == secnum)
692 sec = getSector(secnum,i,1);
693 else
694 sec = getSector(secnum,i,0);
695
696 if (sec->ceilingheight == ceildestheight)
697 return sec;
698 }
699 }
700 return NULL;
701}
702
703//
704// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
705//
706
707// Find the next sector with the same tag as a linedef.
708// Rewritten by Lee Killough to use chained hashing to improve speed
709
710int P_FindSectorFromLineTag(const line_t *line, int start)
711{
712 start = start >= 0 ? sectors[start].nexttag :
713 sectors[(unsigned) line->tag % (unsigned) numsectors].firsttag;
714 while (start >= 0 && sectors[start].tag != line->tag)
715 start = sectors[start].nexttag;
716 return start;
717}
718
719// killough 4/16/98: Same thing, only for linedefs
720
721int P_FindLineFromLineTag(const line_t *line, int start)
722{
723 start = start >= 0 ? lines[start].nexttag :
724 lines[(unsigned) line->tag % (unsigned) numlines].firsttag;
725 while (start >= 0 && lines[start].tag != line->tag)
726 start = lines[start].nexttag;
727 return start;
728}
729
730// Hash the sector tags across the sectors and linedefs.
731static void P_InitTagLists(void)
732{
733 register int i;
734
735 for (i=numsectors; --i>=0; ) // Initially make all slots empty.
736 sectors[i].firsttag = -1;
737 for (i=numsectors; --i>=0; ) // Proceed from last to first sector
738 { // so that lower sectors appear first
739 int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func
740 sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain
741 sectors[j].firsttag = i;
742 }
743
744 // killough 4/17/98: same thing, only for linedefs
745
746 for (i=numlines; --i>=0; ) // Initially make all slots empty.
747 lines[i].firsttag = -1;
748 for (i=numlines; --i>=0; ) // Proceed from last to first linedef
749 { // so that lower linedefs appear first
750 int j = (unsigned) lines[i].tag % (unsigned) numlines; // Hash func
751 lines[i].nexttag = lines[j].firsttag; // Prepend linedef to chain
752 lines[j].firsttag = i;
753 }
754}
755
756//
757// P_FindMinSurroundingLight()
758//
759// Passed a sector and a light level, returns the smallest light level
760// in a surrounding sector less than that passed. If no smaller light
761// level exists, the light level passed is returned.
762//
763int P_FindMinSurroundingLight
764( sector_t* sector,
765 int max )
766{
767 int i;
768 int min;
769 line_t* line;
770 sector_t* check;
771
772 min = max;
773 for (i=0 ; i < sector->linecount ; i++)
774 {
775 line = sector->lines[i];
776 check = getNextSector(line,sector);
777
778 if (!check)
779 continue;
780
781 if (check->lightlevel < min)
782 min = check->lightlevel;
783 }
784 return min;
785}
786
787
788//
789// P_CanUnlockGenDoor()
790//
791// Passed a generalized locked door linedef and a player, returns whether
792// the player has the keys necessary to unlock that door.
793//
794// Note: The linedef passed MUST be a generalized locked door type
795// or results are undefined.
796//
797// jff 02/05/98 routine added to test for unlockability of
798// generalized locked doors
799//
800boolean P_CanUnlockGenDoor
801( line_t* line,
802 player_t* player)
803{
804 // does this line special distinguish between skulls and keys?
805 int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift;
806
807 // determine for each case of lock type if player's keys are adequate
808 switch((line->special & LockedKey)>>LockedKeyShift)
809 {
810 case AnyKey:
811 if
812 (
813 !player->cards[it_redcard] &&
814 !player->cards[it_redskull] &&
815 !player->cards[it_bluecard] &&
816 !player->cards[it_blueskull] &&
817 !player->cards[it_yellowcard] &&
818 !player->cards[it_yellowskull]
819 )
820 {
821 player->message = 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? PD_REDK : 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? PD_BLUEK : 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? PD_YELLOWK : 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? PD_REDK : 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? PD_BLUEK : 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? PD_YELLOWK : 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 = 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 = 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//
950int 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 (int)sec->floordata;
959 case ceiling_special:
960 return (int)sec->ceilingdata;
961 case lighting_special:
962 return (int)sec->lightingdata;
963 }
964 return 1; // 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 int episode;
2398
2399 episode = 1;
2400 if (W_CheckNumForName("texture2") >= 0)
2401 episode = 2;
2402
2403 // See if -timer needs to be used.
2404 levelTimer = false;
2405
2406 i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play
2407 if (i && deathmatch)
2408 {
2409 levelTimer = true;
2410 levelTimeCount = 20 * 60 * TICRATE;
2411 }
2412
2413 i = M_CheckParm("-timer"); // user defined timer on game play
2414 if (i && deathmatch)
2415 {
2416 int time;
2417 time = atoi(myargv[i+1]) * 60 * TICRATE;
2418 levelTimer = true;
2419 levelTimeCount = time;
2420 }
2421
2422 // See if -frags has been used
2423 levelFragLimit = false;
2424 i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support
2425 if (i && deathmatch)
2426 {
2427 int frags;
2428 frags = atoi(myargv[i+1]);
2429 if (frags <= 0) frags = 10; // default 10 if no count provided
2430 levelFragLimit = true;
2431 levelFragLimitCount = frags;
2432 }
2433
2434
2435 // Init special sectors.
2436 sector = sectors;
2437 for (i=0 ; i<numsectors ; i++, sector++)
2438 {
2439 if (!sector->special)
2440 continue;
2441
2442 if (sector->special&SECRET_MASK) //jff 3/15/98 count extended
2443 totalsecret++; // secret sectors too
2444
2445 switch (sector->special&31)
2446 {
2447 case 1:
2448 // random off
2449 P_SpawnLightFlash (sector);
2450 break;
2451
2452 case 2:
2453 // strobe fast
2454 P_SpawnStrobeFlash(sector,FASTDARK,0);
2455 break;
2456
2457 case 3:
2458 // strobe slow
2459 P_SpawnStrobeFlash(sector,SLOWDARK,0);
2460 break;
2461
2462 case 4:
2463 // strobe fast/death slime
2464 P_SpawnStrobeFlash(sector,FASTDARK,0);
2465 sector->special |= 3<<DAMAGE_SHIFT; //jff 3/14/98 put damage bits in
2466 break;
2467
2468 case 8:
2469 // glowing light
2470 P_SpawnGlowingLight(sector);
2471 break;
2472 case 9:
2473 // secret sector
2474 if (sector->special<32) //jff 3/14/98 bits don't count unless not
2475 totalsecret++; // a generalized sector type
2476 break;
2477
2478 case 10:
2479 // door close in 30 seconds
2480 P_SpawnDoorCloseIn30 (sector);
2481 break;
2482
2483 case 12:
2484 // sync strobe slow
2485 P_SpawnStrobeFlash (sector, SLOWDARK, 1);
2486 break;
2487
2488 case 13:
2489 // sync strobe fast
2490 P_SpawnStrobeFlash (sector, FASTDARK, 1);
2491 break;
2492
2493 case 14:
2494 // door raise in 5 minutes
2495 P_SpawnDoorRaiseIn5Mins (sector, i);
2496 break;
2497
2498 case 17:
2499 // fire flickering
2500 P_SpawnFireFlicker(sector);
2501 break;
2502 }
2503 }
2504
2505 P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme
2506
2507 P_RemoveAllActivePlats(); // killough
2508
2509 for (i = 0;i < MAXBUTTONS;i++)
2510 memset(&buttonlist[i],0,sizeof(button_t));
2511
2512 // P_InitTagLists() must be called before P_FindSectorFromLineTag()
2513 // or P_FindLineFromLineTag() can be called.
2514
2515 P_InitTagLists(); // killough 1/30/98: Create xref tables for tags
2516
2517 P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers
2518
2519 P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs
2520
2521 P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
2522
2523 for (i=0; i<numlines; i++)
2524 switch (lines[i].special)
2525 {
2526 int s, sec;
2527
2528 // killough 3/7/98:
2529 // support for drawn heights coming from different sector
2530 case 242:
2531 sec = sides[*lines[i].sidenum].sector-sectors;
2532 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2533 sectors[s].heightsec = sec;
2534 break;
2535
2536 // killough 3/16/98: Add support for setting
2537 // floor lighting independently (e.g. lava)
2538 case 213:
2539 sec = sides[*lines[i].sidenum].sector-sectors;
2540 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2541 sectors[s].floorlightsec = sec;
2542 break;
2543
2544 // killough 4/11/98: Add support for setting
2545 // ceiling lighting independently
2546 case 261:
2547 sec = sides[*lines[i].sidenum].sector-sectors;
2548 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2549 sectors[s].ceilinglightsec = sec;
2550 break;
2551
2552 // killough 10/98:
2553 //
2554 // Support for sky textures being transferred from sidedefs.
2555 // Allows scrolling and other effects (but if scrolling is
2556 // used, then the same sector tag needs to be used for the
2557 // sky sector, the sky-transfer linedef, and the scroll-effect
2558 // linedef). Still requires user to use F_SKY1 for the floor
2559 // or ceiling texture, to distinguish floor and ceiling sky.
2560
2561 case 271: // Regular sky
2562 case 272: // Same, only flipped
2563 for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;)
2564 sectors[s].sky = i | PL_SKYFLAT;
2565 break;
2566 }
2567}
2568
2569// killough 2/28/98:
2570//
2571// This function, with the help of r_plane.c and r_bsp.c, supports generalized
2572// scrolling floors and walls, with optional mobj-carrying properties, e.g.
2573// conveyor belts, rivers, etc. A linedef with a special type affects all
2574// tagged sectors the same way, by creating scrolling and/or object-carrying
2575// properties. Multiple linedefs may be used on the same sector and are
2576// cumulative, although the special case of scrolling a floor and carrying
2577// things on it, requires only one linedef. The linedef's direction determines
2578// the scrolling direction, and the linedef's length determines the scrolling
2579// speed. This was designed so that an edge around the sector could be used to
2580// control the direction of the sector's scrolling, which is usually what is
2581// desired.
2582//
2583// Process the active scrollers.
2584//
2585// This is the main scrolling code
2586// killough 3/7/98
2587
2588void T_Scroll(scroll_t *s)
2589{
2590 fixed_t dx = s->dx, dy = s->dy;
2591
2592 if (s->control != -1)
2593 { // compute scroll amounts based on a sector's height changes
2594 fixed_t height = sectors[s->control].floorheight +
2595 sectors[s->control].ceilingheight;
2596 fixed_t delta = height - s->last_height;
2597 s->last_height = height;
2598 dx = FixedMul(dx, delta);
2599 dy = FixedMul(dy, delta);
2600 }
2601
2602 // killough 3/14/98: Add acceleration
2603 if (s->accel)
2604 {
2605 s->vdx = dx += s->vdx;
2606 s->vdy = dy += s->vdy;
2607 }
2608
2609 if (!(dx | dy)) // no-op if both (x,y) offsets 0
2610 return;
2611
2612 switch (s->type)
2613 {
2614 side_t *side;
2615 sector_t *sec;
2616 fixed_t height, waterheight; // killough 4/4/98: add waterheight
2617 msecnode_t *node;
2618 mobj_t *thing;
2619
2620 case sc_side: // killough 3/7/98: Scroll wall texture
2621 side = sides + s->affectee;
2622 side->textureoffset += dx;
2623 side->rowoffset += dy;
2624 break;
2625
2626 case sc_floor: // killough 3/7/98: Scroll floor texture
2627 sec = sectors + s->affectee;
2628 sec->floor_xoffs += dx;
2629 sec->floor_yoffs += dy;
2630 break;
2631
2632 case sc_ceiling: // killough 3/7/98: Scroll ceiling texture
2633 sec = sectors + s->affectee;
2634 sec->ceiling_xoffs += dx;
2635 sec->ceiling_yoffs += dy;
2636 break;
2637
2638 case sc_carry:
2639
2640 // killough 3/7/98: Carry things on floor
2641 // killough 3/20/98: use new sector list which reflects true members
2642 // killough 3/27/98: fix carrier bug
2643 // killough 4/4/98: Underwater, carry things even w/o gravity
2644
2645 sec = sectors + s->affectee;
2646 height = sec->floorheight;
2647 waterheight = sec->heightsec != -1 &&
2648 sectors[sec->heightsec].floorheight > height ?
2649 sectors[sec->heightsec].floorheight : INT_MIN;
2650
2651 for (node = sec->touching_thinglist; node; node = node->m_snext)
2652 if (!((thing = node->m_thing)->flags & MF_NOCLIP) &&
2653 (!(thing->flags & MF_NOGRAVITY || thing->z > height) ||
2654 thing->z < waterheight))
2655 {
2656 // Move objects only if on floor or underwater,
2657 // non-floating, and clipped.
2658 thing->momx += dx;
2659 thing->momy += dy;
2660 }
2661 break;
2662
2663 case sc_carry_ceiling: // to be added later
2664 break;
2665 }
2666}
2667
2668//
2669// Add_Scroller()
2670//
2671// Add a generalized scroller to the thinker list.
2672//
2673// type: the enumerated type of scrolling: floor, ceiling, floor carrier,
2674// wall, floor carrier & scroller
2675//
2676// (dx,dy): the direction and speed of the scrolling or its acceleration
2677//
2678// control: the sector whose heights control this scroller's effect
2679// remotely, or -1 if no control sector
2680//
2681// affectee: the index of the affected object (sector or sidedef)
2682//
2683// accel: non-zero if this is an accelerative effect
2684//
2685
2686static void Add_Scroller(int type, fixed_t dx, fixed_t dy,
2687 int control, int affectee, int accel)
2688{
2689 scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0);
2690 s->thinker.function = T_Scroll;
2691 s->type = type;
2692 s->dx = dx;
2693 s->dy = dy;
2694 s->accel = accel;
2695 s->vdx = s->vdy = 0;
2696 if ((s->control = control) != -1)
2697 s->last_height =
2698 sectors[control].floorheight + sectors[control].ceilingheight;
2699 s->affectee = affectee;
2700 P_AddThinker(&s->thinker);
2701}
2702
2703// Adds wall scroller. Scroll amount is rotated with respect to wall's
2704// linedef first, so that scrolling towards the wall in a perpendicular
2705// direction is translated into vertical motion, while scrolling along
2706// the wall in a parallel direction is translated into horizontal motion.
2707//
2708// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff
2709//
2710// killough 10/98:
2711// fix scrolling aliasing problems, caused by long linedefs causing overflowing
2712
2713static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l,
2714 int control, int accel)
2715{
2716 fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d;
2717 if (y > x)
2718 d = x, x = y, y = d;
2719 d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90)
2720 >> ANGLETOFINESHIFT]);
2721
2722 // CPhipps - Import scroller calc overflow fix, compatibility optioned
2723 if (compatibility_level >= lxdoom_1_compatibility) {
2724 x = (fixed_t)(((int_64_t)dy * -(int_64_t)l->dy - (int_64_t)dx * (int_64_t)l->dx) / (int_64_t)d); // killough 10/98:
2725 y = (fixed_t)(((int_64_t)dy * (int_64_t)l->dx - (int_64_t)dx * (int_64_t)l->dy) / (int_64_t)d); // Use long long arithmetic
2726 } else {
2727 x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d);
2728 y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d);
2729 }
2730 Add_Scroller(sc_side, x, y, control, *l->sidenum, accel);
2731}
2732
2733// Amount (dx,dy) vector linedef is shifted right to get scroll amount
2734#define SCROLL_SHIFT 5
2735
2736// Factor to scale scrolling effect into mobj-carrying properties = 3/32.
2737// (This is so scrolling floors and objects on them can move at same speed.)
2738#define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375))
2739
2740// Initialize the scrollers
2741static void P_SpawnScrollers(void)
2742{
2743 int i;
2744 line_t *l = lines;
2745
2746 for (i=0;i<numlines;i++,l++)
2747 {
2748 fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling
2749 fixed_t dy = l->dy >> SCROLL_SHIFT;
2750 int control = -1, accel = 0; // no control sector or acceleration
2751 int special = l->special;
2752
2753 // killough 3/7/98: Types 245-249 are same as 250-254 except that the
2754 // first side's sector's heights cause scrolling when they change, and
2755 // this linedef controls the direction and speed of the scrolling. The
2756 // most complicated linedef since donuts, but powerful :)
2757 //
2758 // killough 3/15/98: Add acceleration. Types 214-218 are the same but
2759 // are accelerative.
2760
2761 if (special >= 245 && special <= 249) // displacement scrollers
2762 {
2763 special += 250-245;
2764 control = sides[*l->sidenum].sector - sectors;
2765 }
2766 else
2767 if (special >= 214 && special <= 218) // accelerative scrollers
2768 {
2769 accel = 1;
2770 special += 250-214;
2771 control = sides[*l->sidenum].sector - sectors;
2772 }
2773
2774 switch (special)
2775 {
2776 register int s;
2777
2778 case 250: // scroll effect ceiling
2779 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2780 Add_Scroller(sc_ceiling, -dx, dy, control, s, accel);
2781 break;
2782
2783 case 251: // scroll effect floor
2784 case 253: // scroll and carry objects on floor
2785 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2786 Add_Scroller(sc_floor, -dx, dy, control, s, accel);
2787 if (special != 253)
2788 break;
2789
2790 case 252: // carry objects on floor
2791 dx = FixedMul(dx,CARRYFACTOR);
2792 dy = FixedMul(dy,CARRYFACTOR);
2793 for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;)
2794 Add_Scroller(sc_carry, dx, dy, control, s, accel);
2795 break;
2796
2797 // killough 3/1/98: scroll wall according to linedef
2798 // (same direction and speed as scrolling floors)
2799 case 254:
2800 for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;)
2801 if (s != i)
2802 Add_WallScroller(dx, dy, lines+s, control, accel);
2803 break;
2804
2805 case 255: // killough 3/2/98: scroll according to sidedef offsets
2806 s = lines[i].sidenum[0];
2807 Add_Scroller(sc_side, -sides[s].textureoffset,
2808 sides[s].rowoffset, -1, s, accel);
2809 break;
2810
2811 case 48: // scroll first side
2812 Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel);
2813 break;
2814
2815 case 85: // jff 1/30/98 2-way scroll
2816 Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel);
2817 break;
2818 }
2819 }
2820}
2821
2822// killough 3/7/98 -- end generalized scroll effects
2823
2824////////////////////////////////////////////////////////////////////////////
2825//
2826// FRICTION EFFECTS
2827//
2828// phares 3/12/98: Start of friction effects
2829//
2830// As the player moves, friction is applied by decreasing the x and y
2831// momentum values on each tic. By varying the percentage of decrease,
2832// we can simulate muddy or icy conditions. In mud, the player slows
2833// down faster. In ice, the player slows down more slowly.
2834//
2835// The amount of friction change is controlled by the length of a linedef
2836// with type 223. A length < 100 gives you mud. A length > 100 gives you ice.
2837//
2838// Also, each sector where these effects are to take place is given a
2839// new special type _______. Changing the type value at runtime allows
2840// these effects to be turned on or off.
2841//
2842// Sector boundaries present problems. The player should experience these
2843// friction changes only when his feet are touching the sector floor. At
2844// sector boundaries where floor height changes, the player can find
2845// himself still 'in' one sector, but with his feet at the floor level
2846// of the next sector (steps up or down). To handle this, Thinkers are used
2847// in icy/muddy sectors. These thinkers examine each object that is touching
2848// their sectors, looking for players whose feet are at the same level as
2849// their floors. Players satisfying this condition are given new friction
2850// values that are applied by the player movement code later.
2851//
2852// killough 8/28/98:
2853//
2854// Completely redid code, which did not need thinkers, and which put a heavy
2855// drag on CPU. Friction is now a property of sectors, NOT objects inside
2856// them. All objects, not just players, are affected by it, if they touch
2857// the sector's floor. Code simpler and faster, only calling on friction
2858// calculations when an object needs friction considered, instead of doing
2859// friction calculations on every sector during every tic.
2860//
2861// Although this -might- ruin Boom demo sync involving friction, it's the only
2862// way, short of code explosion, to fix the original design bug. Fixing the
2863// design bug in Boom's original friction code, while maintaining demo sync
2864// under every conceivable circumstance, would double or triple code size, and
2865// would require maintenance of buggy legacy code which is only useful for old
2866// demos. Doom demos, which are more important IMO, are not affected by this
2867// change.
2868//
2869/////////////////////////////
2870//
2871// Initialize the sectors where friction is increased or decreased
2872
2873static void P_SpawnFriction(void)
2874{
2875 int i;
2876 line_t *l = lines;
2877
2878 // killough 8/28/98: initialize all sectors to normal friction first
2879 for (i = 0; i < numsectors; i++)
2880 {
2881 sectors[i].friction = ORIG_FRICTION;
2882 sectors[i].movefactor = ORIG_FRICTION_FACTOR;
2883 }
2884
2885 for (i = 0 ; i < numlines ; i++,l++)
2886 if (l->special == 223)
2887 {
2888 int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS;
2889 int friction = (0x1EB8*length)/0x80 + 0xD000;
2890 int movefactor, s;
2891
2892 // The following check might seem odd. At the time of movement,
2893 // the move distance is multiplied by 'friction/0x10000', so a
2894 // higher friction value actually means 'less friction'.
2895
2896 if (friction > ORIG_FRICTION) // ice
2897 movefactor = ((0x10092 - friction)*(0x70))/0x158;
2898 else
2899 movefactor = ((friction - 0xDB34)*(0xA))/0x80;
2900
2901 if (mbf_features)
2902 { // killough 8/28/98: prevent odd situations
2903 if (friction > FRACUNIT)
2904 friction = FRACUNIT;
2905 if (friction < 0)
2906 friction = 0;
2907 if (movefactor < 32)
2908 movefactor = 32;
2909 }
2910
2911 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
2912 {
2913 // killough 8/28/98:
2914 //
2915 // Instead of spawning thinkers, which are slow and expensive,
2916 // modify the sector's own friction values. Friction should be
2917 // a property of sectors, not objects which reside inside them.
2918 // Original code scanned every object in every friction sector
2919 // on every tic, adjusting its friction, putting unnecessary
2920 // drag on CPU. New code adjusts friction of sector only once
2921 // at level startup, and then uses this friction value.
2922
2923 sectors[s].friction = friction;
2924 sectors[s].movefactor = movefactor;
2925 }
2926 }
2927}
2928
2929//
2930// phares 3/12/98: End of friction effects
2931//
2932////////////////////////////////////////////////////////////////////////////
2933
2934////////////////////////////////////////////////////////////////////////////
2935//
2936// PUSH/PULL EFFECT
2937//
2938// phares 3/20/98: Start of push/pull effects
2939//
2940// This is where push/pull effects are applied to objects in the sectors.
2941//
2942// There are four kinds of push effects
2943//
2944// 1) Pushing Away
2945//
2946// Pushes you away from a point source defined by the location of an
2947// MT_PUSH Thing. The force decreases linearly with distance from the
2948// source. This force crosses sector boundaries and is felt w/in a circle
2949// whose center is at the MT_PUSH. The force is felt only if the point
2950// MT_PUSH can see the target object.
2951//
2952// 2) Pulling toward
2953//
2954// Same as Pushing Away except you're pulled toward an MT_PULL point
2955// source. This force crosses sector boundaries and is felt w/in a circle
2956// whose center is at the MT_PULL. The force is felt only if the point
2957// MT_PULL can see the target object.
2958//
2959// 3) Wind
2960//
2961// Pushes you in a constant direction. Full force above ground, half
2962// force on the ground, nothing if you're below it (water).
2963//
2964// 4) Current
2965//
2966// Pushes you in a constant direction. No force above ground, full
2967// force if on the ground or below it (water).
2968//
2969// The magnitude of the force is controlled by the length of a controlling
2970// linedef. The force vector for types 3 & 4 is determined by the angle
2971// of the linedef, and is constant.
2972//
2973// For each sector where these effects occur, the sector special type has
2974// to have the PUSH_MASK bit set. If this bit is turned off by a switch
2975// at run-time, the effect will not occur. The controlling sector for
2976// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing.
2977
2978
2979#define PUSH_FACTOR 7
2980
2981/////////////////////////////
2982//
2983// Add a push thinker to the thinker list
2984
2985static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee)
2986{
2987 pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0);
2988
2989 p->thinker.function = T_Pusher;
2990 p->source = source;
2991 p->type = type;
2992 p->x_mag = x_mag>>FRACBITS;
2993 p->y_mag = y_mag>>FRACBITS;
2994 p->magnitude = P_AproxDistance(p->x_mag,p->y_mag);
2995 if (source) // point source exist?
2996 {
2997 p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero
2998 p->x = p->source->x;
2999 p->y = p->source->y;
3000 }
3001 p->affectee = affectee;
3002 P_AddThinker(&p->thinker);
3003}
3004
3005/////////////////////////////
3006//
3007// PIT_PushThing determines the angle and magnitude of the effect.
3008// The object's x and y momentum values are changed.
3009//
3010// tmpusher belongs to the point source (MT_PUSH/MT_PULL).
3011//
3012// killough 10/98: allow to affect things besides players
3013
3014pusher_t* tmpusher; // pusher structure for blockmap searches
3015
3016boolean PIT_PushThing(mobj_t* thing)
3017{
3018 /* killough 10/98: made more general */
3019 if (!mbf_features ?
3020 thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) :
3021 (sentient(thing) || thing->flags & MF_SHOOTABLE) &&
3022 !(thing->flags & MF_NOCLIP))
3023 {
3024 angle_t pushangle;
3025 fixed_t speed;
3026 fixed_t sx = tmpusher->x;
3027 fixed_t sy = tmpusher->y;
3028
3029 speed = (tmpusher->magnitude -
3030 ((P_AproxDistance(thing->x - sx,thing->y - sy)
3031 >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1);
3032
3033 // killough 10/98: make magnitude decrease with square
3034 // of distance, making it more in line with real nature,
3035 // so long as it's still in range with original formula.
3036 //
3037 // Removes angular distortion, and makes effort required
3038 // to stay close to source, grow increasingly hard as you
3039 // get closer, as expected. Still, it doesn't consider z :(
3040
3041 if (speed > 0 && mbf_features)
3042 {
3043 int x = (thing->x-sx) >> FRACBITS;
3044 int y = (thing->y-sy) >> FRACBITS;
3045 speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1));
3046 }
3047
3048 // If speed <= 0, you're outside the effective radius. You also have
3049 // to be able to see the push/pull source point.
3050
3051 if (speed > 0 && P_CheckSight(thing,tmpusher->source))
3052 {
3053 pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy);
3054 if (tmpusher->source->type == MT_PUSH)
3055 pushangle += ANG180; // away
3056 pushangle >>= ANGLETOFINESHIFT;
3057 thing->momx += FixedMul(speed,finecosine[pushangle]);
3058 thing->momy += FixedMul(speed,finesine[pushangle]);
3059 }
3060 }
3061 return true;
3062}
3063
3064/////////////////////////////
3065//
3066// T_Pusher looks for all objects that are inside the radius of
3067// the effect.
3068//
3069
3070void T_Pusher(pusher_t *p)
3071{
3072 sector_t *sec;
3073 mobj_t *thing;
3074 msecnode_t* node;
3075 int xspeed,yspeed;
3076 int xl,xh,yl,yh,bx,by;
3077 int radius;
3078 int ht = 0;
3079
3080 if (!allow_pushers)
3081 return;
3082
3083 sec = sectors + p->affectee;
3084
3085 // Be sure the special sector type is still turned on. If so, proceed.
3086 // Else, bail out; the sector type has been changed on us.
3087
3088 if (!(sec->special & PUSH_MASK))
3089 return;
3090
3091 // For constant pushers (wind/current) there are 3 situations:
3092 //
3093 // 1) Affected Thing is above the floor.
3094 //
3095 // Apply the full force if wind, no force if current.
3096 //
3097 // 2) Affected Thing is on the ground.
3098 //
3099 // Apply half force if wind, full force if current.
3100 //
3101 // 3) Affected Thing is below the ground (underwater effect).
3102 //
3103 // Apply no force if wind, full force if current.
3104
3105 if (p->type == p_push)
3106 {
3107
3108 // Seek out all pushable things within the force radius of this
3109 // point pusher. Crosses sectors, so use blockmap.
3110
3111 tmpusher = p; // MT_PUSH/MT_PULL point source
3112 radius = p->radius; // where force goes to zero
3113 tmbbox[BOXTOP] = p->y + radius;
3114 tmbbox[BOXBOTTOM] = p->y - radius;
3115 tmbbox[BOXRIGHT] = p->x + radius;
3116 tmbbox[BOXLEFT] = p->x - radius;
3117
3118 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
3119 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
3120 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
3121 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
3122 for (bx=xl ; bx<=xh ; bx++)
3123 for (by=yl ; by<=yh ; by++)
3124 P_BlockThingsIterator(bx,by,PIT_PushThing);
3125 return;
3126 }
3127
3128 // constant pushers p_wind and p_current
3129
3130 if (sec->heightsec != -1) // special water sector?
3131 ht = sectors[sec->heightsec].floorheight;
3132 node = sec->touching_thinglist; // things touching this sector
3133 for ( ; node ; node = node->m_snext)
3134 {
3135 thing = node->m_thing;
3136 if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)))
3137 continue;
3138 if (p->type == p_wind)
3139 {
3140 if (sec->heightsec == -1) // NOT special water sector
3141 if (thing->z > thing->floorz) // above ground
3142 {
3143 xspeed = p->x_mag; // full force
3144 yspeed = p->y_mag;
3145 }
3146 else // on ground
3147 {
3148 xspeed = (p->x_mag)>>1; // half force
3149 yspeed = (p->y_mag)>>1;
3150 }
3151 else // special water sector
3152 {
3153 if (thing->z > ht) // above ground
3154 {
3155 xspeed = p->x_mag; // full force
3156 yspeed = p->y_mag;
3157 }
3158 else if (thing->player->viewz < ht) // underwater
3159 xspeed = yspeed = 0; // no force
3160 else // wading in water
3161 {
3162 xspeed = (p->x_mag)>>1; // half force
3163 yspeed = (p->y_mag)>>1;
3164 }
3165 }
3166 }
3167 else // p_current
3168 {
3169 if (sec->heightsec == -1) // NOT special water sector
3170 if (thing->z > sec->floorheight) // above ground
3171 xspeed = yspeed = 0; // no force
3172 else // on ground
3173 {
3174 xspeed = p->x_mag; // full force
3175 yspeed = p->y_mag;
3176 }
3177 else // special water sector
3178 if (thing->z > ht) // above ground
3179 xspeed = yspeed = 0; // no force
3180 else // underwater
3181 {
3182 xspeed = p->x_mag; // full force
3183 yspeed = p->y_mag;
3184 }
3185 }
3186 thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR);
3187 thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR);
3188 }
3189}
3190
3191/////////////////////////////
3192//
3193// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
3194// NULL otherwise.
3195
3196mobj_t* P_GetPushThing(int s)
3197{
3198 mobj_t* thing;
3199 sector_t* sec;
3200
3201 sec = sectors + s;
3202 thing = sec->thinglist;
3203 while (thing)
3204 {
3205 switch(thing->type)
3206 {
3207 case MT_PUSH:
3208 case MT_PULL:
3209 return thing;
3210 default:
3211 break;
3212 }
3213 thing = thing->snext;
3214 }
3215 return NULL;
3216}
3217
3218/////////////////////////////
3219//
3220// Initialize the sectors where pushers are present
3221//
3222
3223static void P_SpawnPushers(void)
3224{
3225 int i;
3226 line_t *l = lines;
3227 register int s;
3228 mobj_t* thing;
3229
3230 for (i = 0 ; i < numlines ; i++,l++)
3231 switch(l->special)
3232 {
3233 case 224: // wind
3234 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3235 Add_Pusher(p_wind,l->dx,l->dy,NULL,s);
3236 break;
3237 case 225: // current
3238 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3239 Add_Pusher(p_current,l->dx,l->dy,NULL,s);
3240 break;
3241 case 226: // push/pull
3242 for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; )
3243 {
3244 thing = P_GetPushThing(s);
3245 if (thing) // No MT_P* means no effect
3246 Add_Pusher(p_push,l->dx,l->dy,thing,s);
3247 }
3248 break;
3249 }
3250}
3251
3252//
3253// phares 3/20/98: End of Pusher effects
3254//
3255////////////////////////////////////////////////////////////////////////////