diff --git a/source/core/namedef_custom.h b/source/core/namedef_custom.h index feb9521a2..788297313 100644 --- a/source/core/namedef_custom.h +++ b/source/core/namedef_custom.h @@ -10,3 +10,6 @@ xx(MultiMenu) xx(RazeStatusBar) xx(zoomsize) xx(AltHud) + +// internal Duke actor classes that need direct checking +xx(DukeMasterSwitch) diff --git a/source/games/duke/src/actors.cpp b/source/games/duke/src/actors.cpp index 908092848..6f2a8fa7c 100644 --- a/source/games/duke/src/actors.cpp +++ b/source/games/duke/src/actors.cpp @@ -673,59 +673,6 @@ void detonate(DDukeActor *actor, int explosion) // //--------------------------------------------------------------------------- -void movemasterswitch(DDukeActor *actor) -{ - if (actor->spr.yint == 1) - { - actor->spr.hitag--; - if (actor->spr.hitag <= 0) - { - operatesectors(actor->sector(), actor); - - DukeSectIterator it(actor->sector()); - while (auto effector = it.Next()) - { - if (effector->spr.statnum == STAT_EFFECTOR) - { - switch (effector->spr.lotag) - { - case SE_2_EARTHQUAKE: - case SE_21_DROP_FLOOR: - case SE_31_FLOOR_RISE_FALL: - case SE_32_CEILING_RISE_FALL: - case SE_36_PROJ_SHOOTER: - effector->temp_data[0] = 1; - break; - case SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT: - effector->temp_data[4] = 1; - break; - } - } - else if (effector->spr.statnum == STAT_STANDABLE) - { - if (actorflag(effector, SFLAG2_BRIGHTEXPLODE)) // _SEENINE_ and _OOZFILTER_ - { - effector->spr.shade = -31; - } - } - } - // we cannot delete this because it may be used as a sound source. - // This originally depended on undefined behavior as the deleted sprite was still used for the sound - // with no checking if it got reused in the mean time. - actor->spr.picnum = 0; // give it a picnum without any behavior attached, just in case - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat2 |= CSTAT2_SPRITE_NOFIND; - ChangeActorStat(actor, STAT_REMOVED); - } - } -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - void movetrash(DDukeActor *actor) { if (actor->vel.X == 0) actor->vel.X = 1 / 16.; @@ -1530,7 +1477,7 @@ void reactor(DDukeActor* const actor, int REACTOR, int REACTOR2, int REACTORBURN DukeStatIterator it(STAT_STANDABLE); while (auto a2 = it.Next()) { - if (a2->spr.picnum == MASTERSWITCH) + if (ismasterswitch(a2)) if (a2->spr.hitag == actor->spr.hitag) if (a2->spr.yint == 0) a2->spr.yint = 1; diff --git a/source/games/duke/src/actors_d.cpp b/source/games/duke/src/actors_d.cpp index 26e97d7b0..82ac6db6d 100644 --- a/source/games/duke/src/actors_d.cpp +++ b/source/games/duke/src/actors_d.cpp @@ -945,11 +945,6 @@ void movestandables_d(void) continue; } - else if (picnum == MASTERSWITCH) - { - movemasterswitch(act); - } - else if (picnum == VIEWSCREEN || picnum == VIEWSCREEN2) { moveviewscreen(act); diff --git a/source/games/duke/src/actors_r.cpp b/source/games/duke/src/actors_r.cpp index a8ba65f00..df86a28da 100644 --- a/source/games/duke/src/actors_r.cpp +++ b/source/games/duke/src/actors_r.cpp @@ -793,11 +793,6 @@ void movestandables_r(void) continue; } - else if (picnum == MASTERSWITCH) - { - movemasterswitch(act); - } - else if (picnum == TRASH) { movetrash(act); diff --git a/source/games/duke/src/funct.h b/source/games/duke/src/funct.h index 8d96ae3b9..e9d1b0695 100644 --- a/source/games/duke/src/funct.h +++ b/source/games/duke/src/funct.h @@ -32,7 +32,6 @@ void movefta(); void clearcameras(int i, player_struct* p); void RANDOMSCRAP(DDukeActor* i); void detonate(DDukeActor* i, int explosion); -void movemasterswitch(DDukeActor* i); void movetrash(DDukeActor* i); void movewaterdrip(DDukeActor* i, int drip); void movedoorshock(DDukeActor* i); diff --git a/source/games/duke/src/inlines.h b/source/games/duke/src/inlines.h index 3bf6bd643..8b198cdf9 100644 --- a/source/games/duke/src/inlines.h +++ b/source/games/duke/src/inlines.h @@ -11,6 +11,13 @@ inline int rnd(int X) return ((krand() >> 8) >= (255 - (X))); } +// internal controller classes can be directly checked for by type +inline int ismasterswitch(DDukeActor* actor) +{ + // The STAT_REMOVED check here is important! + return actor->GetClass()->TypeName == NAME_DukeMasterSwitch && actor->spr.statnum != STAT_REMOVED; +} + inline int badguypic(int const tileNum) { return ((gs.actorinfo[tileNum].flags & (SFLAG_INTERNAL_BADGUY | SFLAG_BADGUY)) != 0); diff --git a/source/games/duke/src/premap.cpp b/source/games/duke/src/premap.cpp index d48ad20aa..53f73ab2e 100644 --- a/source/games/duke/src/premap.cpp +++ b/source/games/duke/src/premap.cpp @@ -50,7 +50,6 @@ void premapcontroller(DDukeActor* ac) case ACTIVATOR: case ACTIVATORLOCKED: case LOCATORS: - case MASTERSWITCH: case MUSICANDSFX: case RESPAWN: case SECTOREFFECTOR: @@ -965,6 +964,12 @@ static TArray spawnactors(SpawnSpriteDef& sprites) spawns.Pop(); continue; } + if (i == 210) + { + int a = 0; + } + + auto sprt = &sprites.sprites[i]; auto info = spawnMap.CheckKey(sprt->picnum); auto actor = static_cast(InsertActor(info? info->Class() : RUNTIME_CLASS(DDukeActor), sprt->sectp, sprt->statnum)); diff --git a/source/games/duke/src/sectors.cpp b/source/games/duke/src/sectors.cpp index 5efaafe42..f37bc2e24 100644 --- a/source/games/duke/src/sectors.cpp +++ b/source/games/duke/src/sectors.cpp @@ -1201,7 +1201,7 @@ void operatemasterswitches(int low) DukeStatIterator it(STAT_STANDABLE); while (auto act2 = it.Next()) { - if (act2->spr.picnum == MASTERSWITCH && act2->spr.lotag == low && act2->spr.yint == 0) + if (ismasterswitch(act2) && act2->spr.lotag == low && act2->spr.yint == 0) act2->spr.yint = 1; } } diff --git a/source/games/duke/src/sectors_d.cpp b/source/games/duke/src/sectors_d.cpp index 0882b9a05..f92baff92 100644 --- a/source/games/duke/src/sectors_d.cpp +++ b/source/games/duke/src/sectors_d.cpp @@ -1731,7 +1731,7 @@ void checksectors_d(int snum) DukeSectIterator it(near.hitSector); while (auto act = it.Next()) { - if (act->spr.picnum == ACTIVATOR || act->spr.picnum == MASTERSWITCH) + if (act->spr.picnum == ACTIVATOR || ismasterswitch(act)) return; } operatesectors(near.hitSector, p->GetActor()); @@ -1743,7 +1743,7 @@ void checksectors_d(int snum) DukeSectIterator it(p->GetActor()->sector()); while (auto act = it.Next()) { - if (act->spr.picnum == ACTIVATOR || act->spr.picnum == MASTERSWITCH) return; + if (act->spr.picnum == ACTIVATOR || ismasterswitch(act)) return; } operatesectors(p->GetActor()->sector(), p->GetActor()); } diff --git a/source/games/duke/src/sectors_r.cpp b/source/games/duke/src/sectors_r.cpp index 024530fa6..3b5547283 100644 --- a/source/games/duke/src/sectors_r.cpp +++ b/source/games/duke/src/sectors_r.cpp @@ -2668,7 +2668,7 @@ void checksectors_r(int snum) DukeSectIterator it(near.hitSector); while (auto act = it.Next()) { - if (act->spr.picnum == ACTIVATOR || act->spr.picnum == MASTERSWITCH) + if (act->spr.picnum == ACTIVATOR || ismasterswitch(act)) return; } if (haskey(near.hitSector, snum)) @@ -2689,7 +2689,7 @@ void checksectors_r(int snum) DukeSectIterator it(p->GetActor()->sector()); while (auto act = it.Next()) { - if (act->spr.picnum == ACTIVATOR || act->spr.picnum == MASTERSWITCH) + if (act->spr.picnum == ACTIVATOR || ismasterswitch(act)) return; } if (haskey(near.hitSector, snum)) diff --git a/source/games/duke/src/spawn_r.cpp b/source/games/duke/src/spawn_r.cpp index f05a8343b..cb996e083 100644 --- a/source/games/duke/src/spawn_r.cpp +++ b/source/games/duke/src/spawn_r.cpp @@ -704,12 +704,7 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray* case BOLT1 + 1: case BOLT1 + 2: case BOLT1 + 3: - act->temp_pos.X = act->spr.scale.X; - act->temp_pos.Y = act->spr.scale.Y; - [[fallthrough]]; - case MASTERSWITCH: - if (act->spr.picnum == MASTERSWITCH) - act->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + act->temp_pos.XY() = act->spr.scale; act->spr.yint = 0; ChangeActorStat(act, STAT_STANDABLE); break; diff --git a/source/games/duke/src/vmexports.cpp b/source/games/duke/src/vmexports.cpp index 1b2b0767e..f935661ff 100644 --- a/source/games/duke/src/vmexports.cpp +++ b/source/games/duke/src/vmexports.cpp @@ -357,6 +357,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, checkhitdefault, DukeActor_checkhitdef return 0; } +void DukeActor_operatesectors(DDukeActor* origin, sectortype* sector) +{ + operatesectors(sector, origin); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, operatesectors, DukeActor_operatesectors) +{ + PARAM_SELF_PROLOGUE(DDukeActor); + PARAM_POINTER(sec, sectortype); + operatesectors(sec, self); + return 0; +} + // temporary helpers to hide the fact that these flags are not part of the actor yet. DEFINE_ACTION_FUNCTION(DDukeActor, actorflag1) { diff --git a/wadsrc/static/filter/duke/engine/engine.def b/wadsrc/static/filter/duke/engine/engine.def index f0ae6ce9e..9e1a33a69 100644 --- a/wadsrc/static/filter/duke/engine/engine.def +++ b/wadsrc/static/filter/duke/engine/engine.def @@ -1,5 +1,7 @@ spawnclasses { + 8 = DukeMasterSwitch + 1221 = DukeCranePole 1222 = DukeCrane 563 = DukeWaterFountain diff --git a/wadsrc/static/filter/redneck/engine/engine.def b/wadsrc/static/filter/redneck/engine/engine.def index 45f87c031..2e222e189 100644 --- a/wadsrc/static/filter/redneck/engine/engine.def +++ b/wadsrc/static/filter/redneck/engine/engine.def @@ -1,5 +1,7 @@ spawnclasses { + 8 = DukeMasterSwitch + 1298 = DukeCranePole 1299 = DukeCrane 1092 = DukeWaterFountain diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 28c128d7b..2f290cb5c 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -50,6 +50,7 @@ version "4.10" #include "zscript/games/duke/ui/screens.zs" #include "zscript/games/duke/ui/cutscenes.zs" #include "zscript/games/duke/ui/menu.zs" +#include "zscript/games/duke/actors/masterswitch.zs" #include "zscript/games/duke/actors/crane.zs" #include "zscript/games/duke/actors/waterfountain.zs" #include "zscript/games/duke/actors/flammables.zs" diff --git a/wadsrc/static/zscript/coreactor.zs b/wadsrc/static/zscript/coreactor.zs index f49638ca3..b6df8935e 100644 --- a/wadsrc/static/zscript/coreactor.zs +++ b/wadsrc/static/zscript/coreactor.zs @@ -6,6 +6,7 @@ enum EClipMask }; const MAXPLAYERS = 8; +const MAXSTATUS = 1024; class CoreActor native { @@ -54,4 +55,3 @@ class CoreActor native native void setPosition(Vector3 pos); native void setPositionZ(Vector3 pos); } - diff --git a/wadsrc/static/zscript/games/duke/actors/masterswitch.zs b/wadsrc/static/zscript/games/duke/actors/masterswitch.zs new file mode 100644 index 000000000..e51aa0909 --- /dev/null +++ b/wadsrc/static/zscript/games/duke/actors/masterswitch.zs @@ -0,0 +1,60 @@ +class DukeMasterSwitch : DukeActor +{ + default + { + statnum STAT_STANDABLE; + } + + override void Initialize() + { + self.cstat = CSTAT_SPRITE_INVISIBLE; + self.yint = 0; + } + + override void Tick() + { + if (self.yint == 1 && self.statnum == STAT_STANDABLE) + { + self.hitag--; + if (self.hitag <= 0) + { + self.operatesectors(self.sector); + + DukeSectIterator it; + for (let effector = it.First(self.sector); effector; effector = it.Next()) + { + if (effector.statnum == STAT_EFFECTOR) + { + // Todo: Once the effectors have been ported, do this with a virtual that can be overridden by custom effects. + switch (effector.lotag) + { + case SE_2_EARTHQUAKE: + case SE_21_DROP_FLOOR: + case SE_31_FLOOR_RISE_FALL: + case SE_32_CEILING_RISE_FALL: + case SE_36_PROJ_SHOOTER: + effector.temp_data[0] = 1; + break; + case SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT: + effector.temp_data[4] = 1; + break; + } + } + else //if (effector.statnum == STAT_STANDABLE) this check is not really needed. + { + if (effector.actorflag2(SFLAG2_BRIGHTEXPLODE)) // SEENINE and OOZFILTER + { + effector.shade = -31; + } + } + } + // we cannot delete this actor because it may be used as a sound source. + // This originally depended on undefined behavior as the deleted sprite was still used for the sound + // with no checking if it got reused in the mean time. + self.cstat |= CSTAT_SPRITE_INVISIBLE; + self.cstat2 |= CSTAT2_SPRITE_NOFIND; + self.ChangeStat(STAT_REMOVED); + } + } + } +} diff --git a/wadsrc/static/zscript/games/duke/dukeactor.zs b/wadsrc/static/zscript/games/duke/dukeactor.zs index 62a11b225..11c7e5c42 100644 --- a/wadsrc/static/zscript/games/duke/dukeactor.zs +++ b/wadsrc/static/zscript/games/duke/dukeactor.zs @@ -1,3 +1,55 @@ +// sector effector lotags. Preferably these should be eliminated once SE's get converted to classes. Until then we still need these. +enum EEffectorTypes +{ + SE_0_ROTATING_SECTOR = 0, + SE_1_PIVOT = 1, + SE_2_EARTHQUAKE = 2, + SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT = 3, + SE_4_RANDOM_LIGHTS = 4, + SE_5_BOSS = 5, + SE_6_SUBWAY = 6, + + SE_7_TELEPORT = 7, + SE_8_UP_OPEN_DOOR_LIGHTS = 8, + SE_9_DOWN_OPEN_DOOR_LIGHTS = 9, + SE_10_DOOR_AUTO_CLOSE = 10, + SE_11_SWINGING_DOOR = 11, + SE_12_LIGHT_SWITCH = 12, + SE_13_EXPLOSIVE = 13, + SE_14_SUBWAY_CAR = 14, + SE_15_SLIDING_DOOR = 15, + SE_16_REACTOR = 16, + SE_17_WARP_ELEVATOR = 17, + SE_18_INCREMENTAL_SECTOR_RISE_FALL = 18, + SE_19_EXPLOSION_LOWERS_CEILING = 19, + SE_20_STRETCH_BRIDGE = 20, + SE_21_DROP_FLOOR = 21, + SE_22_TEETH_DOOR = 22, + SE_23_ONE_WAY_TELEPORT = 23, + SE_24_CONVEYOR = 24, + SE_25_PISTON = 25, + SE_26 = 26, + SE_27_DEMO_CAM = 27, + SE_28_LIGHTNING = 28, + SE_29_WAVES = 29, + SE_30_TWO_WAY_TRAIN = 30, + SE_31_FLOOR_RISE_FALL = 31, + SE_32_CEILING_RISE_FALL = 32, + SE_33_QUAKE_DEBRIS = 33, + SE_34 = 34, + SE_35 = 35, + SE_36_PROJ_SHOOTER = 36, + SE_47_LIGHT_SWITCH = 47, + SE_48_LIGHT_SWITCH = 48, + SE_49_POINT_LIGHT = 49, + SE_50_SPOT_LIGHT = 50, + SE_128_GLASS_BREAKING = 128, + SE_130 = 130, + SE_131 = 131, + SE_156_CONVEYOR_NOSCROLL = 156, +}; + + class DukeActor : CoreActor native { enum EStatnums @@ -21,6 +73,9 @@ class DukeActor : CoreActor native STAT_DESTRUCT = 100, STAT_BOWLING = 105, + + STAT_REMOVED = MAXSTATUS-2, + }; native void SetSpritesetImage(int index); @@ -78,6 +133,7 @@ class DukeActor : CoreActor native native void makeitfall(); native void detonate(name type); native void checkhitdefault(DukeActor proj); + native void operatesectors(sectortype sec); virtual void BeginPlay() {} virtual void Initialize() {}