ref: 3191e80bf7fda36bf0c951b0363cd52fa6ceac6b
dir: /p_spec.c/
// P_Spec.c
// HEADER FILES ------------------------------------------------------------
#include "h2stdinc.h"
#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;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
anim_t anims[MAXANIMS];
anim_t *lastanim;
int *TerrainTypes;
mobj_t LavaInflictor;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static int *LevelAmbientSfx[MAX_AMBIENT_SFX];
static int *AmbSfxPtr;
static int AmbSfxCount;
static int AmbSfxTics;
static int AmbSfxVolume;
static int AmbSndSeqInit[] =
{ /* Startup */
afxcmd_end
};
static int AmbSndSeq1[] =
{ /* Scream */
afxcmd_play, sfx_amb1,
afxcmd_end
};
static int AmbSndSeq2[] =
{ /* Squish */
afxcmd_play, sfx_amb2,
afxcmd_end
};
static 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
};
static 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
};
static 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
};
static 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
};
static int AmbSndSeq7[] =
{ /* Growl */
afxcmd_play, sfx_bstsit,
afxcmd_end
};
static int AmbSndSeq8[] =
{ /* Magic */
afxcmd_play, sfx_amb8,
afxcmd_end
};
static 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
};
static 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
};
static int *AmbientSfx[] =
{
AmbSndSeq1, /* Scream */
AmbSndSeq2, /* Squish */
AmbSndSeq3, /* Drops */
AmbSndSeq4, /* SlowFootsteps */
AmbSndSeq5, /* Heartbeat */
AmbSndSeq6, /* Bells */
AmbSndSeq7, /* Growl */
AmbSndSeq8, /* Magic */
AmbSndSeq9, /* Laughter */
AmbSndSeq10 /* FastFootsteps */
};
static 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 }
};
static struct
{
const char *name;
int type;
} TerrainTypeDefs[] =
{
{ "FLTWAWA1", FLOOR_WATER },
{ "FLTFLWW1", FLOOR_WATER },
{ "FLTLAVA1", FLOOR_LAVA },
{ "FLATHUH1", FLOOR_LAVA },
{ "FLTSLUD1", FLOOR_SLUDGE },
{ "END", -1 }
};
// CODE --------------------------------------------------------------------
//----------------------------------------------------------------------------
//
// 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 = (int *) Z_Malloc(size, PU_STATIC, NULL);
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
//
//==================================================================
#define MAX_ADJOINING_SECTORS 20 /* 20 adjoining sectors max! */
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[MAX_ADJOINING_SECTORS];
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;
if (h >= MAX_ADJOINING_SECTORS)
{
fprintf(stderr, "Sector with more than %d adjoining sectors\n",
MAX_ADJOINING_SECTORS);
break;
}
}
//
// Find lowest height in list
//
if(!h)
return currentheight;
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 = H2MAXINT;
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;
}
}
switch (line->special)
{
//====================================================
// TRIGGERS
//====================================================
case 2: // Open Door
EV_DoDoor(line, vldoor_open, VDOORSPEED);
line->special = 0;
break;
case 3: // Close Door
EV_DoDoor(line, vldoor_close, VDOORSPEED);
line->special = 0;
break;
case 4: // Raise Door
EV_DoDoor(line, vldoor_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, vldoor_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, vldoor_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, vldoor_normal, VDOORSPEED);
break;
case 100: // Retrigger_Raise_Door_Turbo
EV_DoDoor(line, vldoor_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;
}
}
switch (line->special)
{
case 24: // Impact_RaiseFloor
EV_DoFloor(line, raiseFloor);
P_ChangeSwitchTexture(line, 0);
break;
case 46: // Impact_OpenDoor
EV_DoDoor(line, vldoor_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 swtch_top:
sides[buttonlist[i].line->sidenum[0]].toptexture =
buttonlist[i].btexture;
break;
case swtch_middle:
sides[buttonlist[i].line->sidenum[0]].midtexture =
buttonlist[i].btexture;
break;
case swtch_bottom:
sides[buttonlist[i].line->sidenum[0]].bottomtexture =
buttonlist[i].btexture;
break;
}
S_StartSound(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 = (floormove_t *) Z_Malloc (sizeof(*floor), PU_LEVSPEC, NULL);
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 = (floormove_t *) Z_Malloc (sizeof(*floor), PU_LEVSPEC, NULL);
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;
#if 0
int episode = 1;
if (W_CheckNumForName("texture2") >= 0)
episode = 2;
#endif
//
// 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);
}