- implemented the 3 special switches

That's the developer commentary icon in World Tour, the deactivation switch for the chicken processing plant in RR and one shootable alarm bell in RRRA.
This commit is contained in:
Christoph Oelckers 2022-12-10 23:40:58 +01:00
parent 0d9fe83cba
commit 2386ea9930
18 changed files with 89 additions and 47 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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)
{

View file

@ -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;

View file

@ -129,7 +129,6 @@ extern TArray<DVector2> 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];

View file

@ -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)

View file

@ -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;

View file

@ -518,10 +518,6 @@ void prelevel_r(int g, TArray<DDukeActor*>& 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<DDukeActor*>& 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())

View file

@ -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)

View file

@ -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
{

View file

@ -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)

View file

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

View file

@ -158,5 +158,6 @@ spawnclasses
3795 = DukeActor, "*RRTILE3795"
7505 = DukeActor, "*RRTILE7505"
7506 = DukeActor, "*RRTILE7506"
8860 = RedneckBellSwitch
}

View file

@ -236,6 +236,7 @@ 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"

View file

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

View file

@ -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))

View file

@ -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
}
}
}

View file

@ -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;