1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
18 // Revision 1.1 2000/02/29 18:21:05 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // Implements special effects:
24 // Texture animation, height or lighting changes
25 // according to adjacent sectors, respective
26 // utility functions, etc.
27 // Line Tag handling. Line and Sector triggers.
29 //-----------------------------------------------------------------------------
60 // Animating textures and planes
61 // There is another anim_t used in wi_stuff, unrelated.
74 // source animation definition
78 boolean istexture
; // if false, it is a flat
88 extern anim_t anims
[MAXANIMS
];
89 extern anim_t
* lastanim
;
95 // Floor/ceiling animation sequences,
96 // defined by first and last frame,
97 // i.e. the flat (64x64 tile) name to
99 // The full animation sequence is given
100 // using all the flats between the start
101 // and end entry, in the order found in
104 animdef_t animdefs
[] =
106 {false, "NUKAGE3", "NUKAGE1", 8},
107 {false, "FWATER4", "FWATER1", 8},
108 {false, "SWATER4", "SWATER1", 8},
109 {false, "LAVA4", "LAVA1", 8},
110 {false, "BLOOD3", "BLOOD1", 8},
112 // DOOM II flat animations.
113 {false, "RROCK08", "RROCK05", 8},
114 {false, "SLIME04", "SLIME01", 8},
115 {false, "SLIME08", "SLIME05", 8},
116 {false, "SLIME12", "SLIME09", 8},
118 {true, "BLODGR4", "BLODGR1", 8},
119 {true, "SLADRIP3", "SLADRIP1", 8},
121 {true, "BLODRIP4", "BLODRIP1", 8},
122 {true, "FIREWALL", "FIREWALA", 8},
123 {true, "GSTFONT3", "GSTFONT1", 8},
124 {true, "FIRELAVA", "FIRELAV3", 8},
125 {true, "FIREMAG3", "FIREMAG1", 8},
126 {true, "FIREBLU2", "FIREBLU1", 8},
127 {true, "ROCKRED3", "ROCKRED1", 8},
129 {true, "BFALL4", "BFALL1", 8},
130 {true, "SFALL4", "SFALL1", 8},
131 {true, "WFALL4", "WFALL1", 8},
132 {true, "DBRAIN4", "DBRAIN1", 8},
137 anim_t anims
[MAXANIMS
];
142 // Animating line specials
144 #define MAXLINEANIMS 64
146 extern short numlinespecials
;
147 extern line_t
* linespeciallist
[MAXLINEANIMS
];
151 void P_InitPicAnims (void)
158 for (i
=0 ; animdefs
[i
].istexture
!= -1 ; i
++)
160 if (animdefs
[i
].istexture
)
162 // different episode ?
163 if (R_CheckTextureNumForName(animdefs
[i
].startname
) == -1)
166 lastanim
->picnum
= R_TextureNumForName (animdefs
[i
].endname
);
167 lastanim
->basepic
= R_TextureNumForName (animdefs
[i
].startname
);
171 if (W_CheckNumForName(animdefs
[i
].startname
) == -1)
174 lastanim
->picnum
= R_FlatNumForName (animdefs
[i
].endname
);
175 lastanim
->basepic
= R_FlatNumForName (animdefs
[i
].startname
);
178 lastanim
->istexture
= animdefs
[i
].istexture
;
179 lastanim
->numpics
= lastanim
->picnum
- lastanim
->basepic
+ 1;
181 if (lastanim
->numpics
< 2)
182 I_Error ("P_InitPicAnims: bad cycle from %s to %s",
183 animdefs
[i
].startname
,
184 animdefs
[i
].endname
);
186 lastanim
->speed
= animdefs
[i
].speed
;
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.
212 return &sides
[ (sectors
[currentSector
].lines
[line
])->sidenum
[side
] ];
218 // Will return a sector_t*
219 // given the number of the current sector,
220 // the line number and the side (0/1) that you want.
228 return sides
[ (sectors
[currentSector
].lines
[line
])->sidenum
[side
] ].sector
;
234 // Given the sector number and the line number,
235 // it will tell you whether the line is two-sided or not.
242 return (sectors
[sector
].lines
[line
])->flags
& ML_TWOSIDED
;
250 // Return sector_t * of sector next to current.
251 // NULL if not two-sided line
258 if (!(line
->flags
& ML_TWOSIDED
))
261 if (line
->frontsector
== sec
)
262 return line
->backsector
;
264 return line
->frontsector
;
270 // P_FindLowestFloorSurrounding()
271 // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
273 fixed_t
P_FindLowestFloorSurrounding(sector_t
* sec
)
278 fixed_t floor
= sec
->floorheight
;
280 for (i
=0 ;i
< sec
->linecount
; i
++)
282 check
= sec
->lines
[i
];
283 other
= getNextSector(check
,sec
);
288 if (other
->floorheight
< floor
)
289 floor
= other
->floorheight
;
297 // P_FindHighestFloorSurrounding()
298 // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
300 fixed_t
P_FindHighestFloorSurrounding(sector_t
*sec
)
305 fixed_t floor
= -500*FRACUNIT
;
307 for (i
=0 ;i
< sec
->linecount
; i
++)
309 check
= sec
->lines
[i
];
310 other
= getNextSector(check
,sec
);
315 if (other
->floorheight
> floor
)
316 floor
= other
->floorheight
;
324 // P_FindNextHighestFloor
325 // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
326 // Note: this should be doable w/o a fixed array.
328 // 20 adjoining sectors max!
329 #define MAX_ADJOINING_SECTORS 20
332 P_FindNextHighestFloor
341 fixed_t height
= currentheight
;
344 fixed_t heightlist
[MAX_ADJOINING_SECTORS
];
346 for (i
=0, h
=0 ;i
< sec
->linecount
; i
++)
348 check
= sec
->lines
[i
];
349 other
= getNextSector(check
,sec
);
354 if (other
->floorheight
> height
)
355 heightlist
[h
++] = other
->floorheight
;
357 // Check for overflow. Exit.
358 if ( h
>= MAX_ADJOINING_SECTORS
)
361 "Sector with more than 20 adjoining sectors\n" );
366 // Find lowest height in list
368 return currentheight
;
373 for (i
= 1;i
< h
;i
++)
374 if (heightlist
[i
] < min
)
382 // FIND LOWEST CEILING IN THE SURROUNDING SECTORS
385 P_FindLowestCeilingSurrounding(sector_t
* sec
)
390 fixed_t height
= MAXINT
;
392 for (i
=0 ;i
< sec
->linecount
; i
++)
394 check
= sec
->lines
[i
];
395 other
= getNextSector(check
,sec
);
400 if (other
->ceilingheight
< height
)
401 height
= other
->ceilingheight
;
408 // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
410 fixed_t
P_FindHighestCeilingSurrounding(sector_t
* sec
)
417 for (i
=0 ;i
< sec
->linecount
; i
++)
419 check
= sec
->lines
[i
];
420 other
= getNextSector(check
,sec
);
425 if (other
->ceilingheight
> height
)
426 height
= other
->ceilingheight
;
434 // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
437 P_FindSectorFromLineTag
443 for (i
=start
+1;i
<numsectors
;i
++)
444 if (sectors
[i
].tag
== line
->tag
)
454 // Find minimum light from an adjacent sector
457 P_FindMinSurroundingLight
467 for (i
=0 ; i
< sector
->linecount
; i
++)
469 line
= sector
->lines
[i
];
470 check
= getNextSector(line
,sector
);
475 if (check
->lightlevel
< min
)
476 min
= check
->lightlevel
;
485 // Events are operations triggered by using, crossing,
486 // or shooting special lines, or by timed thinkers.
490 // P_CrossSpecialLine - TRIGGER
491 // Called every time a thing origin is about
492 // to cross a line with a non 0 special.
503 line
= &lines
[linenum
];
505 // Triggers that other things can activate
508 // Things that should NOT trigger specials...
524 switch(line
->special
)
526 case 39: // TELEPORT TRIGGER
527 case 97: // TELEPORT RETRIGGER
528 case 125: // TELEPORT MONSTERONLY TRIGGER
529 case 126: // TELEPORT MONSTERONLY RETRIGGER
530 case 4: // RAISE DOOR
531 case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER
532 case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER
541 // Note: could use some const's here.
542 switch (line
->special
)
545 // All from here to RETRIGGERS.
548 EV_DoDoor(line
,open
);
554 EV_DoDoor(line
,close
);
560 EV_DoDoor(line
,normal
);
566 EV_DoFloor(line
,raiseFloor
);
571 // Fast Ceiling Crush & Raise
572 EV_DoCeiling(line
,fastCrushAndRaise
);
578 EV_BuildStairs(line
,build8
);
584 EV_DoPlat(line
,downWaitUpStay
,0);
589 // Light Turn On - brightest near
590 EV_LightTurnOn(line
,0);
596 EV_LightTurnOn(line
,255);
602 EV_DoDoor(line
,close30ThenOpen
);
607 // Start Light Strobing
608 EV_StartLightStrobing(line
);
614 EV_DoFloor(line
,lowerFloor
);
619 // Raise floor to nearest height and change texture
620 EV_DoPlat(line
,raiseToNearestAndChange
,0);
625 // Ceiling Crush and Raise
626 EV_DoCeiling(line
,crushAndRaise
);
631 // Raise floor to shortest texture height
632 // on either side of lines.
633 EV_DoFloor(line
,raiseToTexture
);
639 EV_LightTurnOn(line
,35);
644 // Lower Floor (TURBO)
645 EV_DoFloor(line
,turboLower
);
651 EV_DoFloor(line
,lowerAndChange
);
656 // Lower Floor To Lowest
657 EV_DoFloor( line
, lowerFloorToLowest
);
663 EV_Teleport( line
, side
, thing
);
668 // RaiseCeilingLowerFloor
669 EV_DoCeiling( line
, raiseToHighest
);
670 EV_DoFloor( line
, lowerFloorToLowest
);
676 EV_DoCeiling( line
, lowerAndCrush
);
686 // Perpetual Platform Raise
687 EV_DoPlat(line
,perpetualRaise
,0);
699 EV_DoFloor(line
,raiseFloorCrush
);
704 // Ceiling Crush Stop
705 EV_CeilingCrushStop(line
);
711 EV_DoFloor(line
,raiseFloor24
);
716 // Raise Floor 24 And Change
717 EV_DoFloor(line
,raiseFloor24AndChange
);
722 // Turn lights off in sector(tag)
723 EV_TurnTagLightsOff(line
);
728 // Blazing Door Raise (faster than TURBO!)
729 EV_DoDoor (line
,blazeRaise
);
734 // Blazing Door Open (faster than TURBO!)
735 EV_DoDoor (line
,blazeOpen
);
740 // Build Stairs Turbo 16
741 EV_BuildStairs(line
,turbo16
);
746 // Blazing Door Close (faster than TURBO!)
747 EV_DoDoor (line
,blazeClose
);
752 // Raise floor to nearest surr. floor
753 EV_DoFloor(line
,raiseFloorToNearest
);
758 // Blazing PlatDownWaitUpStay
759 EV_DoPlat(line
,blazeDWUS
,0);
765 G_SecretExitLevel ();
769 // TELEPORT MonsterONLY
772 EV_Teleport( line
, side
, thing
);
779 EV_DoFloor(line
,raiseFloorTurbo
);
784 // Silent Ceiling Crush & Raise
785 EV_DoCeiling(line
,silentCrushAndRaise
);
789 // RETRIGGERS. All from here till end.
792 EV_DoCeiling( line
, lowerAndCrush
);
796 // Ceiling Crush and Raise
797 EV_DoCeiling(line
,crushAndRaise
);
801 // Ceiling Crush Stop
802 EV_CeilingCrushStop(line
);
807 EV_DoDoor(line
,close
);
812 EV_DoDoor(line
,close30ThenOpen
);
816 // Fast Ceiling Crush & Raise
817 EV_DoCeiling(line
,fastCrushAndRaise
);
822 EV_LightTurnOn(line
,35);
826 // Light Turn On - brightest near
827 EV_LightTurnOn(line
,0);
832 EV_LightTurnOn(line
,255);
836 // Lower Floor To Lowest
837 EV_DoFloor( line
, lowerFloorToLowest
);
842 EV_DoFloor(line
,lowerFloor
);
847 EV_DoFloor(line
,lowerAndChange
);
852 EV_DoDoor(line
,open
);
856 // Perpetual Platform Raise
857 EV_DoPlat(line
,perpetualRaise
,0);
862 EV_DoPlat(line
,downWaitUpStay
,0);
872 EV_DoDoor(line
,normal
);
877 EV_DoFloor(line
,raiseFloor
);
882 EV_DoFloor(line
,raiseFloor24
);
886 // Raise Floor 24 And Change
887 EV_DoFloor(line
,raiseFloor24AndChange
);
892 EV_DoFloor(line
,raiseFloorCrush
);
896 // Raise floor to nearest height
897 // and change texture.
898 EV_DoPlat(line
,raiseToNearestAndChange
,0);
902 // Raise floor to shortest texture height
903 // on either side of lines.
904 EV_DoFloor(line
,raiseToTexture
);
909 EV_Teleport( line
, side
, thing
);
913 // Lower Floor (TURBO)
914 EV_DoFloor(line
,turboLower
);
918 // Blazing Door Raise (faster than TURBO!)
919 EV_DoDoor (line
,blazeRaise
);
923 // Blazing Door Open (faster than TURBO!)
924 EV_DoDoor (line
,blazeOpen
);
928 // Blazing Door Close (faster than TURBO!)
929 EV_DoDoor (line
,blazeClose
);
933 // Blazing PlatDownWaitUpStay.
934 EV_DoPlat(line
,blazeDWUS
,0);
938 // TELEPORT MonsterONLY.
940 EV_Teleport( line
, side
, thing
);
944 // Raise To Nearest Floor
945 EV_DoFloor(line
,raiseFloorToNearest
);
950 EV_DoFloor(line
,raiseFloorTurbo
);
958 // P_ShootSpecialLine - IMPACT SPECIALS
959 // Called when a thing shoots a special line.
968 // Impacts that other things can activate.
972 switch(line
->special
)
983 switch(line
->special
)
987 EV_DoFloor(line
,raiseFloor
);
988 P_ChangeSwitchTexture(line
,0);
993 EV_DoDoor(line
,open
);
994 P_ChangeSwitchTexture(line
,1);
998 // RAISE FLOOR NEAR AND CHANGE
999 EV_DoPlat(line
,raiseToNearestAndChange
,0);
1000 P_ChangeSwitchTexture(line
,0);
1008 // P_PlayerInSpecialSector
1009 // Called every tic frame
1010 // that the player origin is in a special sector
1012 void P_PlayerInSpecialSector (player_t
* player
)
1016 sector
= player
->mo
->subsector
->sector
;
1018 // Falling, not all the way down yet?
1019 if (player
->mo
->z
!= sector
->floorheight
)
1022 // Has hitten ground.
1023 switch (sector
->special
)
1027 if (!player
->powers
[pw_ironfeet
])
1028 if (!(leveltime
&0x1f))
1029 P_DamageMobj (player
->mo
, NULL
, NULL
, 10);
1034 if (!player
->powers
[pw_ironfeet
])
1035 if (!(leveltime
&0x1f))
1036 P_DamageMobj (player
->mo
, NULL
, NULL
, 5);
1040 // SUPER HELLSLIME DAMAGE
1043 if (!player
->powers
[pw_ironfeet
]
1046 if (!(leveltime
&0x1f))
1047 P_DamageMobj (player
->mo
, NULL
, NULL
, 20);
1053 player
->secretcount
++;
1054 sector
->special
= 0;
1058 // EXIT SUPER DAMAGE! (for E1M8 finale)
1059 player
->cheats
&= ~CF_GODMODE
;
1061 if (!(leveltime
&0x1f))
1062 P_DamageMobj (player
->mo
, NULL
, NULL
, 20);
1064 if (player
->health
<= 10)
1069 I_Error ("P_PlayerInSpecialSector: "
1070 "unknown special %i",
1081 // Animate planes, scroll walls, etc.
1086 void P_UpdateSpecials (void)
1095 if (levelTimer
== true)
1098 if (!levelTimeCount
)
1102 // ANIMATE FLATS AND TEXTURES GLOBALLY
1103 for (anim
= anims
; anim
< lastanim
; anim
++)
1105 for (i
=anim
->basepic
; i
<anim
->basepic
+anim
->numpics
; i
++)
1107 pic
= anim
->basepic
+ ( (leveltime
/anim
->speed
+ i
)%anim
->numpics
);
1108 if (anim
->istexture
)
1109 texturetranslation
[i
] = pic
;
1111 flattranslation
[i
] = pic
;
1116 // ANIMATE LINE SPECIALS
1117 for (i
= 0; i
< numlinespecials
; i
++)
1119 line
= linespeciallist
[i
];
1120 switch(line
->special
)
1123 // EFFECT FIRSTCOL SCROLL +
1124 sides
[line
->sidenum
[0]].textureoffset
+= FRACUNIT
;
1131 for (i
= 0; i
< MAXBUTTONS
; i
++)
1132 if (buttonlist
[i
].btimer
)
1134 buttonlist
[i
].btimer
--;
1135 if (!buttonlist
[i
].btimer
)
1137 switch(buttonlist
[i
].where
)
1140 sides
[buttonlist
[i
].line
->sidenum
[0]].toptexture
=
1141 buttonlist
[i
].btexture
;
1145 sides
[buttonlist
[i
].line
->sidenum
[0]].midtexture
=
1146 buttonlist
[i
].btexture
;
1150 sides
[buttonlist
[i
].line
->sidenum
[0]].bottomtexture
=
1151 buttonlist
[i
].btexture
;
1154 S_StartSound((mobj_t
*)&buttonlist
[i
].soundorg
,sfx_swtchn
);
1155 memset(&buttonlist
[i
],0,sizeof(button_t
));
1164 // Special Stuff that can not be categorized
1166 int EV_DoDonut(line_t
* line
)
1178 while ((secnum
= P_FindSectorFromLineTag(line
,secnum
)) >= 0)
1180 s1
= §ors
[secnum
];
1182 // ALREADY MOVING? IF SO, KEEP GOING...
1183 if (s1
->specialdata
)
1187 s2
= getNextSector(s1
->lines
[0],s1
);
1188 for (i
= 0;i
< s2
->linecount
;i
++)
1190 if ((!(s2
->lines
[i
]->flags
& ML_TWOSIDED
)) ||
1191 (s2
->lines
[i
]->backsector
== s1
))
1193 s3
= s2
->lines
[i
]->backsector
;
1195 // Spawn rising slime
1196 floor
= Z_Malloc (sizeof(*floor
), PU_LEVSPEC
, 0);
1197 P_AddThinker (&floor
->thinker
);
1198 s2
->specialdata
= floor
;
1199 floor
->thinker
.function
.acp1
= (actionf_p1
) T_MoveFloor
;
1200 floor
->type
= donutRaise
;
1201 floor
->crush
= false;
1202 floor
->direction
= 1;
1204 floor
->speed
= FLOORSPEED
/ 2;
1205 floor
->texture
= s3
->floorpic
;
1206 floor
->newspecial
= 0;
1207 floor
->floordestheight
= s3
->floorheight
;
1209 // Spawn lowering donut-hole
1210 floor
= Z_Malloc (sizeof(*floor
), PU_LEVSPEC
, 0);
1211 P_AddThinker (&floor
->thinker
);
1212 s1
->specialdata
= floor
;
1213 floor
->thinker
.function
.acp1
= (actionf_p1
) T_MoveFloor
;
1214 floor
->type
= lowerFloor
;
1215 floor
->crush
= false;
1216 floor
->direction
= -1;
1218 floor
->speed
= FLOORSPEED
/ 2;
1219 floor
->floordestheight
= s3
->floorheight
;
1234 // After the map has been loaded, scan for specials
1235 // that spawn thinkers
1237 short numlinespecials
;
1238 line_t
* linespeciallist
[MAXLINEANIMS
];
1241 // Parses command line parameters.
1242 void P_SpawnSpecials (void)
1249 if (W_CheckNumForName("texture2") >= 0)
1253 // See if -TIMER needs to be used.
1256 i
= M_CheckParm("-avg");
1257 if (i
&& deathmatch
)
1260 levelTimeCount
= 20 * 60 * 35;
1263 i
= M_CheckParm("-timer");
1264 if (i
&& deathmatch
)
1267 time
= atoi(myargv
[i
+1]) * 60 * 35;
1269 levelTimeCount
= time
;
1272 // Init special SECTORs.
1274 for (i
=0 ; i
<numsectors
; i
++, sector
++)
1276 if (!sector
->special
)
1279 switch (sector
->special
)
1282 // FLICKERING LIGHTS
1283 P_SpawnLightFlash (sector
);
1288 P_SpawnStrobeFlash(sector
,FASTDARK
,0);
1293 P_SpawnStrobeFlash(sector
,SLOWDARK
,0);
1297 // STROBE FAST/DEATH SLIME
1298 P_SpawnStrobeFlash(sector
,FASTDARK
,0);
1299 sector
->special
= 4;
1304 P_SpawnGlowingLight(sector
);
1312 // DOOR CLOSE IN 30 SECONDS
1313 P_SpawnDoorCloseIn30 (sector
);
1318 P_SpawnStrobeFlash (sector
, SLOWDARK
, 1);
1323 P_SpawnStrobeFlash (sector
, FASTDARK
, 1);
1327 // DOOR RAISE IN 5 MINUTES
1328 P_SpawnDoorRaiseIn5Mins (sector
, i
);
1332 P_SpawnFireFlicker(sector
);
1338 // Init line EFFECTs
1339 numlinespecials
= 0;
1340 for (i
= 0;i
< numlines
; i
++)
1342 switch(lines
[i
].special
)
1345 // EFFECT FIRSTCOL SCROLL+
1346 linespeciallist
[numlinespecials
] = &lines
[i
];
1353 // Init other misc stuff
1354 for (i
= 0;i
< MAXCEILINGS
;i
++)
1355 activeceilings
[i
] = NULL
;
1357 for (i
= 0;i
< MAXPLATS
;i
++)
1358 activeplats
[i
] = NULL
;
1360 for (i
= 0;i
< MAXBUTTONS
;i
++)
1361 memset(&buttonlist
[i
],0,sizeof(button_t
));
1363 // UNUSED: no horizonal sliders.
1364 // P_InitSlidingDoorFrames();