2 //**************************************************************************
4 //** p_spec.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
19 // MACROS ------------------------------------------------------------------
21 #define MAX_TAGGED_LINES 64
23 // TYPES -------------------------------------------------------------------
25 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
27 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
29 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
31 static boolean CheckedLockedDoor(mobj_t *mo, byte lock);
33 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
35 // PUBLIC DATA DEFINITIONS -------------------------------------------------
44 { "X_005", FLOOR_WATER },
45 { "X_001", FLOOR_LAVA },
46 { "X_009", FLOOR_SLUDGE },
47 { "F_033", FLOOR_ICE },
51 // PRIVATE DATA DEFINITIONS ------------------------------------------------
57 } TaggedLines[MAX_TAGGED_LINES];
58 static int TaggedLineCount;
62 // CODE --------------------------------------------------------------------
64 //==========================================================================
68 //==========================================================================
72 memset(&LavaInflictor, 0, sizeof(mobj_t));
73 LavaInflictor.type = MT_CIRCLEFLAME;
74 LavaInflictor.flags2 = MF2_FIREDAMAGE|MF2_NODMGTHRUST;
77 //==========================================================================
81 //==========================================================================
83 void P_InitTerrainTypes(void)
89 size = (numflats+1)*sizeof(int);
90 TerrainTypes = Z_Malloc(size, PU_STATIC, 0);
91 memset(TerrainTypes, 0, size);
92 for(i = 0; TerrainTypeDefs[i].type != -1; i++)
94 lump = W_CheckNumForName(TerrainTypeDefs[i].name);
97 TerrainTypes[lump-firstflat] = TerrainTypeDefs[i].type;
102 //==========================================================================
106 // Will return a side_t* given the number of the current sector, the
107 // line number, and the side (0/1) that you want.
109 //==========================================================================
112 side_t *getSide(int currentSector, int line, int side)
114 return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
118 //==========================================================================
122 // Will return a sector_t* given the number of the current sector, the
123 // line number, and the side (0/1) that you want.
125 //==========================================================================
128 sector_t *getSector(int currentSector, int line, int side)
130 return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
134 //==========================================================================
138 // Given the sector number and the line number, will tell you whether
139 // the line is two-sided or not.
141 //==========================================================================
144 int twoSided(int sector, int line)
146 return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
150 //==================================================================
152 // Return sector_t * of sector next to current. NULL if not two-sided line
154 //==================================================================
155 sector_t *getNextSector(line_t *line,sector_t *sec)
157 if (!(line->flags & ML_TWOSIDED))
160 if (line->frontsector == sec)
161 return line->backsector;
163 return line->frontsector;
166 //==================================================================
168 // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
170 //==================================================================
171 fixed_t P_FindLowestFloorSurrounding(sector_t *sec)
176 fixed_t floor = sec->floorheight;
178 for (i=0 ;i < sec->linecount ; i++)
180 check = sec->lines[i];
181 other = getNextSector(check,sec);
184 if (other->floorheight < floor)
185 floor = other->floorheight;
190 //==================================================================
192 // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
194 //==================================================================
195 fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
200 fixed_t floor = -500*FRACUNIT;
202 for (i=0 ;i < sec->linecount ; i++)
204 check = sec->lines[i];
205 other = getNextSector(check,sec);
208 if (other->floorheight > floor)
209 floor = other->floorheight;
214 //==================================================================
216 // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
218 //==================================================================
219 fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight)
226 fixed_t height = currentheight;
227 fixed_t heightlist[20]; // 20 adjoining sectors max!
229 for (i =0,h = 0 ;i < sec->linecount ; i++)
231 check = sec->lines[i];
232 other = getNextSector(check,sec);
235 if (other->floorheight > height)
236 heightlist[h++] = other->floorheight;
240 // Find lowest height in list
243 for (i = 1;i < h;i++)
244 if (heightlist[i] < min)
250 //==================================================================
252 // FIND LOWEST CEILING IN THE SURROUNDING SECTORS
254 //==================================================================
255 fixed_t P_FindLowestCeilingSurrounding(sector_t *sec)
260 fixed_t height = MAXINT;
262 for (i=0 ;i < sec->linecount ; i++)
264 check = sec->lines[i];
265 other = getNextSector(check,sec);
268 if (other->ceilingheight < height)
269 height = other->ceilingheight;
274 //==================================================================
276 // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
278 //==================================================================
279 fixed_t P_FindHighestCeilingSurrounding(sector_t *sec)
286 for (i=0 ;i < sec->linecount ; i++)
288 check = sec->lines[i];
289 other = getNextSector(check,sec);
292 if (other->ceilingheight > height)
293 height = other->ceilingheight;
298 //==================================================================
300 // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
302 //==================================================================
305 int P_FindSectorFromLineTag(line_t *line,int start)
309 for (i=start+1;i<numsectors;i++)
310 if (sectors[i].tag == line->arg1)
316 //=========================================================================
318 // P_FindSectorFromTag
320 //=========================================================================
322 int P_FindSectorFromTag(int tag, int start)
326 for(i = start+1; i < numsectors; i++)
328 if(sectors[i].tag == tag)
336 //==================================================================
338 // Find minimum light from an adjacent sector
340 //==================================================================
343 int P_FindMinSurroundingLight(sector_t *sector,int max)
351 for (i=0 ; i < sector->linecount ; i++)
353 line = sector->lines[i];
354 check = getNextSector(line,sector);
357 if (check->lightlevel < min)
358 min = check->lightlevel;
364 //=========================================================================
366 // EV_SectorSoundChange
368 //=========================================================================
370 boolean EV_SectorSoundChange(byte *args)
381 while((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0)
383 sectors[secNum].seqType = args[1];
389 //============================================================================
393 //============================================================================
395 static boolean CheckedLockedDoor(mobj_t *mo, byte lock)
397 extern char *TextKeyMessages[11];
398 char LockedBuffer[80];
408 if(!(mo->player->keys&(1<<(lock-1))))
410 sprintf(LockedBuffer, "YOU NEED THE %s\n",
411 TextKeyMessages[lock-1]);
412 P_SetMessage(mo->player, LockedBuffer, true);
413 S_StartSound(mo, SFX_DOOR_LOCKED);
420 //==========================================================================
422 // EV_LineSearchForPuzzleItem
424 //==========================================================================
426 boolean EV_LineSearchForPuzzleItem(line_t *line, byte *args, mobj_t *mo)
430 artitype_t type,arti;
432 if (!mo) return false;
434 if (!player) return false;
436 // Search player's inventory for puzzle items
437 for (i=0; i<player->artifactCount; i++)
439 arti = player->inventory[i].type;
440 type = arti - arti_firstpuzzitem;
441 if (type < 0) continue;
442 if (type == line->arg1)
444 // A puzzle item was found for the line
445 if (P_UseArtifact(player, arti))
447 // A puzzle item was found for the line
448 P_PlayerRemoveArtifact(player, i);
449 if(player == &players[consoleplayer])
451 if(arti < arti_firstpuzzitem)
453 S_StartSound(NULL, SFX_ARTIFACT_USE);
457 S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
471 ==============================================================================
475 Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
477 ==============================================================================
479 //============================================================================
481 // P_ExecuteLineSpecial
483 //============================================================================
485 boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side,
488 boolean buttonSuccess;
490 buttonSuccess = false;
493 case 1: // Poly Start Line
495 case 2: // Poly Rotate Left
496 buttonSuccess = EV_RotatePoly(line, args, 1, false);
498 case 3: // Poly Rotate Right
499 buttonSuccess = EV_RotatePoly(line, args, -1, false);
502 buttonSuccess = EV_MovePoly(line, args, false, false);
504 case 5: // Poly Explicit Line: Only used in initialization
506 case 6: // Poly Move Times 8
507 buttonSuccess = EV_MovePoly(line, args, true, false);
509 case 7: // Poly Door Swing
510 buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING);
512 case 8: // Poly Door Slide
513 buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE);
515 case 10: // Door Close
516 buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE);
518 case 11: // Door Open
521 buttonSuccess = EV_VerticalDoor(line, mo);
525 buttonSuccess = EV_DoDoor(line, args, DREV_OPEN);
528 case 12: // Door Raise
531 buttonSuccess = EV_VerticalDoor(line, mo);
535 buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
538 case 13: // Door Locked_Raise
539 if(CheckedLockedDoor(mo, args[3]))
543 buttonSuccess = EV_VerticalDoor(line, mo);
547 buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
551 case 20: // Floor Lower by Value
552 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
554 case 21: // Floor Lower to Lowest
555 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST);
557 case 22: // Floor Lower to Nearest
558 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR);
560 case 23: // Floor Raise by Value
561 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
563 case 24: // Floor Raise to Highest
564 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR);
566 case 25: // Floor Raise to Nearest
567 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST);
569 case 26: // Stairs Build Down Normal
570 buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL);
572 case 27: // Build Stairs Up Normal
573 buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL);
575 case 28: // Floor Raise and Crush
576 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH);
578 case 29: // Build Pillar (no crushing)
579 buttonSuccess = EV_BuildPillar(line, args, false);
581 case 30: // Open Pillar
582 buttonSuccess = EV_OpenPillar(line, args);
584 case 31: // Stairs Build Down Sync
585 buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC);
587 case 32: // Build Stairs Up Sync
588 buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC);
590 case 35: // Raise Floor by Value Times 8
591 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8);
593 case 36: // Lower Floor by Value Times 8
594 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8);
596 case 40: // Ceiling Lower by Value
597 buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
599 case 41: // Ceiling Raise by Value
600 buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
602 case 42: // Ceiling Crush and Raise
603 buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE);
605 case 43: // Ceiling Lower and Crush
606 buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH);
608 case 44: // Ceiling Crush Stop
609 buttonSuccess = EV_CeilingCrushStop(line, args);
611 case 45: // Ceiling Crush Raise and Stay
612 buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY);
614 case 46: // Floor Crush Stop
615 buttonSuccess = EV_FloorCrushStop(line, args);
617 case 60: // Plat Perpetual Raise
618 buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0);
620 case 61: // Plat Stop
621 EV_StopPlat(line, args);
623 case 62: // Plat Down-Wait-Up-Stay
624 buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0);
626 case 63: // Plat Down-by-Value*8-Wait-Up-Stay
627 buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY,
630 case 64: // Plat Up-Wait-Down-Stay
631 buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0);
633 case 65: // Plat Up-by-Value*8-Wait-Down-Stay
634 buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY,
637 case 66: // Floor Lower Instant * 8
638 buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT);
640 case 67: // Floor Raise Instant * 8
641 buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT);
643 case 68: // Floor Move to Value * 8
644 buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8);
646 case 69: // Ceiling Move to Value * 8
647 buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8);
651 { // Only teleport when crossing the front side of a line
652 buttonSuccess = EV_Teleport(args[0], mo, true);
655 case 71: // Teleport, no fog
657 { // Only teleport when crossing the front side of a line
658 buttonSuccess = EV_Teleport(args[0], mo, false);
661 case 72: // Thrust Mobj
662 if(!side) // Only thrust on side 0
664 P_ThrustMobj(mo, args[0]*(ANGLE_90/64), args[1]<<FRACBITS);
668 case 73: // Damage Mobj
671 P_DamageMobj(mo, NULL, NULL, args[0]);
674 { // If arg1 is zero, then guarantee a kill
675 P_DamageMobj(mo, NULL, NULL, 10000);
679 case 74: // Teleport_NewMap
681 { // Only teleport when crossing the front side of a line
682 if(!(mo && mo->player && mo->player->playerstate
683 == PST_DEAD)) // Players must be alive to teleport
685 G_Completed(args[0], args[1]);
686 buttonSuccess = true;
690 case 75: // Teleport_EndGame
692 { // Only teleport when crossing the front side of a line
693 if(!(mo && mo->player && mo->player->playerstate
694 == PST_DEAD)) // Players must be alive to teleport
696 buttonSuccess = true;
698 { // Winning in deathmatch just goes back to map 1
702 { // Passing -1, -1 to G_Completed() starts the Finale
708 case 80: // ACS_Execute
710 P_StartACS(args[0], args[1], &args[2], mo, line, side);
712 case 81: // ACS_Suspend
713 buttonSuccess = P_SuspendACS(args[0], args[1]);
715 case 82: // ACS_Terminate
716 buttonSuccess = P_TerminateACS(args[0], args[1]);
718 case 83: // ACS_LockedExecute
719 buttonSuccess = P_StartLockedACS(line, args, mo, side);
721 case 90: // Poly Rotate Left Override
722 buttonSuccess = EV_RotatePoly(line, args, 1, true);
724 case 91: // Poly Rotate Right Override
725 buttonSuccess = EV_RotatePoly(line, args, -1, true);
727 case 92: // Poly Move Override
728 buttonSuccess = EV_MovePoly(line, args, false, true);
730 case 93: // Poly Move Times 8 Override
731 buttonSuccess = EV_MovePoly(line, args, true, true);
733 case 94: // Build Pillar Crush
734 buttonSuccess = EV_BuildPillar(line, args, true);
736 case 95: // Lower Floor and Ceiling
737 buttonSuccess = EV_DoFloorAndCeiling(line, args, false);
739 case 96: // Raise Floor and Ceiling
740 buttonSuccess = EV_DoFloorAndCeiling(line, args, true);
742 case 109: // Force Lightning
743 buttonSuccess = true;
746 case 110: // Light Raise by Value
747 buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE);
749 case 111: // Light Lower by Value
750 buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE);
752 case 112: // Light Change to Value
753 buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE);
755 case 113: // Light Fade
756 buttonSuccess = EV_SpawnLight(line, args, LITE_FADE);
758 case 114: // Light Glow
759 buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW);
761 case 115: // Light Flicker
762 buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER);
764 case 116: // Light Strobe
765 buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE);
767 case 120: // Quake Tremor
768 buttonSuccess = A_LocalQuake(args, mo);
770 case 129: // UsePuzzleItem
771 buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo);
773 case 130: // Thing_Activate
774 buttonSuccess = EV_ThingActivate(args[0]);
776 case 131: // Thing_Deactivate
777 buttonSuccess = EV_ThingDeactivate(args[0]);
779 case 132: // Thing_Remove
780 buttonSuccess = EV_ThingRemove(args[0]);
782 case 133: // Thing_Destroy
783 buttonSuccess = EV_ThingDestroy(args[0]);
785 case 134: // Thing_Projectile
786 buttonSuccess = EV_ThingProjectile(args, 0);
788 case 135: // Thing_Spawn
789 buttonSuccess = EV_ThingSpawn(args, 1);
791 case 136: // Thing_ProjectileGravity
792 buttonSuccess = EV_ThingProjectile(args, 1);
794 case 137: // Thing_SpawnNoFog
795 buttonSuccess = EV_ThingSpawn(args, 0);
797 case 138: // Floor_Waggle
798 buttonSuccess = EV_StartFloorWaggle(args[0], args[1],
799 args[2], args[3], args[4]);
801 case 140: // Sector_SoundChange
802 buttonSuccess = EV_SectorSoundChange(args);
805 // Line specials only processed during level initialization
806 // 100: Scroll_Texture_Left
807 // 101: Scroll_Texture_Right
808 // 102: Scroll_Texture_Up
809 // 103: Scroll_Texture_Down
810 // 121: Line_SetIdentification
812 // Inert Line specials
816 return buttonSuccess;
819 //============================================================================
823 //============================================================================
825 boolean P_ActivateLine(line_t *line, mobj_t *mo, int side, int activationType)
829 boolean buttonSuccess;
831 lineActivation = GET_SPAC(line->flags);
832 if(lineActivation != activationType)
836 if(!mo->player && !(mo->flags&MF_MISSILE))
838 if(lineActivation != SPAC_MCROSS)
839 { // currently, monsters can only activate the MCROSS activation type
842 if(line->flags & ML_SECRET)
843 return false; // never open secret doors
845 repeat = line->flags&ML_REPEAT_SPECIAL;
846 buttonSuccess = false;
848 buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line,
850 if(!repeat && buttonSuccess)
851 { // clear the special on non-retriggerable lines
854 if((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT)
857 P_ChangeSwitchTexture(line, repeat);
862 //----------------------------------------------------------------------------
864 // PROC P_PlayerInSpecialSector
866 // Called every tic frame that the player origin is in a special sector.
868 //----------------------------------------------------------------------------
870 void P_PlayerInSpecialSector(player_t *player)
873 static int pushTab[3] =
880 sector = player->mo->subsector->sector;
881 if(player->mo->z != sector->floorheight)
882 { // Player is not touching the floor
885 switch(sector->special)
887 case 9: // SecretArea
888 player->secretcount++;
892 case 201: case 202: case 203: // Scroll_North_xxx
893 P_Thrust(player, ANG90, pushTab[sector->special-201]);
895 case 204: case 205: case 206: // Scroll_East_xxx
896 P_Thrust(player, 0, pushTab[sector->special-204]);
898 case 207: case 208: case 209: // Scroll_South_xxx
899 P_Thrust(player, ANG270, pushTab[sector->special-207]);
901 case 210: case 211: case 212: // Scroll_West_xxx
902 P_Thrust(player, ANG180, pushTab[sector->special-210]);
904 case 213: case 214: case 215: // Scroll_NorthWest_xxx
905 P_Thrust(player, ANG90+ANG45, pushTab[sector->special-213]);
907 case 216: case 217: case 218: // Scroll_NorthEast_xxx
908 P_Thrust(player, ANG45, pushTab[sector->special-216]);
910 case 219: case 220: case 221: // Scroll_SouthEast_xxx
911 P_Thrust(player, ANG270+ANG45, pushTab[sector->special-219]);
913 case 222: case 223: case 224: // Scroll_SouthWest_xxx
914 P_Thrust(player, ANG180+ANG45, pushTab[sector->special-222]);
917 case 40: case 41: case 42: case 43: case 44: case 45:
918 case 46: case 47: case 48: case 49: case 50: case 51:
919 // Wind specials are handled in (P_mobj):P_XYMovement
922 case 26: // Stairs_Special1
923 case 27: // Stairs_Special2
924 // Used in (P_floor):ProcessStairSector
927 case 198: // Lightning Special
928 case 199: // Lightning Flash special
930 // Used in (R_plane):R_Drawplanes
933 I_Error("P_PlayerInSpecialSector: "
934 "unknown special %i", sector->special);
938 //============================================================================
940 // P_PlayerOnSpecialFlat
942 //============================================================================
944 void P_PlayerOnSpecialFlat(player_t *player, int floorType)
946 if(player->mo->z != player->mo->floorz)
947 { // Player is not touching the floor
955 P_DamageMobj(player->mo, &LavaInflictor, NULL, 10);
956 S_StartSound(player->mo, SFX_LAVA_SIZZLE);
964 //----------------------------------------------------------------------------
966 // PROC P_UpdateSpecials
968 //----------------------------------------------------------------------------
970 void P_UpdateSpecials(void)
975 for(i = 0; i < MAXBUTTONS; i++)
977 if(buttonlist[i].btimer)
979 buttonlist[i].btimer--;
980 if(!buttonlist[i].btimer)
982 switch(buttonlist[i].where)
985 sides[buttonlist[i].line->sidenum[0]].toptexture =
986 buttonlist[i].btexture;
989 sides[buttonlist[i].line->sidenum[0]].midtexture =
990 buttonlist[i].btexture;
993 sides[buttonlist[i].line->sidenum[0]].bottomtexture =
994 buttonlist[i].btexture;
997 //S_StartSound((mobj_t *)&buttonlist[i].soundorg, sfx_switch);
998 memset(&buttonlist[i], 0, sizeof(button_t));
1005 ==============================================================================
1009 ==============================================================================
1012 ================================================================================
1015 = After the map has been loaded, scan for specials that
1018 ===============================================================================
1021 short numlinespecials;
1022 line_t *linespeciallist[MAXLINEANIMS];
1024 void P_SpawnSpecials (void)
1030 // Init special SECTORs
1033 for (i=0 ; i<numsectors ; i++, sector++)
1035 if (!sector->special)
1037 switch (sector->special)
1039 case 1: // Phased light
1040 // Hardcoded base, use sector->lightlevel as the index
1041 P_SpawnPhasedLight(sector, 80, -1);
1043 case 2: // Phased light sequence start
1044 P_SpawnLightSequence(sector, 1);
1046 // Specials 3 & 4 are used by the phased light sequences
1049 case 1: // FLICKERING LIGHTS
1050 P_SpawnLightFlash (sector);
1052 case 2: // STROBE FAST
1053 P_SpawnStrobeFlash(sector,FASTDARK,0);
1055 case 3: // STROBE SLOW
1056 P_SpawnStrobeFlash(sector,SLOWDARK,0);
1058 case 4: // STROBE FAST/DEATH SLIME
1059 P_SpawnStrobeFlash(sector,FASTDARK,0);
1060 sector->special = 4;
1062 case 8: // GLOWING LIGHT
1063 P_SpawnGlowingLight(sector);
1065 case 9: // SECRET SECTOR
1068 case 10: // DOOR CLOSE IN 30 SECONDS
1069 P_SpawnDoorCloseIn30 (sector);
1071 case 12: // SYNC STROBE SLOW
1072 P_SpawnStrobeFlash (sector, SLOWDARK, 1);
1074 case 13: // SYNC STROBE FAST
1075 P_SpawnStrobeFlash (sector, FASTDARK, 1);
1077 case 14: // DOOR RAISE IN 5 MINUTES
1078 P_SpawnDoorRaiseIn5Mins (sector, i);
1086 // Init line EFFECTs
1088 numlinespecials = 0;
1089 TaggedLineCount = 0;
1090 for(i = 0; i < numlines; i++)
1092 switch(lines[i].special)
1094 case 100: // Scroll_Texture_Left
1095 case 101: // Scroll_Texture_Right
1096 case 102: // Scroll_Texture_Up
1097 case 103: // Scroll_Texture_Down
1098 linespeciallist[numlinespecials] = &lines[i];
1101 case 121: // Line_SetIdentification
1104 if(TaggedLineCount == MAX_TAGGED_LINES)
1106 I_Error("P_SpawnSpecials: MAX_TAGGED_LINES "
1107 "(%d) exceeded.", MAX_TAGGED_LINES);
1109 TaggedLines[TaggedLineCount].line = &lines[i];
1110 TaggedLines[TaggedLineCount++].lineTag
1113 lines[i].special = 0;
1119 // Init other misc stuff
1121 for (i = 0;i < MAXCEILINGS;i++)
1122 activeceilings[i] = NULL;
1123 for (i = 0;i < MAXPLATS;i++)
1124 activeplats[i] = NULL;
1125 for (i = 0;i < MAXBUTTONS;i++)
1126 memset(&buttonlist[i],0,sizeof(button_t));
1128 // Initialize flat and texture animations
1132 //==========================================================================
1136 //==========================================================================
1138 line_t *P_FindLine(int lineTag, int *searchPosition)
1142 for(i = *searchPosition+1; i < TaggedLineCount; i++)
1144 if(TaggedLines[i].lineTag == lineTag)
1146 *searchPosition = i;
1147 return TaggedLines[i].line;
1150 *searchPosition = -1;