1 /** @file p.spec.cpp  Map special effects.
2  *
3  * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2005-2014 Daniel Swanson <danij@dengine.net>
5  * @authors Copyright © 2003-2005 Samuel Villarreal <svkaiser@gmail.com>
6  * @authors Copyright © 1993-1996 id Software, Inc.
7  *
8  * @par License
9  * GPL: http://www.gnu.org/licenses/gpl.html
10  *
11  * <small>This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by the
13  * Free Software Foundation; either version 2 of the License, or (at your
14  * option) any later version. This program is distributed in the hope that it
15  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details. You should have received a copy of the GNU
18  * General Public License along with this program; if not, write to the Free
19  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA</small>
21  */
22 
23 #include "jdoom64.h"
24 #include "p_spec.h"
25 
26 #include <cstdio>
27 #include <cstring>
28 #include "gamesession.h"
29 #include "d_net.h"
30 #include "d_netsv.h"
31 #include "dmu_lib.h"
32 #include "m_argv.h"
33 #include "p_ceiling.h"
34 #include "p_door.h"
35 #include "p_floor.h"
36 #include "p_mapsetup.h"
37 #include "p_mapspec.h"
38 #include "p_plat.h"
39 #include "p_scroll.h"
40 #include "p_switch.h"
41 #include "p_tick.h"
42 #include "player.h"
43 
44 static void P_CrossSpecialLine(Line *line, int side, mobj_t *thing);
45 static void P_ShootSpecialLine(mobj_t *thing, Line *line);
46 
P_ActivateLine(Line * ld,mobj_t * mo,int side,int actType)47 dd_bool P_ActivateLine(Line *ld, mobj_t *mo, int side, int actType)
48 {
49     // Clients do not activate lines.
50     if(IS_CLIENT) return false;
51 
52     switch(actType)
53     {
54     case SPAC_CROSS:
55         P_CrossSpecialLine(ld, side, mo);
56         return true;
57 
58     case SPAC_USE:
59         return P_UseSpecialLine(mo, ld, side);
60 
61     case SPAC_IMPACT:
62         P_ShootSpecialLine(mo, ld);
63         return true;
64 
65     default:
66         DENG2_ASSERT(!"P_ActivateLine: Unknown activation type");
67         break;
68     }
69 
70     return false;
71 }
72 
73 /**
74  * Called every time a thing origin is about to cross a line with a non 0 special.
75  */
P_CrossSpecialLine(Line * line,int side,mobj_t * thing)76 static void P_CrossSpecialLine(Line *line, int side, mobj_t *thing)
77 {
78     // Extended functionality overrides old.
79     if(XL_CrossLine(line, side, thing)) return;
80 
81     xline_t *xline = P_ToXLine(line);
82 
83     // Triggers that other things can activate
84     if(!thing->player)
85     {
86         dd_bool ok = false;
87 
88         // Things that should NOT trigger specials...
89         switch(thing->type)
90         {
91         case MT_ROCKET:
92         case MT_PLASMA:
93         case MT_BFG:
94         case MT_TROOPSHOT:
95         case MT_HEADSHOT:
96         case MT_BRUISERSHOT:
97         case MT_BRUISERSHOTRED: // jd64
98         case MT_NTROSHOT: // jd64
99             return;
100 
101         default: break;
102         }
103 
104         switch(xline->special)
105         {
106         case 39:  ///< TELEPORT TRIGGER
107         case 97:  ///< TELEPORT RETRIGGER
108         case 993: // jd64
109         case 125: ///< TELEPORT MONSTERONLY TRIGGER
110         case 126: ///< TELEPORT MONSTERONLY RETRIGGER
111         case 4:   ///< RAISE DOOR
112         case 10:  ///< PLAT DOWN-WAIT-UP-STAY TRIGGER
113         case 88:  ///< PLAT DOWN-WAIT-UP-STAY RETRIGGER
114         case 415: // jd64
115             ok = true;
116             break;
117         }
118 
119         // Anything can trigger this line!
120         if(xline->flags & ML_ALLTRIGGER)
121             ok = true;
122 
123         if(!ok) return;
124     }
125 
126     // Note: could use some const's here.
127     switch(xline->special)
128     {
129     // TRIGGERS.
130     // All from here to RETRIGGERS.
131     case 2:
132         // Open Door
133         EV_DoDoor(line, DT_OPEN);
134         xline->special = 0;
135         break;
136 
137     case 3:
138         // Close Door
139         EV_DoDoor(line, DT_CLOSE);
140         xline->special = 0;
141         break;
142 
143     case 4:
144         // Raise Door
145         EV_DoDoor(line, DT_NORMAL);
146         xline->special = 0;
147         break;
148 
149     case 5:
150         // Raise Floor
151         EV_DoFloor(line, FT_RAISEFLOOR);
152         xline->special = 0;
153         break;
154 
155     case 6:
156         // Fast Ceiling Crush & Raise
157         EV_DoCeiling(line, CT_CRUSHANDRAISEFAST);
158         xline->special = 0;
159         break;
160 
161     case 8:
162         // Build Stairs
163         EV_BuildStairs(line, build8);
164         xline->special = 0;
165         break;
166 
167     case 10:
168         // PlatDownWaitUp
169         EV_DoPlat(line, PT_DOWNWAITUPSTAY, 0);
170         xline->special = 0;
171         break;
172 
173     case 12:
174         // Light Turn On - brightest near
175         EV_LightTurnOn(line, 0);
176         xline->special = 0;
177         break;
178 
179     case 13:
180         // Light Turn On - max
181         EV_LightTurnOn(line, 1);
182         xline->special = 0;
183         break;
184 
185     case 16:
186         // Close Door 30
187         EV_DoDoor(line, DT_CLOSE30THENOPEN);
188         xline->special = 0;
189         break;
190 
191     case 17:
192         // Start Light Strobing
193         EV_StartLightStrobing(line);
194         xline->special = 0;
195         break;
196 
197     case 19:
198         // Lower Floor
199         EV_DoFloor(line, FT_LOWER);
200         xline->special = 0;
201         break;
202 
203     case 22:
204         // Raise floor to nearest height and change texture
205         EV_DoPlat(line, PT_RAISETONEARESTANDCHANGE, 0);
206         xline->special = 0;
207         break;
208 
209     case 25:
210         // Ceiling Crush and Raise
211         EV_DoCeiling(line, CT_CRUSHANDRAISE);
212         xline->special = 0;
213         break;
214 
215     case 30:
216         // Raise floor to shortest texture height
217         //  on either side of lines.
218         EV_DoFloor(line, FT_RAISETOTEXTURE);
219         xline->special = 0;
220         break;
221 
222     case 35:
223         // Lights Very Dark
224         EV_LightTurnOn(line, 35.0f/255.0f);
225         xline->special = 0;
226         break;
227 
228     case 36:
229         // Lower Floor (TURBO)
230         EV_DoFloor(line, FT_LOWERTURBO);
231         xline->special = 0;
232         break;
233 
234     case 37:
235         // LowerAndChange
236         EV_DoFloor(line, FT_LOWERANDCHANGE);
237         xline->special = 0;
238         break;
239 
240     case 38:
241         // Lower Floor To Lowest
242         EV_DoFloor(line, FT_LOWERTOLOWEST);
243         xline->special = 0;
244         break;
245 
246     case 420: // jd64
247         EV_DoFloorAndCeiling(line, FT_TOHIGHESTPLUS8, CT_RAISETOHIGHEST);
248         xline->special = 0;
249         break;
250 
251     case 430: // jd64
252         EV_DoFloor(line, FT_TOHIGHESTPLUSBITMIP);
253         break;
254 
255     case 431: // jd64
256         EV_DoFloor(line, FT_TOHIGHESTPLUSBITMIP);
257         xline->special = 0;
258         break;
259 
260     case 426: // jd64
261         EV_DoCeiling(line, CT_CUSTOM);
262         break;
263 
264     case 427: // jd64
265         EV_DoCeiling(line, CT_CUSTOM);
266         xline->special = 0;
267         break;
268 
269     case 991: // jd64
270         // TELEPORT!
271         EV_FadeSpawn(line, thing);
272         xline->special = 0;
273         break;
274 
275     case 993: // jd64
276         if(!thing->player)
277             EV_FadeSpawn(line, thing);
278         xline->special = 0;
279         break;
280 
281     case 992: // jd64
282         // Lower Ceiling to Floor
283         if(EV_DoCeiling(line, CT_LOWERTOFLOOR))
284         {
285             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
286             xline->special = 0;
287         }
288         break;
289 
290     case 994: // jd64
291         /// @todo Might as well do this with XG.
292         /// Also, export this text string to DED.
293         P_SetMessage(thing->player, "You've found a secret area!");
294         thing->player->secretCount++;
295         thing->player->update |= PSF_COUNTERS;
296         xline->special = 0;
297         break;
298 
299     case 995: // jd64
300         /// @todo Might as well do this with XG.
301         P_SetMessage(thing->player, "You've found a shrine!");
302         xline->special = 0;
303         break;
304 
305     case 998: // jd64
306         // BE GONE!
307         EV_FadeAway(line, thing);
308         xline->special = 0;
309         break;
310 
311     case 39:
312         // TELEPORT!
313         EV_Teleport(line, side, thing, true);
314         xline->special = 0;
315         break;
316 
317     case 40:
318         // RaiseCeilingLowerFloor
319         EV_DoCeiling(line, CT_RAISETOHIGHEST);
320         EV_DoFloor(line, FT_LOWERTOLOWEST);
321         xline->special = 0;
322         break;
323 
324     case 44:
325         // Ceiling Crush
326         EV_DoCeiling(line, CT_LOWERANDCRUSH);
327         xline->special = 0;
328         break;
329 
330     case 52:
331         // EXIT!
332         G_SetGameActionMapCompleted(gfw_Session()->mapUriForNamedExit("next"));
333         break;
334 
335     case 53:
336         // Perpetual Platform Raise
337         EV_DoPlat(line, PT_PERPETUALRAISE, 0);
338         xline->special = 0;
339         break;
340 
341     case 54:
342         // Platform Stop
343         P_PlatDeactivate(xline->tag);
344         xline->special = 0;
345         break;
346 
347     case 56:
348         // Raise Floor Crush
349         EV_DoFloor(line, FT_RAISEFLOORCRUSH);
350         xline->special = 0;
351         break;
352 
353     case 57:
354         // Ceiling Crush Stop
355         P_CeilingDeactivate(xline->tag);
356         xline->special = 0;
357         break;
358 
359     case 58:
360         // Raise Floor 24
361         EV_DoFloor(line, FT_RAISE24);
362         xline->special = 0;
363         break;
364 
365     case 59:
366         // Raise Floor 24 And Change
367         EV_DoFloor(line, FT_RAISE24ANDCHANGE);
368         xline->special = 0;
369         break;
370 
371     case 104:
372         // Turn lights off in sector(tag)
373         EV_TurnTagLightsOff(line);
374         xline->special = 0;
375         break;
376 
377     case 108:
378         // Blazing Door Raise (faster than TURBO!)
379         EV_DoDoor(line, DT_BLAZERAISE);
380         xline->special = 0;
381         break;
382 
383     case 109:
384         // Blazing Door Open (faster than TURBO!)
385         EV_DoDoor(line, DT_BLAZEOPEN);
386         xline->special = 0;
387         break;
388 
389     case 100:
390         // Build Stairs Turbo 16
391         EV_BuildStairs(line, turbo16);
392         xline->special = 0;
393         break;
394 
395     case 110:
396         // Blazing Door Close (faster than TURBO!)
397         EV_DoDoor(line, DT_BLAZECLOSE);
398         xline->special = 0;
399         break;
400 
401     case 119:
402         // Raise floor to nearest surr. floor
403         EV_DoFloor(line, FT_RAISEFLOORTONEAREST);
404         xline->special = 0;
405         break;
406 
407     case 121:
408         // Blazing PlatDownWaitUpStay
409         EV_DoPlat(line, PT_DOWNWAITUPSTAYBLAZE, 0);
410         xline->special = 0;
411         break;
412 
413     case 124:
414         // Secret EXIT
415         G_SetGameActionMapCompleted(gfw_Session()->mapUriForNamedExit("secret"), 0, true);
416         break;
417 
418     case 125:
419         // TELEPORT MonsterONLY
420         if(!thing->player)
421         {
422             EV_Teleport(line, side, thing, true);
423             xline->special = 0;
424         }
425         break;
426 
427     case 130:
428         // Raise Floor Turbo
429         EV_DoFloor(line, FT_RAISEFLOORTURBO);
430         xline->special = 0;
431         break;
432 
433     case 141:
434         // Silent Ceiling Crush & Raise
435         EV_DoCeiling(line, CT_SILENTCRUSHANDRAISE);
436         xline->special = 0;
437         break;
438 
439         // RETRIGGERS.  All from here till end.
440     case 72:
441         // Ceiling Crush
442         EV_DoCeiling(line, CT_LOWERANDCRUSH);
443         break;
444 
445     case 73:
446         // Ceiling Crush and Raise
447         EV_DoCeiling(line, CT_CRUSHANDRAISE);
448         break;
449 
450     case 74:
451         // Ceiling Crush Stop
452         P_CeilingDeactivate(xline->tag);
453         break;
454 
455     case 75:
456         // Close Door
457         EV_DoDoor(line, DT_CLOSE);
458         break;
459 
460     case 76:
461         // Close Door 30
462         EV_DoDoor(line, DT_CLOSE30THENOPEN);
463         break;
464 
465     case 77:
466         // Fast Ceiling Crush & Raise
467         EV_DoCeiling(line, CT_CRUSHANDRAISEFAST);
468         break;
469 
470     case 79:
471         // Lights Very Dark
472         EV_LightTurnOn(line, 35.0f/255.0f);
473         break;
474 
475     case 80:
476         // Light Turn On - brightest near
477         EV_LightTurnOn(line, 0);
478         break;
479 
480     case 81:
481         // Light Turn On - max
482         EV_LightTurnOn(line, 1);
483         break;
484 
485     case 82:
486         // Lower Floor To Lowest
487         EV_DoFloor(line, FT_LOWERTOLOWEST);
488         break;
489 
490     case 83:
491         // Lower Floor
492         EV_DoFloor(line, FT_LOWER);
493         break;
494 
495     case 84:
496         // LowerAndChange
497         EV_DoFloor(line, FT_LOWERANDCHANGE);
498         break;
499 
500     case 86:
501         // Open Door
502         EV_DoDoor(line, DT_OPEN);
503         break;
504 
505     case 87:
506         // Perpetual Platform Raise
507         EV_DoPlat(line, PT_PERPETUALRAISE, 0);
508         break;
509 
510     case 88:
511         // PlatDownWaitUp
512         EV_DoPlat(line, PT_DOWNWAITUPSTAY, 0);
513         break;
514 
515     case 415: // jd64
516         if(thing->player)
517             EV_DoPlat(line, PT_UPWAITDOWNSTAY, 0);
518         break;
519 
520     case 89:
521         // Platform Stop
522         P_PlatDeactivate(xline->tag);
523         break;
524 
525     case 90:
526         // Raise Door
527         EV_DoDoor(line, DT_NORMAL);
528         break;
529 
530     case 91:
531         // Raise Floor
532         EV_DoFloor(line, FT_RAISEFLOOR);
533         break;
534 
535     case 92:
536         // Raise Floor 24
537         EV_DoFloor(line, FT_RAISE24);
538         break;
539 
540     case 93:
541         // Raise Floor 24 And Change
542         EV_DoFloor(line, FT_RAISE24ANDCHANGE);
543         break;
544 
545     case 94:
546         // Raise Floor Crush
547         EV_DoFloor(line, FT_RAISEFLOORCRUSH);
548         break;
549 
550     case 95:
551         // Raise floor to nearest height
552         // and change texture.
553         EV_DoPlat(line, PT_RAISETONEARESTANDCHANGE, 0);
554         break;
555 
556     case 96:
557         // Raise floor to shortest texture height
558         // on either side of lines.
559         EV_DoFloor(line, FT_RAISETOTEXTURE);
560         break;
561 
562     case 97:
563         // TELEPORT!
564         EV_Teleport(line, side, thing, true);
565         break;
566 
567     case 423: // jd64
568         // TELEPORT! (no fog)
569         // FIXME: DJS - might as well do this in XG.
570         EV_Teleport(line, side, thing, false);
571         break;
572 
573     case 98:
574         // Lower Floor (TURBO)
575         EV_DoFloor(line, FT_LOWERTURBO);
576         break;
577 
578     case 105:
579         // Blazing Door Raise (faster than TURBO!)
580         EV_DoDoor(line, DT_BLAZERAISE);
581         break;
582 
583     case 106:
584         // Blazing Door Open (faster than TURBO!)
585         EV_DoDoor(line, DT_BLAZEOPEN);
586         break;
587 
588     case 107:
589         // Blazing Door Close (faster than TURBO!)
590         EV_DoDoor(line, DT_BLAZECLOSE);
591         break;
592 
593     case 120:
594         // Blazing PlatDownWaitUpStay.
595         EV_DoPlat(line, PT_DOWNWAITUPSTAYBLAZE, 0);
596         break;
597 
598     case 126:
599         // TELEPORT MonsterONLY.
600         if(!thing->player)
601             EV_Teleport(line, side, thing, true);
602         break;
603 
604     case 128:
605         // Raise To Nearest Floor
606         EV_DoFloor(line, FT_RAISEFLOORTONEAREST);
607         break;
608 
609     case 129:
610         // Raise Floor Turbo
611         EV_DoFloor(line, FT_RAISEFLOORTURBO);
612         break;
613 
614     case 155: // jd64
615         // Raise Floor 512
616         // FIXME: DJS - again, might as well do this in XG.
617         if(EV_DoFloor(line, FT_RAISE32))
618         {
619             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
620             P_ToXLine(line)->special = 0;
621         }
622         break;
623     }
624 }
625 
626 /**
627  * Called when a thing shoots a special line.
628  */
P_ShootSpecialLine(mobj_t * thing,Line * line)629 static void P_ShootSpecialLine(mobj_t *thing, Line *line)
630 {
631     xline_t *xline = P_ToXLine(line);
632 
633     //  Impacts that other things can activate.
634     if(!thing->player)
635     {
636         switch(xline->special)
637         {
638         default: return;
639 
640         case 46: ///< OPEN DOOR IMPACT
641             break;
642         }
643     }
644 
645     switch(xline->special)
646     {
647     case 24: ///< RAISE FLOOR
648         EV_DoFloor(line, FT_RAISEFLOOR);
649         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
650         xline->special = 0;
651         break;
652 
653     case 46: ///< OPEN DOOR
654         EV_DoDoor(line, DT_OPEN);
655         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
656         break;
657 
658     case 47: ///< RAISE FLOOR NEAR AND CHANGE
659         EV_DoPlat(line, PT_RAISETONEARESTANDCHANGE, 0);
660         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
661         xline->special = 0;
662         break;
663 
664     case 191: ///< LOWER FLOOR WAIT RAISE (jd64)
665         EV_DoPlat(line, PT_DOWNWAITUPSTAYBLAZE, 0);
666         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
667         break;
668     }
669 }
670 
671 /**
672  * Called every tic frame that the player origin is in a special sector
673  */
P_PlayerInSpecialSector(player_t * player)674 void P_PlayerInSpecialSector(player_t *player)
675 {
676     Sector *sector = Mobj_Sector(player->plr->mo);
677 
678     if(IS_CLIENT) return;
679 
680     // Falling, not all the way down yet?
681     if(!FEQUAL(player->plr->mo->origin[VZ], P_GetDoublep(sector, DMU_FLOOR_HEIGHT))) return;
682 
683     // Has hitten ground.
684     switch(P_ToXSector(sector)->special)
685     {
686     default: break;
687 
688     case 5: ///< HELLSLIME DAMAGE
689         if(!player->powers[PT_IRONFEET])
690             if(!(mapTime & 0x1f))
691                 P_DamageMobj(player->plr->mo, NULL, NULL, 10, false);
692         break;
693 
694     case 7: ///< NUKAGE DAMAGE
695         if(!player->powers[PT_IRONFEET])
696             if(!(mapTime & 0x1f))
697                 P_DamageMobj(player->plr->mo, NULL, NULL, 5, false);
698         break;
699 
700     case 16: ///< SUPER HELLSLIME DAMAGE
701     case 4:  ///< STROBE HURT
702         if(!player->powers[PT_IRONFEET] || (P_Random() < 5))
703         {
704             if(!(mapTime & 0x1f))
705                 P_DamageMobj(player->plr->mo, NULL, NULL, 20, false);
706         }
707         break;
708 
709     case 9: ///< SECRET SECTOR
710         player->secretCount++;
711         P_ToXSector(sector)->special = 0;
712         if(cfg.secretMsg)
713         {
714             P_SetMessage(player, "You've found a secret area!");
715             // S_ConsoleSound(SFX_SECRET, 0, player - players); // jd64
716         }
717         break;
718     }
719 }
720 
721 /**
722  * d64tc
723  */
P_ThunderSector()724 void P_ThunderSector()
725 {
726     if(!(P_Random() < 10)) return;
727 
728     iterlist_t *list = P_GetSectorIterListForTag(20000, false);
729     if(!list) return;
730 
731     IterList_SetIteratorDirection(list, ITERLIST_FORWARD);
732     IterList_RewindIterator(list);
733 
734     Sector *sec;
735     while((sec = (Sector *)IterList_MoveIterator(list)))
736     {
737         if(!(mapTime & 32))
738         {
739             P_SetFloatp(sec, DMU_LIGHT_LEVEL, 1);
740         }
741     }
742 
743     S_StartSound(SFX_SSSIT | DDSF_NO_ATTENUATION, NULL);
744 }
745 
P_SpawnSectorSpecialThinkers()746 void P_SpawnSectorSpecialThinkers()
747 {
748     // Clients spawn specials only on the server's instruction.
749     if(IS_CLIENT) return;
750 
751     for(int i = 0; i < numsectors; ++i)
752     {
753         Sector *sec     = (Sector *)P_ToPtr(DMU_SECTOR, i);
754         xsector_t *xsec = P_ToXSector(sec);
755 
756         // XG sector types override the game's built-in types.
757         if(xsec->xg) continue;
758 
759         // jd64 >
760         // DJS - yet more hacks! Why use the tag?
761         switch(xsec->tag)
762         {
763         default: break;
764 
765         case 10000:
766         case 10001:
767         case 10002:
768         case 10003:
769         case 10004:
770             P_SpawnGlowingLight(sec);
771             break;
772 
773         case 11000:
774             P_SpawnLightFlash(sec);
775             break;
776 
777         case 12000:
778             P_SpawnFireFlicker(sec);
779             break;
780 
781         case 13000:
782             P_SpawnLightBlink(sec);
783             break;
784 
785         case 20000:
786             P_SpawnGlowingLight(sec);
787             break;
788         }
789         // < d64tc
790 
791         switch(xsec->special)
792         {
793         default: break;
794 
795         case 1: ///< FLICKERING LIGHTS
796             P_SpawnLightFlash(sec);
797             break;
798 
799         case 2: ///< STROBE FAST
800             P_SpawnStrobeFlash(sec, FASTDARK, 0);
801             break;
802 
803         case 3: ///< STROBE SLOW
804             P_SpawnStrobeFlash(sec, SLOWDARK, 0);
805             break;
806 
807         case 4: ///< STROBE FAST/DEATH SLIME
808             P_SpawnStrobeFlash(sec, FASTDARK, 0);
809             xsec->special = 4;
810             break;
811 
812         case 8: ///< GLOWING LIGHT
813             P_SpawnGlowingLight(sec);
814             break;
815 
816         case 10: ///< DOOR CLOSE IN 30 SECONDS
817             P_SpawnDoorCloseIn30(sec);
818             break;
819 
820         case 12: ///< SYNC STROBE SLOW
821             P_SpawnStrobeFlash(sec, SLOWDARK, 1);
822             break;
823 
824         case 13: ///< SYNC STROBE FAST
825             P_SpawnStrobeFlash(sec, FASTDARK, 1);
826             break;
827 
828         case 14: ///< DOOR RAISE IN 5 MINUTES
829             P_SpawnDoorRaiseIn5Mins(sec);
830             break;
831 
832         case 17:
833             P_SpawnFireFlicker(sec);
834             break;
835         }
836     }
837 }
838 
P_SpawnLineSpecialThinkers()839 void P_SpawnLineSpecialThinkers()
840 {
841     // Stub.
842 }
843 
P_SpawnAllSpecialThinkers()844 void P_SpawnAllSpecialThinkers()
845 {
846     P_SpawnSectorSpecialThinkers();
847     P_SpawnLineSpecialThinkers();
848 }
849 
P_UseSpecialLine2(mobj_t * mo,Line * line,int side)850 dd_bool P_UseSpecialLine2(mobj_t *mo, Line *line, int side)
851 {
852     xline_t *xline = P_ToXLine(line);
853 
854     // Err...
855     // Use the back sides of VERY SPECIAL lines...
856     if(side)
857     {
858         switch(xline->special)
859         {
860         case 124: // Sliding door open&close (unused).
861             break;
862 
863         default: return false;
864         }
865     }
866 
867     // Switches that other things can activate.
868     if(!mo->player)
869     {
870         // Never open secret doors.
871         if(xline->flags & ML_SECRET)
872             return false;
873 
874         switch(xline->special)
875         {
876         case 1:                 // MANUAL DOOR RAISE
877         case 32:                // MANUAL BLUE
878         case 33:                // MANUAL RED
879         case 34:                // MANUAL YELLOW
880             break;
881 
882         default:
883             return false;
884             break;
885         }
886     }
887 
888     // Do something.
889     switch(xline->special)
890     {
891         // MANUALS
892     case 1:                     // Vertical Door
893     case 26:                    // Blue Door/Locked
894     case 27:                    // Yellow Door /Locked
895     case 28:                    // Red Door /Locked
896 
897     case 31:                    // Manual door open
898     case 32:                    // Blue locked door open
899     case 33:                    // Red locked door open
900     case 34:                    // Yellow locked door open
901 
902     case 117:                   // Blazing door raise
903     case 118:                   // Blazing door open
904     case 525: // jd64
905     case 526: // jd64
906     case 527: // jd64
907         EV_VerticalDoor(line, mo);
908         break;
909 
910         //UNUSED - Door Slide Open&Close
911         // case 124:
912         // EV_SlidingDoor (line, mo);
913         // break;
914 
915         // SWITCHES
916     case 7:
917         // Build Stairs,
918         if(EV_BuildStairs(line, build8))
919         {
920             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
921             xline->special = 0;
922         }
923         break;
924 
925     case 9:
926         // Change Donut,
927         if(EV_DoDonut(line))
928         {
929             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
930             xline->special = 0;
931         }
932         break;
933 
934     case 11:
935         // Exit level,
936         if(cyclingMaps && mapCycleNoExit)
937             break;
938 
939         // Prevent zombies from exiting levels,
940         if(mo->player && mo->player->health <= 0 && !cfg.zombiesCanExit)
941         {
942             S_StartSound(SFX_NOWAY, mo);
943             return false;
944         }
945 
946         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_SWTCHX, false, 0);
947         xline->special = 0;
948         G_SetGameActionMapCompleted(gfw_Session()->mapUriForNamedExit("next"));
949         break;
950 
951     case 14:
952         // Raise Floor 32 and change texture.
953         if(EV_DoPlat(line, PT_RAISEANDCHANGE, 32))
954         {
955             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
956             xline->special = 0;
957         }
958         break;
959 
960     case 15:
961         // Raise Floor 24 and change texture.
962         if(EV_DoPlat(line, PT_RAISEANDCHANGE, 24))
963         {
964             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
965             xline->special = 0;
966         }
967         break;
968 
969     case 18:
970         // Raise Floor to next highest floor.
971         if(EV_DoFloor(line, FT_RAISEFLOORTONEAREST))
972         {
973             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
974             xline->special = 0;
975         }
976         break;
977 
978     case 20:
979         // Raise Plat next highest floor and change texture.
980         if(EV_DoPlat(line, PT_RAISETONEARESTANDCHANGE, 0))
981         {
982             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
983             xline->special = 0;
984         }
985         break;
986 
987     case 21:
988         // PlatDownWaitUpStay.
989         if(EV_DoPlat(line, PT_DOWNWAITUPSTAY, 0))
990         {
991             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
992             xline->special = 0;
993         }
994         break;
995 
996     case 23:
997         // Lower Floor to Lowest.
998         if(EV_DoFloor(line, FT_LOWERTOLOWEST))
999         {
1000             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1001             xline->special = 0;
1002         }
1003         break;
1004 
1005     case 29:
1006         // Raise Door.
1007         if(EV_DoDoor(line, DT_NORMAL))
1008         {
1009             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1010             xline->special = 0;
1011         }
1012         break;
1013 
1014     case 41:
1015         // Lower Ceiling to Floor.
1016         if(EV_DoCeiling(line, CT_LOWERTOFLOOR))
1017         {
1018             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1019             xline->special = 0;
1020         }
1021         break;
1022 
1023     case 71:
1024         // Turbo Lower Floor.
1025         if(EV_DoFloor(line, FT_LOWERTURBO))
1026         {
1027             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1028             xline->special = 0;
1029         }
1030         break;
1031 
1032     case 49:
1033         // Ceiling Crush And Raise.
1034         if(EV_DoCeiling(line, CT_CRUSHANDRAISE))
1035         {
1036             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1037             xline->special = 0;
1038         }
1039         break;
1040 
1041     case 50:
1042         // Close Door.
1043         if(EV_DoDoor(line, DT_CLOSE))
1044         {
1045             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1046             xline->special = 0;
1047         }
1048         break;
1049 
1050     case 51:
1051         // Secret EXIT.
1052         if(cyclingMaps && mapCycleNoExit)
1053             break;
1054 
1055         // Prevent zombies from exiting levels.
1056         if(mo->player && mo->player->health <= 0 && !cfg.zombiesCanExit)
1057         {
1058             S_StartSound(SFX_NOWAY, mo);
1059             return false;
1060         }
1061 
1062         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1063         xline->special = 0;
1064         G_SetGameActionMapCompleted(gfw_Session()->mapUriForNamedExit("secret"), 0, true);
1065         break;
1066 
1067     case 55:
1068         // Raise Floor Crush.
1069         if(EV_DoFloor(line, FT_RAISEFLOORCRUSH))
1070         {
1071             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1072             xline->special = 0;
1073         }
1074         break;
1075 
1076     case 101:
1077         // Raise Floor.
1078         if(EV_DoFloor(line, FT_RAISEFLOOR))
1079         {
1080             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1081             xline->special = 0;
1082         }
1083         break;
1084 
1085     case 102:
1086         // Lower Floor to Surrounding floor height.
1087         if(EV_DoFloor(line, FT_LOWER))
1088         {
1089             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1090             xline->special = 0;
1091         }
1092         break;
1093 
1094     case 103:
1095         // Open Door.
1096         if(EV_DoDoor(line, DT_OPEN))
1097         {
1098             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1099             xline->special = 0;
1100         }
1101         break;
1102 
1103     case 111:
1104         // Blazing Door Raise (faster than TURBO!).
1105         if(EV_DoDoor(line, DT_BLAZERAISE))
1106         {
1107             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1108             xline->special = 0;
1109         }
1110         break;
1111 
1112     case 112:
1113         // Blazing Door Open (faster than TURBO!).
1114         if(EV_DoDoor(line, DT_BLAZEOPEN))
1115         {
1116             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1117             xline->special = 0;
1118         }
1119         break;
1120 
1121     case 113:
1122         // Blazing Door Close (faster than TURBO!).
1123         if(EV_DoDoor(line, DT_BLAZECLOSE))
1124         {
1125             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1126             xline->special = 0;
1127         }
1128         break;
1129 
1130     case 122:
1131         // Blazing PlatDownWaitUpStay.
1132         if(EV_DoPlat(line, PT_DOWNWAITUPSTAYBLAZE, 0))
1133         {
1134             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1135             xline->special = 0;
1136         }
1137         break;
1138 
1139     case 127:
1140         // Build Stairs Turbo 16.
1141         if(EV_BuildStairs(line, turbo16))
1142         {
1143             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1144             xline->special = 0;
1145         }
1146         break;
1147 
1148     case 131:
1149         // Raise Floor Turbo.
1150         if(EV_DoFloor(line, FT_RAISEFLOORTURBO))
1151         {
1152             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1153             xline->special = 0;
1154         }
1155         break;
1156 
1157     case 133:
1158         // BlzOpenDoor BLUE.
1159     case 135:
1160         // BlzOpenDoor RED.
1161     case 137:
1162         // BlzOpenDoor YELLOW.
1163         if(EV_DoLockedDoor(line, DT_BLAZEOPEN, mo))
1164         {
1165             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1166             xline->special = 0;
1167         }
1168         break;
1169 
1170     case 140:
1171         // Raise Floor 512.
1172         if(EV_DoFloor(line, FT_RAISE512))
1173         {
1174             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1175             xline->special = 0;
1176         }
1177         break;
1178 
1179     // BUTTONS
1180     case 42:
1181         // Close Door.
1182         if(EV_DoDoor(line, DT_CLOSE))
1183             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1184         break;
1185 
1186     case 43:
1187         // Lower Ceiling to Floor.
1188         if(EV_DoCeiling(line, CT_LOWERTOFLOOR))
1189             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1190         break;
1191 
1192     case 45:
1193         // Lower Floor to Surrounding floor height.
1194         if(EV_DoFloor(line, FT_LOWER))
1195             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1196         break;
1197 
1198     case 60:
1199         // Lower Floor to Lowest.
1200         if(EV_DoFloor(line, FT_LOWERTOLOWEST))
1201             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1202         break;
1203 
1204     case 61:
1205         // Open Door.
1206         if(EV_DoDoor(line, DT_OPEN))
1207             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1208         break;
1209 
1210     case 62:
1211         // PlatDownWaitUpStay.
1212         if(EV_DoPlat(line, PT_DOWNWAITUPSTAY, 1))
1213             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1214         break;
1215 
1216     case 63:
1217         // Raise Door.
1218         if(EV_DoDoor(line, DT_NORMAL))
1219             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1220         break;
1221 
1222     case 64:
1223         // Raise Floor to ceiling.
1224         if(EV_DoFloor(line, FT_RAISEFLOOR))
1225             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1226         break;
1227 
1228     case 66:
1229         // Raise Floor 24 and change texture.
1230         if(EV_DoPlat(line, PT_RAISEANDCHANGE, 24))
1231             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1232         break;
1233 
1234     case 67:
1235         // Raise Floor 32 and change texture.
1236         if(EV_DoPlat(line, PT_RAISEANDCHANGE, 32))
1237             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1238         break;
1239 
1240     case 65:
1241         // Raise Floor Crush.
1242         if(EV_DoFloor(line, FT_RAISEFLOORCRUSH))
1243             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1244         break;
1245 
1246     case 68:
1247         // Raise Plat to next highest floor and change texture.
1248         if(EV_DoPlat(line, PT_RAISETONEARESTANDCHANGE, 0))
1249             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1250         break;
1251 
1252     case 69:
1253         // Raise Floor to next highest floor.
1254         if(EV_DoFloor(line, FT_RAISEFLOORTONEAREST))
1255             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1256         break;
1257 
1258     case 70:
1259         // Turbo Lower Floor.
1260         if(EV_DoFloor(line, FT_LOWERTURBO))
1261             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1262         break;
1263 
1264     case 114:
1265         // Blazing Door Raise (faster than TURBO!).
1266         if(EV_DoDoor(line, DT_BLAZERAISE))
1267             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1268         break;
1269 
1270     case 115:
1271         // Blazing Door Open (faster than TURBO!).
1272         if(EV_DoDoor(line, DT_BLAZEOPEN))
1273             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1274         break;
1275 
1276     case 116:
1277         // Blazing Door Close (faster than TURBO!).
1278         if(EV_DoDoor(line, DT_BLAZECLOSE))
1279             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1280         break;
1281 
1282     case 123:
1283         // Blazing PlatDownWaitUpStay.
1284         if(EV_DoPlat(line, PT_DOWNWAITUPSTAYBLAZE, 0))
1285             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1286         break;
1287 
1288     case 132:
1289         // Raise Floor Turbo.
1290         if(EV_DoFloor(line, FT_RAISEFLOORTURBO))
1291             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1292         break;
1293 
1294     case 99:
1295         // BlzOpenDoor BLUE.
1296     case 134:
1297         // BlzOpenDoor RED.
1298     case 136:
1299         // BlzOpenDoor YELLOW.
1300         if(EV_DoLockedDoor(line, DT_BLAZERAISE, mo)) // jd64 was "DT_BLAZEOPEN"
1301             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1302         break;
1303 
1304     case 138:
1305         // Light Turn On.
1306         EV_LightTurnOn(line, 1);
1307         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1308         break;
1309 
1310     case 139:
1311         // Light Turn Off.
1312         EV_LightTurnOn(line, 35.0f/255.0f);
1313         P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1314         break;
1315 
1316     case 343: // jd64 - BlzOpenDoor LaserPowerup 1.
1317     case 344: // jd64 - BlzOpenDoor LaserPowerup 2.
1318     case 345: // jd64 - BlzOpenDoor LaserPowerup 3.
1319         if(EV_DoLockedDoor(line, DT_BLAZEOPEN, mo))
1320         {
1321             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1322             xline->special = 0;
1323         }
1324         break;
1325 
1326     case 414: // jd64
1327         if(EV_DoPlat(line, PT_UPWAITDOWNSTAY, 1))
1328             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1329         break;
1330 
1331     case 416: // jd64
1332         if(EV_DoFloorAndCeiling(line, FT_TOHIGHESTPLUS8, CT_RAISETOHIGHEST))
1333         {
1334             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1335             xline->special = 0;
1336         }
1337         break;
1338 
1339     case 424: // jd64
1340         if(EV_DoCeiling(line, CT_CUSTOM))
1341             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1342         break;
1343 
1344     case 425: // jd64
1345         if(EV_DoCeiling(line, CT_CUSTOM))
1346         {
1347             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1348             xline->special = 0;
1349         }
1350         break;
1351 
1352     case 428: // jd64
1353         if(EV_DoFloor(line, FT_TOHIGHESTPLUSBITMIP))
1354             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, BUTTONTIME);
1355         break;
1356 
1357     case 429: // jd64
1358         if(EV_DoFloor(line, FT_TOHIGHESTPLUSBITMIP))
1359         {
1360             P_ToggleSwitch((Side *)P_GetPtrp(line, DMU_FRONT), SFX_NONE, false, 0);
1361             xline->special = 0;
1362         }
1363         break;
1364     }
1365 
1366     return true;
1367 }
1368