diff --git a/source/games/duke/src/constants.h b/source/games/duke/src/constants.h index 5ffc6d580..fe804e1d7 100644 --- a/source/games/duke/src/constants.h +++ b/source/games/duke/src/constants.h @@ -415,7 +415,7 @@ DEFINE_TFLAGS_OPERATORS(EDukeFlags3) // these get stored as user flags inside the texture manager. enum { - TFLAG_WALLSWITCH = 1 << 0, + TFLAG_WALLSWITCH = 1 << 0, // fake switches, actually... TFLAG_ADULT = 1 << 1, TFLAG_CLEARINVENTORY = 1 << 2, // really dumb Duke stuff... TFLAG_DOORWALL = 1 << 3, diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h index ecf393201..96d3c7f86 100644 --- a/source/games/duke/src/duke3d.h +++ b/source/games/duke/src/duke3d.h @@ -125,6 +125,7 @@ void CallStaticSetup(DDukeActor* actor); void CallPlayFTASound(DDukeActor* actor); void CallStandingOn(DDukeActor* actor, player_struct* p); void CallRunState(DDukeActor* actor); +bool CallTriggerSwitch(DDukeActor* actor, player_struct* p); extern FTextureID mirrortex, foftex; diff --git a/source/games/duke/src/game.cpp b/source/games/duke/src/game.cpp index 13b97375e..0f499ae1a 100644 --- a/source/games/duke/src/game.cpp +++ b/source/games/duke/src/game.cpp @@ -79,7 +79,6 @@ size_t DDukeActor::PropagateMark() static void markgcroots() { GC::Mark(camsprite); - GC::Mark(BellSprite); GC::MarkArray(spriteq, 1024); GC::Mark(currentCommentarySprite); GC::Mark(ud.cameraactor); @@ -561,6 +560,18 @@ void CallStandingOn(DDukeActor* actor, player_struct* p) } } +bool CallTriggerSwitch(DDukeActor* actor, player_struct* p) +{ + int nval = false; + IFVIRTUALPTR(actor, DDukeActor, TriggerSwitch) + { + VMReturn ret(&nval); + VMValue val[] = { actor, p }; + VMCall(func, val, 2, &ret, 1); + } + return nval; +} + CCMD(changewalltexture) { diff --git a/source/games/duke/src/global.cpp b/source/games/duke/src/global.cpp index d1b7ec87c..189a9a90b 100644 --- a/source/games/duke/src/global.cpp +++ b/source/games/duke/src/global.cpp @@ -65,7 +65,6 @@ int ufocnt; // UFO spawn count int hulkspawn; // Spawn a hulk? int lastlevel; // Set at the end of RRRA's E2L7. short fakebubba_spawn, mamaspawn_count, banjosound; // RRRA special effects -short BellTime; int WindTime; DAngle WindDir; uint8_t enemysizecheat /*raat607*/, pistonsound, chickenphase /* raat605*/, RRRA_ExitedLevel, fogactive; diff --git a/source/games/duke/src/global.h b/source/games/duke/src/global.h index 7c6744976..3b7e8d921 100644 --- a/source/games/duke/src/global.h +++ b/source/games/duke/src/global.h @@ -129,7 +129,6 @@ extern TArray mspos; extern int WindTime; extern DAngle WindDir; extern short fakebubba_spawn, mamaspawn_count, banjosound; -extern short BellTime; extern uint8_t enemysizecheat /*raat607*/, pistonsound, chickenphase /* raat605*/, RRRA_ExitedLevel, fogactive; extern uint32_t everyothertime; extern player_orig po[MAXPLAYERS]; diff --git a/source/games/duke/src/player_r.cpp b/source/games/duke/src/player_r.cpp index 81c56dfba..b5cbd4ec2 100644 --- a/source/games/duke/src/player_r.cpp +++ b/source/games/duke/src/player_r.cpp @@ -1154,12 +1154,6 @@ int doincrements_r(player_struct* p) WindDir = randomAngle(); } - if (BellTime > 0) - { - BellTime--; - if (BellTime == 0 && BellSprite) - BellSprite->spr.picnum++; - } if (chickenphase > 0) chickenphase--; if (p->SeaSick) diff --git a/source/games/duke/src/premap.cpp b/source/games/duke/src/premap.cpp index 77230886c..9d82f4adb 100644 --- a/source/games/duke/src/premap.cpp +++ b/source/games/duke/src/premap.cpp @@ -427,8 +427,6 @@ void resetprestat(int snum,int g) WindDir = nullAngle; fakebubba_spawn = 0; RRRA_ExitedLevel = 0; - BellTime = 0; - BellSprite = nullptr; if(p->curr_weapon == HANDREMOTE_WEAPON) { @@ -661,8 +659,6 @@ void prelevel_common(int g) fakebubba_spawn = 0; RRRA_ExitedLevel = 0; mamaspawn_count = currentLevel->rr_mamaspawn; - BellTime = 0; - BellSprite = nullptr; // RRRA E2L1 fog handling. fogactive = 0; diff --git a/source/games/duke/src/premap_r.cpp b/source/games/duke/src/premap_r.cpp index b47a6fe9d..d26454d8f 100644 --- a/source/games/duke/src/premap_r.cpp +++ b/source/games/duke/src/premap_r.cpp @@ -518,10 +518,6 @@ void prelevel_r(int g, TArray& actors) { ps[0].Exit = ac->spr.pos.XY(); } - else if (ac->spr.picnum == RTILE_CHICKENPLANTBUTTON) - { - ud.chickenplant = 1; - } else { premapcontroller(ac); @@ -612,8 +608,6 @@ void prelevel_r(int g, TArray& actors) case RTILE_POWERSWITCH1ON: case RTILE_LOCKSWITCH1ON: case RTILE_POWERSWITCH2ON: - case RTILE_CHICKENPLANTBUTTON: - case RTILE_CHICKENPLANTBUTTONON: j = lotags.Find(ac->spr.lotag); if (j == lotags.Size()) diff --git a/source/games/duke/src/savegame.cpp b/source/games/duke/src/savegame.cpp index 63f9c4586..893c50fdb 100644 --- a/source/games/duke/src/savegame.cpp +++ b/source/games/duke/src/savegame.cpp @@ -428,8 +428,6 @@ void GameInterface::SerializeGameState(FSerializer& arc) ("fakebubba_spawn", fakebubba_spawn) ("mamaspawn_count", mamaspawn_count) ("banjosound", banjosound) - ("belltime", BellTime) - ("bellsprite", BellSprite) ("enemysizecheat", enemysizecheat) ("pistonsound", pistonsound) ("chickenphase", chickenphase) diff --git a/source/games/duke/src/sectors_d.cpp b/source/games/duke/src/sectors_d.cpp index e6600d0ed..9da3ee716 100644 --- a/source/games/duke/src/sectors_d.cpp +++ b/source/games/duke/src/sectors_d.cpp @@ -223,6 +223,9 @@ bool checkhitswitch_d(int snum, walltype* wwal, DDukeActor *act) spos = act->spr.pos.XY(); picnum = act->spr.picnum; switchpal = act->spr.pal; + + // custom switches that maintain themselves can immediately abort. + if (CallTriggerSwitch(act, &ps[snum])) return true; } else { diff --git a/source/games/duke/src/sectors_r.cpp b/source/games/duke/src/sectors_r.cpp index bd894833e..aa2e2af8b 100644 --- a/source/games/duke/src/sectors_r.cpp +++ b/source/games/duke/src/sectors_r.cpp @@ -193,6 +193,9 @@ bool checkhitswitch_r(int snum, walltype* wwal, DDukeActor* act) pos = act->spr.pos.XY(); picnum = act->spr.picnum; switchpal = act->spr.pal; + + // custom switches that maintain themselves can immediately abort. + if (CallTriggerSwitch(act, &ps[snum])) return true; } else { @@ -258,8 +261,6 @@ bool checkhitswitch_r(int snum, walltype* wwal, DDukeActor* act) case RTILE_LOCKSWITCH1ON: case RTILE_POWERSWITCH2: case RTILE_POWERSWITCH2ON: - case RTILE_CHICKENPLANTBUTTON: - case RTILE_CHICKENPLANTBUTTONON: case RTILE_CONTESTSWITCH: case RTILE_ALERTSWITCH: case RTILE_ALERTSWITCHON: @@ -331,7 +332,6 @@ bool checkhitswitch_r(int snum, walltype* wwal, DDukeActor* act) case RTILE_PULLSWITCH: case RTILE_DIPSWITCH2: case RTILE_DIPSWITCH3: - case RTILE_CHICKENPLANTBUTTON: case RTILE_ALERTSWITCH: case RTILE_HANDLESWITCH: if (other->spr.picnum == RTILE_DIPSWITCH3) @@ -345,13 +345,6 @@ bool checkhitswitch_r(int snum, walltype* wwal, DDukeActor* act) other->spr.picnum++; break; } - if (other->spr.picnum == RTILE_CHICKENPLANTBUTTON) - ud.chickenplant = 0; - if (other->spr.picnum == RTILE_BELLSWITCH) - { - BellTime = 132; - BellSprite = other; - } other->spr.picnum++; break; case RTILE_PULLSWITCHON: @@ -367,11 +360,8 @@ bool checkhitswitch_r(int snum, walltype* wwal, DDukeActor* act) case RTILE_FRANKENSTINESWITCHON: case RTILE_DIPSWITCH2ON: case RTILE_DIPSWITCH3ON: - case RTILE_CHICKENPLANTBUTTONON: case RTILE_ALERTSWITCHON: case RTILE_HANDLESWITCHON: - if (other->spr.picnum == RTILE_CHICKENPLANTBUTTONON) - ud.chickenplant = 1; if (other->spr.hitag != 999) other->spr.picnum--; break; @@ -538,13 +528,7 @@ bool checkhitswitch_r(int snum, walltype* wwal, DDukeActor* act) goOn2: if (isRRRA()) { - if (picnum == RTILE_BELLSWITCH && act) - { - BellTime = 132; - BellSprite = act; - act->spr.picnum++; - } - else if (picnum == RTILE_IRONWHEELSWITCH) + if (picnum == RTILE_IRONWHEELSWITCH) { act->spr.picnum = act->spr.picnum + 1; if (hitag == 10001) diff --git a/source/games/duke/src/spawn.cpp b/source/games/duke/src/spawn.cpp index f32401815..2903f4343 100644 --- a/source/games/duke/src/spawn.cpp +++ b/source/games/duke/src/spawn.cpp @@ -195,8 +195,18 @@ bool initspriteforspawn(DDukeActor* act) act->temp_pos = DVector3(0, 0, 0); auto ext = GetExtInfo(act->spr.spritetexture()); + bool overrideswitch = false; - if (act->spr.cstat & CSTAT_SPRITE_ALIGNMENT_WALL && (wallswitchcheck(act) || ext.switchindex > 0)) + // The STAT_FALLER code below would render any switch actor inoperable so we must also include everything that overrides TriggerSwitch, + // even if it got no other hint for being a switch. A bit dirty but it makes it unnecessary to explicitly mark such switches. + + IFVIRTUALPTR(act, DDukeActor, TriggerSwitch) + { + if (func->PrintableName.CompareNoCase("DukeActor.TriggerSwitch") != 0) + overrideswitch = true; + } + + if (act->spr.cstat & CSTAT_SPRITE_ALIGNMENT_WALL && (wallswitchcheck(act) || ext.switchindex > 0 || overrideswitch)) { // this is a bit more complicated than needed thanks to some bugs in the original code that must be retained for the multiplayer filter. // Not all switches were properly included here. @@ -214,7 +224,7 @@ bool initspriteforspawn(DDukeActor* act) act->spr.pal = 0; } act->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL; - return false; + return true; } diff --git a/wadsrc/static/filter/redneck.ridesagain/rmapinfo.spawnclasses b/wadsrc/static/filter/redneck.ridesagain/rmapinfo.spawnclasses index 0500be6f6..053a8ea5b 100644 --- a/wadsrc/static/filter/redneck.ridesagain/rmapinfo.spawnclasses +++ b/wadsrc/static/filter/redneck.ridesagain/rmapinfo.spawnclasses @@ -158,5 +158,6 @@ spawnclasses 3795 = DukeActor, "*RRTILE3795" 7505 = DukeActor, "*RRTILE7505" 7506 = DukeActor, "*RRTILE7506" + 8860 = RedneckBellSwitch } diff --git a/wadsrc/static/filter/redneck/rmapinfo.spawnclasses b/wadsrc/static/filter/redneck/rmapinfo.spawnclasses index bbc88ce66..dae0b8098 100644 --- a/wadsrc/static/filter/redneck/rmapinfo.spawnclasses +++ b/wadsrc/static/filter/redneck/rmapinfo.spawnclasses @@ -236,7 +236,8 @@ spawnclasses 2654 = DukeGenericDestructible, "RRTILE2654", "", "GLASS_BREAKING", spawnglass 2656 = DukeGenericDestructible, "RRTILE2656", "", "GLASS_BREAKING", spawnglass 3172 = DukeGenericDestructible, "RRTILE3172", "", "GLASS_BREAKING", spawnglass - + 94 = RedneckChickenPlantButton + 1878 = DukeActor, "*RRTILE1878" 1952 = DukeActor, "*RRTILE1952" 1953 = DukeActor, "*RRTILE1953" diff --git a/wadsrc/static/zscript/games/duke/actors/chickenplant.zs b/wadsrc/static/zscript/games/duke/actors/chickenplant.zs index 4d3103e22..a290ebbc9 100644 --- a/wadsrc/static/zscript/games/duke/actors/chickenplant.zs +++ b/wadsrc/static/zscript/games/duke/actors/chickenplant.zs @@ -389,3 +389,23 @@ class RedneckChickenHead : DukeActor } } +class RedneckChickenplantButton : DukeActor +{ + default + { + spriteset "CHICKENPLANTBUTTON", "CHICKENPLANTBUTTONON"; + } + + override void Initialize() + { + ud.chickenplant = 1; + } + + override bool TriggerSwitch(DukePlayer activator) + { + ud.chickenplant = self.spritesetindex; + self.setSpriteSetImage(1 - self.spritesetindex); + self.PlayActorSound("SWITCH_ON"); + return true; + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/games/duke/actors/dukemisc.zs b/wadsrc/static/zscript/games/duke/actors/dukemisc.zs index d7c5b0ebd..276b25a85 100644 --- a/wadsrc/static/zscript/games/duke/actors/dukemisc.zs +++ b/wadsrc/static/zscript/games/duke/actors/dukemisc.zs @@ -190,9 +190,9 @@ class DeveloperCommentary : DukeActor spriteset "DEVELOPERCOMMENTARY", "DEVELOPERCOMMENTARYON"; } - override bool OnUse(DukePlayer p) + override bool TriggerSwitch(DukePlayer p) { - if (!wt_commentary) return false; + if (!wt_commentary) return true; if (self.spriteSetIndex == 0) { if (Duke.StartCommentary(self.lotag, self)) diff --git a/wadsrc/static/zscript/games/duke/actors/redneckmisc.zs b/wadsrc/static/zscript/games/duke/actors/redneckmisc.zs index 1c552f966..63f43faf7 100644 --- a/wadsrc/static/zscript/games/duke/actors/redneckmisc.zs +++ b/wadsrc/static/zscript/games/duke/actors/redneckmisc.zs @@ -70,3 +70,33 @@ class RedneckPopcorn : DukeActor pic "POPCORN"; } } + + +class RedneckBellSwitch : DukeActor +{ + default + { + spriteset "BELLSWITCH", "BELLSWITCHON", "BELLSWITCHOFF"; + } + + override bool TriggerSwitch(DukePlayer activator) + { + if (self.spritesetindex == 1 || dlevel.check_activator_motion(lotag)) return true; + + self.detail = 132; + self.setSpriteSetImage(1); + self.changeStat(STAT_MISC); // needs to be made to call Tick + return false; // still needs to act as a switch. + } + + override void Tick() + { + if (self.detail > 0) + { + self.detail--; + if (self.detail == 0) + self.SetSpritesetImage(2); // stop animating + } + } +} + diff --git a/wadsrc/static/zscript/games/duke/dukeactor.zs b/wadsrc/static/zscript/games/duke/dukeactor.zs index c1d25b8b0..7e8cf73cb 100644 --- a/wadsrc/static/zscript/games/duke/dukeactor.zs +++ b/wadsrc/static/zscript/games/duke/dukeactor.zs @@ -198,6 +198,7 @@ class DukeActor : CoreActor native virtual void RunState() {} // this is the CON function. virtual void PlayFTASound() {} virtual void StandingOn(DukePlayer p) {} + virtual bool TriggerSwitch(DukePlayer activator) { return false; } virtual bool shootthis(DukeActor actor, DukePlayer p, Vector3 pos, double ang) const // this gets called on the defaults. { return false;