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