Source to src/p_spec.c
// P_Spec.c
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
// Macros
#define MAX_AMBIENT_SFX 8 // Per level
// Types
typedef enum
{
afxcmd_play, // (sound)
afxcmd_playabsvol, // (sound, volume)
afxcmd_playrelvol, // (sound, volume)
afxcmd_delay, // (ticks)
afxcmd_delayrand, // (andbits)
afxcmd_end // ()
} afxcmd_t;
// Data
int *LevelAmbientSfx[MAX_AMBIENT_SFX];
int *AmbSfxPtr;
int AmbSfxCount;
int AmbSfxTics;
int AmbSfxVolume;
int AmbSndSeqInit[] =
{ // Startup
afxcmd_end
};
int AmbSndSeq1[] =
{ // Scream
afxcmd_play, sfx_amb1,
afxcmd_end
};
int AmbSndSeq2[] =
{ // Squish
afxcmd_play, sfx_amb2,
afxcmd_end
};
int AmbSndSeq3[] =
{ // Drops
afxcmd_play, sfx_amb3,
afxcmd_delay, 16,
afxcmd_delayrand, 31,
afxcmd_play, sfx_amb7,
afxcmd_delay, 16,
afxcmd_delayrand, 31,
afxcmd_play, sfx_amb3,
afxcmd_delay, 16,
afxcmd_delayrand, 31,
afxcmd_play, sfx_amb7,
afxcmd_delay, 16,
afxcmd_delayrand, 31,
afxcmd_play, sfx_amb3,
afxcmd_delay, 16,
afxcmd_delayrand, 31,
afxcmd_play, sfx_amb7,
afxcmd_delay, 16,
afxcmd_delayrand, 31,
afxcmd_end
};
int AmbSndSeq4[] =
{ // SlowFootSteps
afxcmd_play, sfx_amb4,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb4, -3,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb4, -3,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb4, -3,
afxcmd_delay, 15,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_end
};
int AmbSndSeq5[] =
{ // Heartbeat
afxcmd_play, sfx_amb5,
afxcmd_delay, 35,
afxcmd_play, sfx_amb5,
afxcmd_delay, 35,
afxcmd_play, sfx_amb5,
afxcmd_delay, 35,
afxcmd_play, sfx_amb5,
afxcmd_end
};
int AmbSndSeq6[] =
{ // Bells
afxcmd_play, sfx_amb6,
afxcmd_delay, 17,
afxcmd_playrelvol, sfx_amb6, -8,
afxcmd_delay, 17,
afxcmd_playrelvol, sfx_amb6, -8,
afxcmd_delay, 17,
afxcmd_playrelvol, sfx_amb6, -8,
afxcmd_end
};
int AmbSndSeq7[] =
{ // Growl
afxcmd_play, sfx_bstsit,
afxcmd_end
};
int AmbSndSeq8[] =
{ // Magic
afxcmd_play, sfx_amb8,
afxcmd_end
};
int AmbSndSeq9[] =
{ // Laughter
afxcmd_play, sfx_amb9,
afxcmd_delay, 16,
afxcmd_playrelvol, sfx_amb9, -4,
afxcmd_delay, 16,
afxcmd_playrelvol, sfx_amb9, -4,
afxcmd_delay, 16,
afxcmd_playrelvol, sfx_amb10, -4,
afxcmd_delay, 16,
afxcmd_playrelvol, sfx_amb10, -4,
afxcmd_delay, 16,
afxcmd_playrelvol, sfx_amb10, -4,
afxcmd_end
};
int AmbSndSeq10[] =
{ // FastFootsteps
afxcmd_play, sfx_amb4,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb4, -3,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb4, -3,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb4, -3,
afxcmd_delay, 8,
afxcmd_playrelvol, sfx_amb11, -3,
afxcmd_end
};
int *AmbientSfx[] =
{
AmbSndSeq1, // Scream
AmbSndSeq2, // Squish
AmbSndSeq3, // Drops
AmbSndSeq4, // SlowFootsteps
AmbSndSeq5, // Heartbeat
AmbSndSeq6, // Bells
AmbSndSeq7, // Growl
AmbSndSeq8, // Magic
AmbSndSeq9, // Laughter
AmbSndSeq10 // FastFootsteps
};
animdef_t animdefs[] =
{
// false = flat
// true = texture
{false, "FLTWAWA3", "FLTWAWA1", 8}, // Water
{false, "FLTSLUD3", "FLTSLUD1", 8}, // Sludge
{false, "FLTTELE4", "FLTTELE1", 6}, // Teleport
{false, "FLTFLWW3", "FLTFLWW1", 9}, // River - West
{false, "FLTLAVA4", "FLTLAVA1", 8}, // Lava
{false, "FLATHUH4", "FLATHUH1", 8}, // Super Lava
{true, "LAVAFL3", "LAVAFL1", 6}, // Texture: Lavaflow
{true, "WATRWAL3", "WATRWAL1", 4}, // Texture: Waterfall
{-1}
};
anim_t anims[MAXANIMS];
anim_t *lastanim;
int *TerrainTypes;
struct
{
char *name;
int type;
} TerrainTypeDefs[] =
{
{ "FLTWAWA1", FLOOR_WATER },
{ "FLTFLWW1", FLOOR_WATER },
{ "FLTLAVA1", FLOOR_LAVA },
{ "FLATHUH1", FLOOR_LAVA },
{ "FLTSLUD1", FLOOR_SLUDGE },
{ "END", -1 }
};
mobj_t LavaInflictor;
//----------------------------------------------------------------------------
//
// PROC P_InitLava
//
//----------------------------------------------------------------------------
void P_InitLava(void)
{
memset(&LavaInflictor, 0, sizeof(mobj_t));
LavaInflictor.type = MT_PHOENIXFX2;
LavaInflictor.flags2 = MF2_FIREDAMAGE|MF2_NODMGTHRUST;
}
//----------------------------------------------------------------------------
//
// PROC P_InitTerrainTypes
//
//----------------------------------------------------------------------------
void P_InitTerrainTypes(void)
{
int i;
int lump;
int size;
size = (numflats+1)*sizeof(int);
TerrainTypes = Z_Malloc(size, PU_STATIC, 0);
memset(TerrainTypes, 0, size);
for(i = 0; TerrainTypeDefs[i].type != -1; i++)
{
lump = W_CheckNumForName(TerrainTypeDefs[i].name);
if(lump != -1)
{
TerrainTypes[lump-firstflat] = TerrainTypeDefs[i].type;
}
}
}
//----------------------------------------------------------------------------
//
// PROC P_InitPicAnims
//
//----------------------------------------------------------------------------
void P_InitPicAnims(void)
{
int i;
lastanim = anims;
for(i = 0; animdefs[i].istexture != -1; i++)
{
if(animdefs[i].istexture)
{ // Texture animation
if(R_CheckTextureNumForName(animdefs[i].startname) == -1)
{ // Texture doesn't exist
continue;
}
lastanim->picnum = R_TextureNumForName(animdefs[i].endname);
lastanim->basepic = R_TextureNumForName(animdefs[i].startname);
}
else
{ // Flat animation
if(W_CheckNumForName(animdefs[i].startname) == -1)
{ // Flat doesn't exist
continue;
}
lastanim->picnum = R_FlatNumForName(animdefs[i].endname);
lastanim->basepic = R_FlatNumForName(animdefs[i].startname);
}
lastanim->istexture = animdefs[i].istexture;
lastanim->numpics = lastanim->picnum-lastanim->basepic+1;
if(lastanim->numpics < 2)
{
I_Error("P_InitPicAnims: bad cycle from %s to %s",
animdefs[i].startname, animdefs[i].endname);
}
lastanim->speed = animdefs[i].speed;
lastanim++;
}
}
/*
==============================================================================
UTILITIES
==============================================================================
*/
//
// Will return a side_t* given the number of the current sector,
// the line number, and the side (0/1) that you want.
//
side_t *getSide(int currentSector,int line, int side)
{
return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
}
//
// Will return a sector_t* given the number of the current sector,
// the line number and the side (0/1) that you want.
//
sector_t *getSector(int currentSector,int line,int side)
{
return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
}
//
// Given the sector number and the line number, will tell you whether
// the line is two-sided or not.
//
int twoSided(int sector,int line)
{
return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
}
//==================================================================
//
// Return sector_t * of sector next to current. NULL if not two-sided line
//
//==================================================================
sector_t *getNextSector(line_t *line,sector_t *sec)
{
if (!(line->flags & ML_TWOSIDED))
return NULL;
if (line->frontsector == sec)
return line->backsector;
return line->frontsector;
}
//==================================================================
//
// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
//
//==================================================================
fixed_t P_FindLowestFloorSurrounding(sector_t *sec)
{
int i;
line_t *check;
sector_t *other;
fixed_t floor = sec->floorheight;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->floorheight < floor)
floor = other->floorheight;
}
return floor;
}
//==================================================================
//
// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
//
//==================================================================
fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
{
int i;
line_t *check;
sector_t *other;
fixed_t floor = -500*FRACUNIT;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->floorheight > floor)
floor = other->floorheight;
}
return floor;
}
//==================================================================
//
// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
//
//==================================================================
fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight)
{
int i;
int h;
int min;
line_t *check;
sector_t *other;
fixed_t height = currentheight;
fixed_t heightlist[20]; // 20 adjoining sectors max!
for (i =0,h = 0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->floorheight > height)
heightlist[h++] = other->floorheight;
}
//
// Find lowest height in list
//
min = heightlist[0];
for (i = 1;i < h;i++)
if (heightlist[i] < min)
min = heightlist[i];
return min;
}
//==================================================================
//
// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
//
//==================================================================
fixed_t P_FindLowestCeilingSurrounding(sector_t *sec)
{
int i;
line_t *check;
sector_t *other;
fixed_t height = MAXINT;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->ceilingheight < height)
height = other->ceilingheight;
}
return height;
}
//==================================================================
//
// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
//
//==================================================================
fixed_t P_FindHighestCeilingSurrounding(sector_t *sec)
{
int i;
line_t *check;
sector_t *other;
fixed_t height = 0;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->ceilingheight > height)
height = other->ceilingheight;
}
return height;
}
//==================================================================
//
// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
//
//==================================================================
int P_FindSectorFromLineTag(line_t *line,int start)
{
int i;
for (i=start+1;i<numsectors;i++)
if (sectors[i].tag == line->tag)
return i;
return -1;
}
//==================================================================
//
// Find minimum light from an adjacent sector
//
//==================================================================
int P_FindMinSurroundingLight(sector_t *sector,int max)
{
int i;
int min;
line_t *line;
sector_t *check;
min = max;
for (i=0 ; i < sector->linecount ; i++)
{
line = sector->lines[i];
check = getNextSector(line,sector);
if (!check)
continue;
if (check->lightlevel < min)
min = check->lightlevel;
}
return min;
}
/*
==============================================================================
EVENTS
Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
==============================================================================
*/
/*
===============================================================================
=
= P_CrossSpecialLine - TRIGGER
=
= Called every time a thing origin is about to cross
= a line with a non 0 special
=
===============================================================================
*/
void P_CrossSpecialLine(int linenum, int side, mobj_t *thing)
{
line_t *line;
line = &lines[linenum];
if(!thing->player)
{ // Check if trigger allowed by non-player mobj
switch(line->special)
{
case 39: // Trigger_TELEPORT
case 97: // Retrigger_TELEPORT
case 4: // Trigger_Raise_Door
//case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER
//case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER
break;
default:
return;
break;
}
}
switch(line->special)
{
//====================================================
// TRIGGERS
//====================================================
case 2: // Open Door
EV_DoDoor(line,open,VDOORSPEED);
line->special = 0;
break;
case 3: // Close Door
EV_DoDoor(line,close,VDOORSPEED);
line->special = 0;
break;
case 4: // Raise Door
EV_DoDoor(line,normal,VDOORSPEED);
line->special = 0;
break;
case 5: // Raise Floor
EV_DoFloor(line,raiseFloor);
line->special = 0;
break;
case 6: // Fast Ceiling Crush & Raise
EV_DoCeiling(line,fastCrushAndRaise);
line->special = 0;
break;
case 8: // Trigger_Build_Stairs (8 pixel steps)
EV_BuildStairs(line, 8*FRACUNIT);
line->special = 0;
break;
case 106: // Trigger_Build_Stairs_16 (16 pixel steps)
EV_BuildStairs(line, 16*FRACUNIT);
line->special = 0;
break;
case 10: // PlatDownWaitUp
EV_DoPlat(line,downWaitUpStay,0);
line->special = 0;
break;
case 12: // Light Turn On - brightest near
EV_LightTurnOn(line,0);
line->special = 0;
break;
case 13: // Light Turn On 255
EV_LightTurnOn(line,255);
line->special = 0;
break;
case 16: // Close Door 30
EV_DoDoor(line,close30ThenOpen,VDOORSPEED);
line->special = 0;
break;
case 17: // Start Light Strobing
EV_StartLightStrobing(line);
line->special = 0;
break;
case 19: // Lower Floor
EV_DoFloor(line,lowerFloor);
line->special = 0;
break;
case 22: // Raise floor to nearest height and change texture
EV_DoPlat(line,raiseToNearestAndChange,0);
line->special = 0;
break;
case 25: // Ceiling Crush and Raise
EV_DoCeiling(line,crushAndRaise);
line->special = 0;
break;
case 30: // Raise floor to shortest texture height
// on either side of lines
EV_DoFloor(line,raiseToTexture);
line->special = 0;
break;
case 35: // Lights Very Dark
EV_LightTurnOn(line,35);
line->special = 0;
break;
case 36: // Lower Floor (TURBO)
EV_DoFloor(line,turboLower);
line->special = 0;
break;
case 37: // LowerAndChange
EV_DoFloor(line,lowerAndChange);
line->special = 0;
break;
case 38: // Lower Floor To Lowest
EV_DoFloor( line, lowerFloorToLowest );
line->special = 0;
break;
case 39: // TELEPORT!
EV_Teleport( line, side, thing );
line->special = 0;
break;
case 40: // RaiseCeilingLowerFloor
EV_DoCeiling( line, raiseToHighest );
EV_DoFloor( line, lowerFloorToLowest );
line->special = 0;
break;
case 44: // Ceiling Crush
EV_DoCeiling( line, lowerAndCrush );
line->special = 0;
break;
case 52: // EXIT!
G_ExitLevel ();
line->special = 0;
break;
case 53: // Perpetual Platform Raise
EV_DoPlat(line,perpetualRaise,0);
line->special = 0;
break;
case 54: // Platform Stop
EV_StopPlat(line);
line->special = 0;
break;
case 56: // Raise Floor Crush
EV_DoFloor(line,raiseFloorCrush);
line->special = 0;
break;
case 57: // Ceiling Crush Stop
EV_CeilingCrushStop(line);
line->special = 0;
break;
case 58: // Raise Floor 24
EV_DoFloor(line,raiseFloor24);
line->special = 0;
break;
case 59: // Raise Floor 24 And Change
EV_DoFloor(line,raiseFloor24AndChange);
line->special = 0;
break;
case 104: // Turn lights off in sector(tag)
EV_TurnTagLightsOff(line);
line->special = 0;
break;
case 105: // Trigger_SecretExit
G_SecretExitLevel();
line->special = 0;
break;
//====================================================
// RE-DOABLE TRIGGERS
//====================================================
case 72: // Ceiling Crush
EV_DoCeiling( line, lowerAndCrush );
break;
case 73: // Ceiling Crush and Raise
EV_DoCeiling(line,crushAndRaise);
break;
case 74: // Ceiling Crush Stop
EV_CeilingCrushStop(line);
break;
case 75: // Close Door
EV_DoDoor(line,close,VDOORSPEED);
break;
case 76: // Close Door 30
EV_DoDoor(line,close30ThenOpen,VDOORSPEED);
break;
case 77: // Fast Ceiling Crush & Raise
EV_DoCeiling(line,fastCrushAndRaise);
break;
case 79: // Lights Very Dark
EV_LightTurnOn(line,35);
break;
case 80: // Light Turn On - brightest near
EV_LightTurnOn(line,0);
break;
case 81: // Light Turn On 255
EV_LightTurnOn(line,255);
break;
case 82: // Lower Floor To Lowest
EV_DoFloor( line, lowerFloorToLowest );
break;
case 83: // Lower Floor
EV_DoFloor(line,lowerFloor);
break;
case 84: // LowerAndChange
EV_DoFloor(line,lowerAndChange);
break;
case 86: // Open Door
EV_DoDoor(line,open,VDOORSPEED);
break;
case 87: // Perpetual Platform Raise
EV_DoPlat(line,perpetualRaise,0);
break;
case 88: // PlatDownWaitUp
EV_DoPlat(line,downWaitUpStay,0);
break;
case 89: // Platform Stop
EV_StopPlat(line);
break;
case 90: // Raise Door
EV_DoDoor(line,normal,VDOORSPEED);
break;
case 100: // Retrigger_Raise_Door_Turbo
EV_DoDoor(line, normal, VDOORSPEED*3);
break;
case 91: // Raise Floor
EV_DoFloor(line,raiseFloor);
break;
case 92: // Raise Floor 24
EV_DoFloor(line,raiseFloor24);
break;
case 93: // Raise Floor 24 And Change
EV_DoFloor(line,raiseFloor24AndChange);
break;
case 94: // Raise Floor Crush
EV_DoFloor(line,raiseFloorCrush);
break;
case 95: // Raise floor to nearest height and change texture
EV_DoPlat(line,raiseToNearestAndChange,0);
break;
case 96: // Raise floor to shortest texture height
// on either side of lines
EV_DoFloor(line,raiseToTexture);
break;
case 97: // TELEPORT!
EV_Teleport( line, side, thing );
break;
case 98: // Lower Floor (TURBO)
EV_DoFloor(line,turboLower);
break;
}
}
//----------------------------------------------------------------------------
//
// PROC P_ShootSpecialLine
//
// Called when a thing shoots a special line.
//
//----------------------------------------------------------------------------
void P_ShootSpecialLine(mobj_t *thing, line_t *line)
{
if(!thing->player)
{ // Check if trigger allowed by non-player mobj
switch(line->special)
{
case 46: // Impact_OpenDoor
break;
default:
return;
break;
}
}
switch(line->special)
{
case 24: // Impact_RaiseFloor
EV_DoFloor(line, raiseFloor);
P_ChangeSwitchTexture(line, 0);
break;
case 46: // Impact_OpenDoor
EV_DoDoor(line, open, VDOORSPEED);
P_ChangeSwitchTexture(line, 1);
break;
case 47: // Impact_RaiseFloorNear&Change
EV_DoPlat(line, raiseToNearestAndChange, 0);
P_ChangeSwitchTexture(line, 0);
break;
}
}
//----------------------------------------------------------------------------
//
// PROC P_PlayerInSpecialSector
//
// Called every tic frame that the player origin is in a special sector.
//
//----------------------------------------------------------------------------
void P_PlayerInSpecialSector(player_t *player)
{
sector_t *sector;
static int pushTab[5] = {
2048*5,
2048*10,
2048*25,
2048*30,
2048*35
};
sector = player->mo->subsector->sector;
if(player->mo->z != sector->floorheight)
{ // Player is not touching the floor
return;
}
switch(sector->special)
{
case 7: // Damage_Sludge
if(!(leveltime&31))
{
P_DamageMobj(player->mo, NULL, NULL, 4);
}
break;
case 5: // Damage_LavaWimpy
if(!(leveltime&15))
{
P_DamageMobj(player->mo, &LavaInflictor, NULL, 5);
P_HitFloor(player->mo);
}
break;
case 16: // Damage_LavaHefty
if(!(leveltime&15))
{
P_DamageMobj(player->mo, &LavaInflictor, NULL, 8);
P_HitFloor(player->mo);
}
break;
case 4: // Scroll_EastLavaDamage
P_Thrust(player, 0, 2048*28);
if(!(leveltime&15))
{
P_DamageMobj(player->mo, &LavaInflictor, NULL, 5);
P_HitFloor(player->mo);
}
break;
case 9: // SecretArea
player->secretcount++;
sector->special = 0;
break;
case 11: // Exit_SuperDamage (DOOM E1M8 finale)
/*
player->cheats &= ~CF_GODMODE;
if(!(leveltime&0x1f))
{
P_DamageMobj(player->mo, NULL, NULL, 20);
}
if(player->health <= 10)
{
G_ExitLevel();
}
*/
break;
case 25: case 26: case 27: case 28: case 29: // Scroll_North
P_Thrust(player, ANG90, pushTab[sector->special-25]);
break;
case 20: case 21: case 22: case 23: case 24: // Scroll_East
P_Thrust(player, 0, pushTab[sector->special-20]);
break;
case 30: case 31: case 32: case 33: case 34: // Scroll_South
P_Thrust(player, ANG270, pushTab[sector->special-30]);
break;
case 35: case 36: case 37: case 38: case 39: // Scroll_West
P_Thrust(player, ANG180, pushTab[sector->special-35]);
break;
case 40: case 41: case 42: case 43: case 44: case 45:
case 46: case 47: case 48: case 49: case 50: case 51:
// Wind specials are handled in (P_mobj):P_XYMovement
break;
case 15: // Friction_Low
// Only used in (P_mobj):P_XYMovement and (P_user):P_Thrust
break;
default:
I_Error("P_PlayerInSpecialSector: "
"unknown special %i", sector->special);
}
}
//----------------------------------------------------------------------------
//
// PROC P_UpdateSpecials
//
// Animate planes, scroll walls, etc.
//
//----------------------------------------------------------------------------
void P_UpdateSpecials(void)
{
int i;
int pic;
anim_t *anim;
line_t *line;
// Animate flats and textures
for(anim = anims; anim < lastanim; anim++)
{
for(i = anim->basepic; i < anim->basepic+anim->numpics; i++)
{
pic = anim->basepic+((leveltime/anim->speed+i)%anim->numpics);
if(anim->istexture)
{
texturetranslation[i] = pic;
}
else
{
flattranslation[i] = pic;
}
}
}
// Update scrolling texture offsets
for(i = 0; i < numlinespecials; i++)
{
line = linespeciallist[i];
switch(line->special)
{
case 48: // Effect_Scroll_Left
sides[line->sidenum[0]].textureoffset += FRACUNIT;
break;
case 99: // Effect_Scroll_Right
sides[line->sidenum[0]].textureoffset -= FRACUNIT;
break;
}
}
// Handle buttons
for(i = 0; i < MAXBUTTONS; i++)
{
if(buttonlist[i].btimer)
{
buttonlist[i].btimer--;
if(!buttonlist[i].btimer)
{
switch(buttonlist[i].where)
{
case top:
sides[buttonlist[i].line->sidenum[0]].toptexture =
buttonlist[i].btexture;
break;
case middle:
sides[buttonlist[i].line->sidenum[0]].midtexture =
buttonlist[i].btexture;
break;
case bottom:
sides[buttonlist[i].line->sidenum[0]].bottomtexture =
buttonlist[i].btexture;
break;
}
S_StartSound((mobj_t *)&buttonlist[i].soundorg, sfx_switch);
memset(&buttonlist[i], 0, sizeof(button_t));
}
}
}
}
//============================================================
//
// Special Stuff that can't be categorized
//
//============================================================
int EV_DoDonut(line_t *line)
{
sector_t *s1;
sector_t *s2;
sector_t *s3;
int secnum;
int rtn;
int i;
floormove_t *floor;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
s1 = §ors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (s1->specialdata)
continue;
rtn = 1;
s2 = getNextSector(s1->lines[0],s1);
for (i = 0;i < s2->linecount;i++)
{
if ((!s2->lines[i]->flags & ML_TWOSIDED) ||
(s2->lines[i]->backsector == s1))
continue;
s3 = s2->lines[i]->backsector;
//
// Spawn rising slime
//
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
s2->specialdata = floor;
floor->thinker.function = T_MoveFloor;
floor->type = donutRaise;
floor->crush = false;
floor->direction = 1;
floor->sector = s2;
floor->speed = FLOORSPEED / 2;
floor->texture = s3->floorpic;
floor->newspecial = 0;
floor->floordestheight = s3->floorheight;
//
// Spawn lowering donut-hole
//
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
s1->specialdata = floor;
floor->thinker.function = T_MoveFloor;
floor->type = lowerFloor;
floor->crush = false;
floor->direction = -1;
floor->sector = s1;
floor->speed = FLOORSPEED / 2;
floor->floordestheight = s3->floorheight;
break;
}
}
return rtn;
}
/*
==============================================================================
SPECIAL SPAWNING
==============================================================================
*/
/*
================================================================================
= P_SpawnSpecials
=
= After the map has been loaded, scan for specials that
= spawn thinkers
=
===============================================================================
*/
short numlinespecials;
line_t *linespeciallist[MAXLINEANIMS];
void P_SpawnSpecials (void)
{
sector_t *sector;
int i;
int episode;
episode = 1;
if (W_CheckNumForName("texture2") >= 0)
episode = 2;
//
// Init special SECTORs
//
sector = sectors;
for (i=0 ; i<numsectors ; i++, sector++)
{
if (!sector->special)
continue;
switch (sector->special)
{
case 1: // FLICKERING LIGHTS
P_SpawnLightFlash (sector);
break;
case 2: // STROBE FAST
P_SpawnStrobeFlash(sector,FASTDARK,0);
break;
case 3: // STROBE SLOW
P_SpawnStrobeFlash(sector,SLOWDARK,0);
break;
case 4: // STROBE FAST/DEATH SLIME
P_SpawnStrobeFlash(sector,FASTDARK,0);
sector->special = 4;
break;
case 8: // GLOWING LIGHT
P_SpawnGlowingLight(sector);
break;
case 9: // SECRET SECTOR
totalsecret++;
break;
case 10: // DOOR CLOSE IN 30 SECONDS
P_SpawnDoorCloseIn30 (sector);
break;
case 12: // SYNC STROBE SLOW
P_SpawnStrobeFlash (sector, SLOWDARK, 1);
break;
case 13: // SYNC STROBE FAST
P_SpawnStrobeFlash (sector, FASTDARK, 1);
break;
case 14: // DOOR RAISE IN 5 MINUTES
P_SpawnDoorRaiseIn5Mins (sector, i);
break;
}
}
//
// Init line EFFECTs
//
numlinespecials = 0;
for (i = 0;i < numlines; i++)
switch(lines[i].special)
{
case 48: // Effect_Scroll_Left
case 99: // Effect_Scroll_Right
linespeciallist[numlinespecials] = &lines[i];
numlinespecials++;
break;
}
//
// Init other misc stuff
//
for (i = 0;i < MAXCEILINGS;i++)
activeceilings[i] = NULL;
for (i = 0;i < MAXPLATS;i++)
activeplats[i] = NULL;
for (i = 0;i < MAXBUTTONS;i++)
memset(&buttonlist[i],0,sizeof(button_t));
}
//----------------------------------------------------------------------------
//
// PROC P_InitAmbientSound
//
//----------------------------------------------------------------------------
void P_InitAmbientSound(void)
{
AmbSfxCount = 0;
AmbSfxVolume = 0;
AmbSfxTics = 10*TICSPERSEC;
AmbSfxPtr = AmbSndSeqInit;
}
//----------------------------------------------------------------------------
//
// PROC P_AddAmbientSfx
//
// Called by (P_mobj):P_SpawnMapThing during (P_setup):P_SetupLevel.
//
//----------------------------------------------------------------------------
void P_AddAmbientSfx(int sequence)
{
if(AmbSfxCount == MAX_AMBIENT_SFX)
{
I_Error("Too many ambient sound sequences");
}
LevelAmbientSfx[AmbSfxCount++] = AmbientSfx[sequence];
}
//----------------------------------------------------------------------------
//
// PROC P_AmbientSound
//
// Called every tic by (P_tick):P_Ticker.
//
//----------------------------------------------------------------------------
void P_AmbientSound(void)
{
afxcmd_t cmd;
int sound;
boolean done;
if(!AmbSfxCount)
{ // No ambient sound sequences on current level
return;
}
if(--AmbSfxTics)
{
return;
}
done = false;
do
{
cmd = *AmbSfxPtr++;
switch(cmd)
{
case afxcmd_play:
AmbSfxVolume = P_Random()>>2;
S_StartSoundAtVolume(NULL, *AmbSfxPtr++, AmbSfxVolume);
break;
case afxcmd_playabsvol:
sound = *AmbSfxPtr++;
AmbSfxVolume = *AmbSfxPtr++;
S_StartSoundAtVolume(NULL, sound, AmbSfxVolume);
break;
case afxcmd_playrelvol:
sound = *AmbSfxPtr++;
AmbSfxVolume += *AmbSfxPtr++;
if(AmbSfxVolume < 0)
{
AmbSfxVolume = 0;
}
else if(AmbSfxVolume > 127)
{
AmbSfxVolume = 127;
}
S_StartSoundAtVolume(NULL, sound, AmbSfxVolume);
break;
case afxcmd_delay:
AmbSfxTics = *AmbSfxPtr++;
done = true;
break;
case afxcmd_delayrand:
AmbSfxTics = P_Random()&(*AmbSfxPtr++);
done = true;
break;
case afxcmd_end:
AmbSfxTics = 6*TICSPERSEC+P_Random();
AmbSfxPtr = LevelAmbientSfx[P_Random()%AmbSfxCount];
done = true;
break;
default:
I_Error("P_AmbientSound: Unknown afxcmd %d", cmd);
break;
}
} while(done == false);
}