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); }