/* P_Spec.c */ #include "doomdef.h" #include "p_local.h" #include "soundst.h" #ifdef GL_HERETIC #include "gl_struct.h" extern int *a_iGLTexTranslation; extern int switchlist[MAXSWITCHES * 2]; #endif /* 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 (1) { if (!(line->flags & ML_TWOSIDED)) return NULL; } /* // VR: old code removed, added BOOM - crash in E3M8 still not fixed if (line->frontsector == sec) return line->backsector; */ /* return (line->frontsector == sec) ? line->backsector : line->frontsector; */ if (line->frontsector == sec) { if (line->backsector!=sec) return line->backsector; /* jff: don't retn sec unless compatibility */ else /* fixes an intra-sector line breaking functions */ return NULL; /* like floor->highest floor */ } return line->frontsector; /* 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; } /* * P_FindNextHighestFloor() * * Passed a sector and a floor height, returns the fixed point value * of the smallest floor height in a surrounding sector larger than * the floor height passed. If no such height exists the floorheight * passed is returned. * * Rewritten by Lee Killough to avoid fixed array and to be faster * * VR: This clever Lee's rewrite also fixed bug in Heretic E3M8 */ /* * ================================================================== * * FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS * * ================================================================== */ fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight) { sector_t *other; int i; for (i = 0; i < sec->linecount; i++) { if ((other = getNextSector(sec->lines[i],sec)) && other->floorheight > currentheight) { int height = other->floorheight; while (++i < sec->linecount) { if ((other = getNextSector(sec->lines[i],sec)) && other->floorheight < height && other->floorheight > currentheight) { height = other->floorheight; } } return height; } } return currentheight; } /* * ================================================================== * * 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;itag) 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,dopen,VDOORSPEED); line->special = 0; break; case 3: /* Close Door */ EV_DoDoor(line,dclose,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,dclose,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,dopen,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, dopen, 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); #ifndef GL_HERETIC if(anim->istexture) { texturetranslation[i] = pic; } else { flattranslation[i] = pic; } #else a_iGLTexTranslation[i]=pic; #endif } } /* 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; #ifdef GL_HERETIC fn_vScrollWallTexture(line->iLineID,sides[line->sidenum[0]].textureoffset); #endif break; case 99: /* Effect_Scroll_Right */ sides[line->sidenum[0]].textureoffset -= FRACUNIT; #ifdef GL_HERETIC fn_vScrollWallTexture(line->iLineID,sides[line->sidenum[0]].textureoffset); #endif 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: #ifdef GL_HERETIC sides[buttonlist[i].line->sidenum[0]].toptexture = switchlist[buttonlist[i].btexture]; fn_vUpdateWallTexture(buttonlist[i].line->iLineID,1,buttonlist[i].btexture); #else sides[buttonlist[i].line->sidenum[0]].toptexture = buttonlist[i].btexture; #endif break; case middle: #ifdef GL_HERETIC sides[buttonlist[i].line->sidenum[0]].midtexture = switchlist[buttonlist[i].btexture]; fn_vUpdateWallTexture(buttonlist[i].line->iLineID,0,buttonlist[i].btexture); #else sides[buttonlist[i].line->sidenum[0]].midtexture = buttonlist[i].btexture; #endif break; case bottom: #ifdef GL_HERETIC sides[buttonlist[i].line->sidenum[0]].bottomtexture = switchlist[buttonlist[i].btexture]; fn_vUpdateWallTexture(buttonlist[i].line->iLineID,2,buttonlist[i].btexture); #else sides[buttonlist[i].line->sidenum[0]].bottomtexture = buttonlist[i].btexture; #endif 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.acp1 = (actionf_p1)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.acp1 = (actionf_p1)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 ; ispecial) 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 >> 3); break; case afxcmd_playabsvol: sound = *AmbSfxPtr++; AmbSfxVolume = *AmbSfxPtr++; S_StartSoundAtVolume(NULL, sound, AmbSfxVolume >> 3); break; case afxcmd_playrelvol: sound = *AmbSfxPtr++; AmbSfxVolume += *AmbSfxPtr++; if(AmbSfxVolume < 0) { AmbSfxVolume = 0; } else if(AmbSfxVolume > 127) { AmbSfxVolume = 127; } S_StartSoundAtVolume(NULL, sound, AmbSfxVolume >> 3); 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); }