From 0df2cb80cf03d7259746834220d209b306a8c503 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 4 Sep 2008 23:15:36 +0000 Subject: Add GPLed Heretic/Hexen source. Subversion-branch: /branches/raven-branch Subversion-revision: 1195 --- src/hexen/p_spec.c | 1152 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1152 insertions(+) create mode 100644 src/hexen/p_spec.c (limited to 'src/hexen/p_spec.c') diff --git a/src/hexen/p_spec.c b/src/hexen/p_spec.c new file mode 100644 index 00000000..b351061a --- /dev/null +++ b/src/hexen/p_spec.c @@ -0,0 +1,1152 @@ + +//************************************************************************** +//** +//** p_spec.c : Heretic 2 : Raven Software, Corp. +//** +//** $RCSfile: p_spec.c,v $ +//** $Revision: 1.67 $ +//** $Date: 96/01/06 18:37:33 $ +//** $Author: bgokey $ +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include "h2def.h" +#include "p_local.h" +#include "soundst.h" + +// MACROS ------------------------------------------------------------------ + +#define MAX_TAGGED_LINES 64 + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static boolean CheckedLockedDoor(mobj_t *mo, byte lock); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +int *TerrainTypes; +struct +{ + char *name; + int type; +} TerrainTypeDefs[] = +{ + { "X_005", FLOOR_WATER }, + { "X_001", FLOOR_LAVA }, + { "X_009", FLOOR_SLUDGE }, + { "F_033", FLOOR_ICE }, + { "END", -1 } +}; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static struct +{ + line_t *line; + int lineTag; +} TaggedLines[MAX_TAGGED_LINES]; +static int TaggedLineCount; + +mobj_t LavaInflictor; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// P_InitLava +// +//========================================================================== + +void P_InitLava(void) +{ + memset(&LavaInflictor, 0, sizeof(mobj_t)); + LavaInflictor.type = MT_CIRCLEFLAME; + LavaInflictor.flags2 = MF2_FIREDAMAGE|MF2_NODMGTHRUST; +} + +//========================================================================== +// +// 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; + } + } +} + +//========================================================================== +// +// getSide +// +// 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] ]; +} +*/ + +//========================================================================== +// +// getSector +// +// 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; +} +*/ + +//========================================================================== +// +// twoSided +// +// 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;iarg1) + return i; + return -1; +} +*/ + +//========================================================================= +// +// P_FindSectorFromTag +// +//========================================================================= + +int P_FindSectorFromTag(int tag, int start) +{ + int i; + + for(i = start+1; i < numsectors; i++) + { + if(sectors[i].tag == 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; +} +*/ + +//========================================================================= +// +// EV_SectorSoundChange +// +//========================================================================= + +boolean EV_SectorSoundChange(byte *args) +{ + int secNum; + boolean rtn; + + if(!args[0]) + { + return false; + } + secNum = -1; + rtn = false; + while((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0) + { + sectors[secNum].seqType = args[1]; + rtn = true; + } + return rtn; +} + +//============================================================================ +// +// CheckedLockedDoor +// +//============================================================================ + +static boolean CheckedLockedDoor(mobj_t *mo, byte lock) +{ + extern char *TextKeyMessages[11]; + char LockedBuffer[80]; + + if(!mo->player) + { + return false; + } + if(!lock) + { + return true; + } + if(!(mo->player->keys&(1<<(lock-1)))) + { + sprintf(LockedBuffer, "YOU NEED THE %s\n", + TextKeyMessages[lock-1]); + P_SetMessage(mo->player, LockedBuffer, true); + S_StartSound(mo, SFX_DOOR_LOCKED); + return false; + } + return true; +} + + +//========================================================================== +// +// EV_LineSearchForPuzzleItem +// +//========================================================================== + +boolean EV_LineSearchForPuzzleItem(line_t *line, byte *args, mobj_t *mo) +{ + player_t *player; + int i; + artitype_t type,arti; + + if (!mo) return false; + player = mo->player; + if (!player) return false; + + // Search player's inventory for puzzle items + for (i=0; iartifactCount; i++) + { + arti = player->inventory[i].type; + type = arti - arti_firstpuzzitem; + if (type < 0) continue; + if (type == line->arg1) + { + // A puzzle item was found for the line + if (P_UseArtifact(player, arti)) + { + // A puzzle item was found for the line + P_PlayerRemoveArtifact(player, i); + if(player == &players[consoleplayer]) + { + if(arti < arti_firstpuzzitem) + { + S_StartSound(NULL, SFX_ARTIFACT_USE); + } + else + { + S_StartSound(NULL, SFX_PUZZLE_SUCCESS); + } + ArtifactFlash = 4; + } + return true; + } + } + } + return false; +} + + + +/* +============================================================================== + + EVENTS + +Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers + +============================================================================== +*/ +//============================================================================ +// +// P_ExecuteLineSpecial +// +//============================================================================ + +boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side, + mobj_t *mo) +{ + boolean buttonSuccess; + + buttonSuccess = false; + switch(special) + { + case 1: // Poly Start Line + break; + case 2: // Poly Rotate Left + buttonSuccess = EV_RotatePoly(line, args, 1, false); + break; + case 3: // Poly Rotate Right + buttonSuccess = EV_RotatePoly(line, args, -1, false); + break; + case 4: // Poly Move + buttonSuccess = EV_MovePoly(line, args, false, false); + break; + case 5: // Poly Explicit Line: Only used in initialization + break; + case 6: // Poly Move Times 8 + buttonSuccess = EV_MovePoly(line, args, true, false); + break; + case 7: // Poly Door Swing + buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING); + break; + case 8: // Poly Door Slide + buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE); + break; + case 10: // Door Close + buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE); + break; + case 11: // Door Open + if(!args[0]) + { + buttonSuccess = EV_VerticalDoor(line, mo); + } + else + { + buttonSuccess = EV_DoDoor(line, args, DREV_OPEN); + } + break; + case 12: // Door Raise + if(!args[0]) + { + buttonSuccess = EV_VerticalDoor(line, mo); + } + else + { + buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL); + } + break; + case 13: // Door Locked_Raise + if(CheckedLockedDoor(mo, args[3])) + { + if(!args[0]) + { + buttonSuccess = EV_VerticalDoor(line, mo); + } + else + { + buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL); + } + } + break; + case 20: // Floor Lower by Value + buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE); + break; + case 21: // Floor Lower to Lowest + buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST); + break; + case 22: // Floor Lower to Nearest + buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR); + break; + case 23: // Floor Raise by Value + buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE); + break; + case 24: // Floor Raise to Highest + buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR); + break; + case 25: // Floor Raise to Nearest + buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST); + break; + case 26: // Stairs Build Down Normal + buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL); + break; + case 27: // Build Stairs Up Normal + buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL); + break; + case 28: // Floor Raise and Crush + buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH); + break; + case 29: // Build Pillar (no crushing) + buttonSuccess = EV_BuildPillar(line, args, false); + break; + case 30: // Open Pillar + buttonSuccess = EV_OpenPillar(line, args); + break; + case 31: // Stairs Build Down Sync + buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC); + break; + case 32: // Build Stairs Up Sync + buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC); + break; + case 35: // Raise Floor by Value Times 8 + buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8); + break; + case 36: // Lower Floor by Value Times 8 + buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8); + break; + case 40: // Ceiling Lower by Value + buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE); + break; + case 41: // Ceiling Raise by Value + buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE); + break; + case 42: // Ceiling Crush and Raise + buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE); + break; + case 43: // Ceiling Lower and Crush + buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH); + break; + case 44: // Ceiling Crush Stop + buttonSuccess = EV_CeilingCrushStop(line, args); + break; + case 45: // Ceiling Crush Raise and Stay + buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY); + break; + case 46: // Floor Crush Stop + buttonSuccess = EV_FloorCrushStop(line, args); + break; + case 60: // Plat Perpetual Raise + buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0); + break; + case 61: // Plat Stop + EV_StopPlat(line, args); + break; + case 62: // Plat Down-Wait-Up-Stay + buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0); + break; + case 63: // Plat Down-by-Value*8-Wait-Up-Stay + buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY, + 0); + break; + case 64: // Plat Up-Wait-Down-Stay + buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0); + break; + case 65: // Plat Up-by-Value*8-Wait-Down-Stay + buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY, + 0); + break; + case 66: // Floor Lower Instant * 8 + buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT); + break; + case 67: // Floor Raise Instant * 8 + buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT); + break; + case 68: // Floor Move to Value * 8 + buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8); + break; + case 69: // Ceiling Move to Value * 8 + buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8); + break; + case 70: // Teleport + if(side == 0) + { // Only teleport when crossing the front side of a line + buttonSuccess = EV_Teleport(args[0], mo, true); + } + break; + case 71: // Teleport, no fog + if(side == 0) + { // Only teleport when crossing the front side of a line + buttonSuccess = EV_Teleport(args[0], mo, false); + } + break; + case 72: // Thrust Mobj + if(!side) // Only thrust on side 0 + { + P_ThrustMobj(mo, args[0]*(ANGLE_90/64), args[1]<player && mo->player->playerstate + == PST_DEAD)) // Players must be alive to teleport + { + G_Completed(args[0], args[1]); + buttonSuccess = true; + } + } + break; + case 75: // Teleport_EndGame + if(side == 0) + { // Only teleport when crossing the front side of a line + if(!(mo && mo->player && mo->player->playerstate + == PST_DEAD)) // Players must be alive to teleport + { + buttonSuccess = true; + if(deathmatch) + { // Winning in deathmatch just goes back to map 1 + G_Completed(1, 0); + } + else + { // Passing -1, -1 to G_Completed() starts the Finale + G_Completed(-1, -1); + } + } + } + break; + case 80: // ACS_Execute + buttonSuccess = + P_StartACS(args[0], args[1], &args[2], mo, line, side); + break; + case 81: // ACS_Suspend + buttonSuccess = P_SuspendACS(args[0], args[1]); + break; + case 82: // ACS_Terminate + buttonSuccess = P_TerminateACS(args[0], args[1]); + break; + case 83: // ACS_LockedExecute + buttonSuccess = P_StartLockedACS(line, args, mo, side); + break; + case 90: // Poly Rotate Left Override + buttonSuccess = EV_RotatePoly(line, args, 1, true); + break; + case 91: // Poly Rotate Right Override + buttonSuccess = EV_RotatePoly(line, args, -1, true); + break; + case 92: // Poly Move Override + buttonSuccess = EV_MovePoly(line, args, false, true); + break; + case 93: // Poly Move Times 8 Override + buttonSuccess = EV_MovePoly(line, args, true, true); + break; + case 94: // Build Pillar Crush + buttonSuccess = EV_BuildPillar(line, args, true); + break; + case 95: // Lower Floor and Ceiling + buttonSuccess = EV_DoFloorAndCeiling(line, args, false); + break; + case 96: // Raise Floor and Ceiling + buttonSuccess = EV_DoFloorAndCeiling(line, args, true); + break; + case 109: // Force Lightning + buttonSuccess = true; + P_ForceLightning(); + break; + case 110: // Light Raise by Value + buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE); + break; + case 111: // Light Lower by Value + buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE); + break; + case 112: // Light Change to Value + buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE); + break; + case 113: // Light Fade + buttonSuccess = EV_SpawnLight(line, args, LITE_FADE); + break; + case 114: // Light Glow + buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW); + break; + case 115: // Light Flicker + buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER); + break; + case 116: // Light Strobe + buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE); + break; + case 120: // Quake Tremor + buttonSuccess = A_LocalQuake(args, mo); + break; + case 129: // UsePuzzleItem + buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo); + break; + case 130: // Thing_Activate + buttonSuccess = EV_ThingActivate(args[0]); + break; + case 131: // Thing_Deactivate + buttonSuccess = EV_ThingDeactivate(args[0]); + break; + case 132: // Thing_Remove + buttonSuccess = EV_ThingRemove(args[0]); + break; + case 133: // Thing_Destroy + buttonSuccess = EV_ThingDestroy(args[0]); + break; + case 134: // Thing_Projectile + buttonSuccess = EV_ThingProjectile(args, 0); + break; + case 135: // Thing_Spawn + buttonSuccess = EV_ThingSpawn(args, 1); + break; + case 136: // Thing_ProjectileGravity + buttonSuccess = EV_ThingProjectile(args, 1); + break; + case 137: // Thing_SpawnNoFog + buttonSuccess = EV_ThingSpawn(args, 0); + break; + case 138: // Floor_Waggle + buttonSuccess = EV_StartFloorWaggle(args[0], args[1], + args[2], args[3], args[4]); + break; + case 140: // Sector_SoundChange + buttonSuccess = EV_SectorSoundChange(args); + break; + + // Line specials only processed during level initialization + // 100: Scroll_Texture_Left + // 101: Scroll_Texture_Right + // 102: Scroll_Texture_Up + // 103: Scroll_Texture_Down + // 121: Line_SetIdentification + + // Inert Line specials + default: + break; + } + return buttonSuccess; +} + +//============================================================================ +// +// P_ActivateLine +// +//============================================================================ + +boolean P_ActivateLine(line_t *line, mobj_t *mo, int side, int activationType) +{ + int lineActivation; + boolean repeat; + boolean buttonSuccess; + + lineActivation = GET_SPAC(line->flags); + if(lineActivation != activationType) + { + return false; + } + if(!mo->player && !(mo->flags&MF_MISSILE)) + { + if(lineActivation != SPAC_MCROSS) + { // currently, monsters can only activate the MCROSS activation type + return false; + } + if(line->flags & ML_SECRET) + return false; // never open secret doors + } + repeat = line->flags&ML_REPEAT_SPECIAL; + buttonSuccess = false; + + buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line, + side, mo); + if(!repeat && buttonSuccess) + { // clear the special on non-retriggerable lines + line->special = 0; + } + if((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT) + && buttonSuccess) + { + P_ChangeSwitchTexture(line, repeat); + } + return true; +} + +//---------------------------------------------------------------------------- +// +// 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[3] = + { + 2048*5, + 2048*10, + 2048*25 + }; + + sector = player->mo->subsector->sector; + if(player->mo->z != sector->floorheight) + { // Player is not touching the floor + return; + } + switch(sector->special) + { + case 9: // SecretArea + player->secretcount++; + sector->special = 0; + break; + + case 201: case 202: case 203: // Scroll_North_xxx + P_Thrust(player, ANG90, pushTab[sector->special-201]); + break; + case 204: case 205: case 206: // Scroll_East_xxx + P_Thrust(player, 0, pushTab[sector->special-204]); + break; + case 207: case 208: case 209: // Scroll_South_xxx + P_Thrust(player, ANG270, pushTab[sector->special-207]); + break; + case 210: case 211: case 212: // Scroll_West_xxx + P_Thrust(player, ANG180, pushTab[sector->special-210]); + break; + case 213: case 214: case 215: // Scroll_NorthWest_xxx + P_Thrust(player, ANG90+ANG45, pushTab[sector->special-213]); + break; + case 216: case 217: case 218: // Scroll_NorthEast_xxx + P_Thrust(player, ANG45, pushTab[sector->special-216]); + break; + case 219: case 220: case 221: // Scroll_SouthEast_xxx + P_Thrust(player, ANG270+ANG45, pushTab[sector->special-219]); + break; + case 222: case 223: case 224: // Scroll_SouthWest_xxx + P_Thrust(player, ANG180+ANG45, pushTab[sector->special-222]); + 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 26: // Stairs_Special1 + case 27: // Stairs_Special2 + // Used in (P_floor):ProcessStairSector + break; + + case 198: // Lightning Special + case 199: // Lightning Flash special + case 200: // Sky2 + // Used in (R_plane):R_Drawplanes + break; + default: + I_Error("P_PlayerInSpecialSector: " + "unknown special %i", sector->special); + } +} + +//============================================================================ +// +// P_PlayerOnSpecialFlat +// +//============================================================================ + +void P_PlayerOnSpecialFlat(player_t *player, int floorType) +{ + if(player->mo->z != player->mo->floorz) + { // Player is not touching the floor + return; + } + switch(floorType) + { + case FLOOR_LAVA: + if(!(leveltime&31)) + { + P_DamageMobj(player->mo, &LavaInflictor, NULL, 10); + S_StartSound(player->mo, SFX_LAVA_SIZZLE); + } + break; + default: + break; + } +} + +//---------------------------------------------------------------------------- +// +// PROC P_UpdateSpecials +// +//---------------------------------------------------------------------------- + +void P_UpdateSpecials(void) +{ + int i; + + // 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((mobj_t *)&buttonlist[i].soundorg, sfx_switch); + memset(&buttonlist[i], 0, sizeof(button_t)); + } + } + } +} + +/* +============================================================================== + + 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; + + // + // Init special SECTORs + // + sector = sectors; + for (i=0 ; ispecial) + continue; + switch (sector->special) + { + case 1: // Phased light + // Hardcoded base, use sector->lightlevel as the index + P_SpawnPhasedLight(sector, 80, -1); + break; + case 2: // Phased light sequence start + P_SpawnLightSequence(sector, 1); + break; + // Specials 3 & 4 are used by the phased light sequences + + /* + 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; + TaggedLineCount = 0; + for(i = 0; i < numlines; i++) + { + switch(lines[i].special) + { + case 100: // Scroll_Texture_Left + case 101: // Scroll_Texture_Right + case 102: // Scroll_Texture_Up + case 103: // Scroll_Texture_Down + linespeciallist[numlinespecials] = &lines[i]; + numlinespecials++; + break; + case 121: // Line_SetIdentification + if(lines[i].arg1) + { + if(TaggedLineCount == MAX_TAGGED_LINES) + { + I_Error("P_SpawnSpecials: MAX_TAGGED_LINES " + "(%d) exceeded.", MAX_TAGGED_LINES); + } + TaggedLines[TaggedLineCount].line = &lines[i]; + TaggedLines[TaggedLineCount++].lineTag + = lines[i].arg1; + } + lines[i].special = 0; + 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)); + + // Initialize flat and texture animations + P_InitFTAnims(); +} + +//========================================================================== +// +// P_FindLine +// +//========================================================================== + +line_t *P_FindLine(int lineTag, int *searchPosition) +{ + int i; + + for(i = *searchPosition+1; i < TaggedLineCount; i++) + { + if(TaggedLines[i].lineTag == lineTag) + { + *searchPosition = i; + return TaggedLines[i].line; + } + } + *searchPosition = -1; + return NULL; +} -- cgit v1.2.3