diff --git a/source/core/defparser.cpp b/source/core/defparser.cpp index 7e61c31ed..bdc618d7b 100644 --- a/source/core/defparser.cpp +++ b/source/core/defparser.cpp @@ -2351,6 +2351,47 @@ static void parseTileFlags(FScanner& sc, FScriptPosition& pos) sc.SetCMode(false); } +static void parseBreakWall(FScanner& sc, FScriptPosition& pos) +{ + int basetile; + int breaktile; + FName sound; + VMFunction* handler = nullptr; + + sc.SetCMode(true); + sc.MustGetString(); + basetile = TileFiles.tileForName(sc.String); + sc.MustGetStringName(","); + sc.MustGetString(); + breaktile = TileFiles.tileForName(sc.String); + sc.MustGetStringName(","); + sc.MustGetString(); + sound = sc.String; + if (sc.CheckString(",")) + { + sc.MustGetString(); + + size_t p = strcspn(sc.String, "."); + if (p == 0) + { + sc.ScriptMessage("Call to undefined function %s", sc.String); + return; + } + + FString clsname(sc.String, p); + FString funcname = sc.String + p + 1; + handler = PClass::FindFunction(clsname, funcname); + if (handler == nullptr) + sc.ScriptMessage("Call to undefined function %s", sc.String); + + // todo: validate the function's signature. Must be (walltype, TextureID, Sound, DukeActor) + + } + breakWallMap.Insert(basetile, { breaktile, sound, handler }); + sc.SetCMode(false); +} + + //=========================================================================== // // @@ -2445,6 +2486,7 @@ static const dispatch basetokens[] = { "spawnclasses", parseSpawnClasses }, { "tileflag", parseTileFlags }, + { "breakwall", parseBreakWall }, { nullptr, nullptr }, }; diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h index 6fb3b910e..ffdbcf88a 100644 --- a/source/core/gamecontrol.h +++ b/source/core/gamecontrol.h @@ -294,3 +294,12 @@ struct SpawnRec }; using SpawnMap = TMap<int, SpawnRec>; inline SpawnMap spawnMap; + +struct BreakWallRec +{ + int brokentex; + FName breaksound; + VMFunction* handler; +}; +using BreakWallMap = TMap<int, BreakWallRec>; +inline BreakWallMap breakWallMap; diff --git a/source/core/vmexports.cpp b/source/core/vmexports.cpp index 3198205e1..61366ddbf 100644 --- a/source/core/vmexports.cpp +++ b/source/core/vmexports.cpp @@ -478,8 +478,9 @@ int sector_checktexture(sectortype* sec, int place, int intname) if (!sec) ThrowAbortException(X_READ_NIL, nullptr); int tilenum = TileFiles.tileForName(FName(ENamedName(intname)).GetChars()); - return tilenum == place ? sec->ceilingpicnum : sec->floorpicnum; + return tilenum == (place == 0 ? sec->ceilingpicnum : sec->floorpicnum); } + DEFINE_ACTION_FUNCTION_NATIVE(_sectortype, checktexture, sector_checktexture) { PARAM_SELF_STRUCT_PROLOGUE(sectortype); @@ -488,11 +489,26 @@ DEFINE_ACTION_FUNCTION_NATIVE(_sectortype, checktexture, sector_checktexture) ACTION_RETURN_BOOL(sector_checktexture(self, place, name)); } -void sector_settexture(sectortype* sec, int place, int intname) +void sector_settexturename(sectortype* sec, int place, int intname) { if (!sec) ThrowAbortException(X_READ_NIL, nullptr); int tilenum = TileFiles.tileForName(FName(ENamedName(intname)).GetChars()); - (place ? sec->ceilingpicnum : sec->floorpicnum) = tilenum; + (place == 0 ? sec->ceilingpicnum : sec->floorpicnum) = tilenum; +} +DEFINE_ACTION_FUNCTION_NATIVE(_sectortype, settexturename, sector_settexturename) +{ + PARAM_SELF_STRUCT_PROLOGUE(sectortype); + PARAM_INT(place); + PARAM_INT(name); + sector_settexturename(self, place, name); + return 0; +} + +// This is declared as TextureID but for now receives a tilenum +void sector_settexture(sectortype* sec, int place, int tilenum) +{ + if (!sec) ThrowAbortException(X_READ_NIL, nullptr); + (place == 0 ? sec->ceilingpicnum : sec->floorpicnum) = tilenum; } DEFINE_ACTION_FUNCTION_NATIVE(_sectortype, settexture, sector_settexture) { @@ -701,6 +717,37 @@ DEFINE_ACTION_FUNCTION_NATIVE(_walltype, twosided, wall_twosided) ACTION_RETURN_BOOL(self->twoSided()); } +void wall_settexturename(walltype* sec, int place, int intname) +{ + if (!sec) ThrowAbortException(X_READ_NIL, nullptr); + int tilenum = TileFiles.tileForName(FName(ENamedName(intname)).GetChars()); + (place ? sec->overpicnum : sec->picnum) = tilenum; +} +DEFINE_ACTION_FUNCTION_NATIVE(_walltype, settexturename, wall_settexturename) +{ + PARAM_SELF_STRUCT_PROLOGUE(walltype); + PARAM_INT(place); + PARAM_INT(name); + wall_settexturename(self, place, name); + return 0; +} + +// This is declared as TextureID but for now receives a tilenum +void wall_settexture(walltype* sec, int place, int tilenum) +{ + if (!sec) ThrowAbortException(X_READ_NIL, nullptr); + (place ? sec->overpicnum : sec->picnum) = tilenum; +} +DEFINE_ACTION_FUNCTION_NATIVE(_walltype, settexture, wall_settexture) +{ + PARAM_SELF_STRUCT_PROLOGUE(walltype); + PARAM_INT(place); + PARAM_INT(name); + wall_settexture(self, place, name); + return 0; +} + + //============================================================================= void tspritetype_setSpritePic(tspritetype* targ, DCoreActor* self, unsigned z) diff --git a/source/games/duke/src/game.cpp b/source/games/duke/src/game.cpp index 4a0297968..493c08963 100644 --- a/source/games/duke/src/game.cpp +++ b/source/games/duke/src/game.cpp @@ -538,4 +538,18 @@ void CallStandingOn(DDukeActor* actor, player_struct* p) } +CCMD(changewalltexture) +{ + if (argv.argc() < 2) return; + int tile = TileFiles.tileForName(argv[1]); + if (tile < 0) tile = (int)strtol(argv[1], nullptr, 10); + HitInfoBase hit; + hitscan(ps[0].actor->spr.pos, ps[0].cursector, DVector3(ps[0].actor->spr.Angles.Yaw.ToVector(), 0) * 1024, hit, CLIPMASK1); + if (hit.hitWall) + { + hit.hitWall->picnum = tile; + } +} + + END_DUKE_NS diff --git a/source/games/duke/src/player_r.cpp b/source/games/duke/src/player_r.cpp index 00db10530..411bea16d 100644 --- a/source/games/duke/src/player_r.cpp +++ b/source/games/duke/src/player_r.cpp @@ -316,7 +316,7 @@ static void shootweapon(DDukeActor* actor, int p, DVector3 pos, DAngle ang, int if (hit.actor()) { - if (hit.actor()->spr.picnum == 1930) + if (hit.actor()->spr.picnum == TORNADO) return; fi.checkhitsprite(hit.actor(), spark); if (hit.actor()->isPlayer() && (ud.coop != 1 || ud.ffire == 1)) @@ -459,7 +459,7 @@ static void shootstuff(DDukeActor* actor, int p, DVector3 pos, DAngle ang, int a scount = 1; if (atwith == SHITBALL) { - if (actor->spr.picnum == 8705) + if (actor->spr.picnum == MAMA) vel = 37.5; else vel = 25; @@ -476,7 +476,7 @@ static void shootstuff(DDukeActor* actor, int p, DVector3 pos, DAngle ang, int a { vel = 52.5; pos.Z -= 4; - if (actor->spr.picnum == 4649) + if (actor->spr.picnum == HULK) { pos += (actor->spr.Angles.Yaw + DAngle45).ToVector() * 16; pos.Z += 12; diff --git a/source/games/duke/src/sectors_r.cpp b/source/games/duke/src/sectors_r.cpp index ac9c2c215..50fa8e186 100644 --- a/source/games/duke/src/sectors_r.cpp +++ b/source/games/duke/src/sectors_r.cpp @@ -33,6 +33,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms #include "mapinfo.h" #include "dukeactor.h" #include "secrets.h" +#include "vm.h" // PRIMITIVE BEGIN_DUKE_NS @@ -869,7 +870,21 @@ void checkhitwall_r(DDukeActor* spr, walltype* wal, const DVector3& pos, int atw } } - switch (wal->picnum) + auto data = breakWallMap.CheckKey(wal->picnum); + if (data) + { + if (!data->handler) + { + wal->picnum = data->brokentex; + S_PlayActorSound(S_FindSound(data->breaksound.GetChars()), spr); + } + else + { + VMValue args[4] = { wal, data->brokentex, S_FindSound(data->breaksound.GetChars()).index(), spr }; + VMCall(data->handler, args, 4, nullptr, 0); + } + } + else switch (wal->picnum) { case IRONWHEELSWITCH: if (isRRRA()) break; @@ -901,139 +916,6 @@ void checkhitwall_r(DDukeActor* spr, walltype* wal, const DVector3& pos, int atw } return; } - case RRTILE7555: - if (!isRRRA()) break; - wal->picnum = RRTILE5015; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7441: - if (!isRRRA()) break; - wal->picnum = RRTILE5016; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7559: - if (!isRRRA()) break; - wal->picnum = RRTILE5017; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7433: - if (!isRRRA()) break; - wal->picnum = RRTILE5018; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7557: - if (!isRRRA()) break; - wal->picnum = RRTILE5019; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7553: - if (!isRRRA()) break; - wal->picnum = RRTILE5020; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7552: - if (!isRRRA()) break; - wal->picnum = RRTILE5021; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7568: - if (!isRRRA()) break; - wal->picnum = RRTILE5022; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7540: - if (!isRRRA()) break; - wal->picnum = RRTILE5023; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7558: - if (!isRRRA()) break; - wal->picnum = RRTILE5024; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7554: - if (!isRRRA()) break; - wal->picnum = RRTILE5025; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7579: - if (!isRRRA()) break; - wal->picnum = RRTILE5026; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7561: - if (!isRRRA()) break; - wal->picnum = RRTILE5027; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7580: - if (!isRRRA()) break; - wal->picnum = RRTILE5037; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE8227: - if (!isRRRA()) break; - wal->picnum = RRTILE5070; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE8503: - if (!isRRRA()) break; - wal->picnum = RRTILE5079; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE8567: - case RRTILE8568: - case RRTILE8569: - case RRTILE8570: - case RRTILE8571: - if (!isRRRA()) break; - wal->picnum = RRTILE5082; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE7859: - if (!isRRRA()) break; - wal->picnum = RRTILE5081; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE8496: - if (!isRRRA()) break; - wal->picnum = RRTILE5061; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE8617: - if (!isRRRA()) break; - if (numplayers < 2) - { - wal->picnum = RRTILE8618; - S_PlayActorSound(47, spr); - } - return; - case RRTILE8620: - if (!isRRRA()) break; - wal->picnum = RRTILE8621; - S_PlayActorSound(47, spr); - return; - case RRTILE8622: - if (!isRRRA()) break; - wal->picnum = RRTILE8623; - S_PlayActorSound(495, spr); - return; - case WEAPONCABINET: - if (!isRRRA()) break; - wal->picnum = WEAPONCABINETBROKE; - S_PlayActorSound(GLASS_HEAVYBREAK, spr); - return; - case RRTILE8497: - if (!isRRRA()) break; - wal->picnum = RRTILE5076; - S_PlayActorSound(495, spr); - return; - case RRTILE7533: - if (!isRRRA()) break; - wal->picnum = RRTILE5035; - S_PlayActorSound(495, spr); - return; - case COLAMACHINE: case VENDMACHINE: breakwall(wal->picnum + 2, spr, wal); diff --git a/source/games/duke/src/vmexports.cpp b/source/games/duke/src/vmexports.cpp index f604f1c00..daf38ab4f 100644 --- a/source/games/duke/src/vmexports.cpp +++ b/source/games/duke/src/vmexports.cpp @@ -486,29 +486,31 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, spawnweaponorammo, DukeActor_spawnweap ACTION_RETURN_POINTER(DukeActor_spawnweaponorammo(self, type)); } -void DukeActor_Lotsofglass(DDukeActor* origin, int count) +void DukeActor_Lotsofglass(DDukeActor* origin, int count, walltype* wal) { - lotsofglass(origin, nullptr, count); + lotsofglass(origin, wal, count); } DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, lotsofglass, DukeActor_Lotsofglass) { PARAM_SELF_PROLOGUE(DDukeActor); PARAM_INT(count); - DukeActor_Lotsofglass(self, count); + PARAM_POINTER(wall, walltype); + DukeActor_Lotsofglass(self, count, wall); return 0; } -void DukeActor_Lotsofcolourglass(DDukeActor* origin, int count) +void DukeActor_Lotsofcolourglass(DDukeActor* origin, int count, walltype* wal) { - lotsofcolourglass(origin, nullptr, count); + lotsofcolourglass(origin, wal, count); } DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, lotsofcolourglass, DukeActor_Lotsofcolourglass) { PARAM_SELF_PROLOGUE(DDukeActor); PARAM_INT(count); - DukeActor_Lotsofcolourglass(self, count); + PARAM_POINTER(wall, walltype); + DukeActor_Lotsofcolourglass(self, count, wall); return 0; } diff --git a/wadsrc/static/filter/redneck.ridesagain/engine/engine.def b/wadsrc/static/filter/redneck.ridesagain/engine/engine.def index ee0343546..f5dba6aa0 100644 --- a/wadsrc/static/filter/redneck.ridesagain/engine/engine.def +++ b/wadsrc/static/filter/redneck.ridesagain/engine/engine.def @@ -193,4 +193,35 @@ tileflag TFLAG_BLOCKDOOR { RRTILE8565 RRTILE8605 } - \ No newline at end of file + + breakwall RRTILE7555, RRTILE5015, GLASS_HEAVYBREAK + breakwall RRTILE7441, RRTILE5016, GLASS_HEAVYBREAK + breakwall RRTILE7559, RRTILE5017, GLASS_HEAVYBREAK + breakwall RRTILE7433, RRTILE5018, GLASS_HEAVYBREAK + breakwall RRTILE7557, RRTILE5019, GLASS_HEAVYBREAK + breakwall RRTILE7553, RRTILE5020, GLASS_HEAVYBREAK + breakwall RRTILE7552, RRTILE5021, GLASS_HEAVYBREAK + breakwall RRTILE7568, RRTILE5022, GLASS_HEAVYBREAK + breakwall RRTILE7540, RRTILE5023, GLASS_HEAVYBREAK + breakwall RRTILE7558, RRTILE5024, GLASS_HEAVYBREAK + breakwall RRTILE7554, RRTILE5025, GLASS_HEAVYBREAK + breakwall RRTILE7579, RRTILE5026, GLASS_HEAVYBREAK + breakwall RRTILE7561, RRTILE5027, GLASS_HEAVYBREAK + breakwall RRTILE7580, RRTILE5037, GLASS_HEAVYBREAK + breakwall RRTILE8227, RRTILE5070, GLASS_HEAVYBREAK + breakwall RRTILE8503, RRTILE5079, GLASS_HEAVYBREAK + breakwall RRTILE8567, RRTILE5082, GLASS_HEAVYBREAK + breakwall RRTILE8568, RRTILE5082, GLASS_HEAVYBREAK + breakwall RRTILE8569, RRTILE5082, GLASS_HEAVYBREAK + breakwall RRTILE8570, RRTILE5082, GLASS_HEAVYBREAK + breakwall RRTILE8571, RRTILE5082, GLASS_HEAVYBREAK + breakwall RRTILE7859, RRTILE5081, GLASS_HEAVYBREAK + breakwall RRTILE8496, RRTILE5061, GLASS_HEAVYBREAK + breakwall RRTILE8620, RRTILE8621, WOODBREK + breakwall RRTILE8622, RRTILE8623, SIGNHIT + breakwall WEAPONCABINET, WEAPONCABINETBROKE, GLASS_HEAVYBREAK + breakwall RRTILE8497, RRTILE5076, SIGNHIT + breakwall RRTILE7533, RRTILE5035, SIGNHIT + breakwall RRTILE8617, RRTILE8618, WOODBREK, "RedneckBreakwalls.SinglePlayerBreak" + + diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index ec58143a1..94e55e32f 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -115,6 +115,8 @@ version "4.10" #include "zscript/games/duke/actors/airplane.zs" #include "zscript/games/duke/actors/piano.zs" +#include "zscript/games/duke/world/redneckbreak.zs" + #include "zscript/games/blood/bloodgame.zs" #include "zscript/games/blood/ui/menu.zs" #include "zscript/games/blood/ui/sbar.zs" diff --git a/wadsrc/static/zscript/games/duke/actors/destructibles.zs b/wadsrc/static/zscript/games/duke/actors/destructibles.zs index 91d626b33..d40283e34 100644 --- a/wadsrc/static/zscript/games/duke/actors/destructibles.zs +++ b/wadsrc/static/zscript/games/duke/actors/destructibles.zs @@ -129,7 +129,7 @@ class DukeFanSprite : DukeActor self.setSpriteSetImage(1); self.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; if (self.sector.CheckTexture(sectortype.floor, "FANSHADOW")) - self.sector.SetTexture(sectortype.floor, "FANSHADOWBROKE"); + self.sector.SetTextureName(sectortype.floor, "FANSHADOWBROKE"); self.PlayActorSound("GLASS_HEAVYBREAK"); for (int j = 0; j < 16; j++) self.RANDOMSCRAP(); diff --git a/wadsrc/static/zscript/games/duke/dukeactor.zs b/wadsrc/static/zscript/games/duke/dukeactor.zs index 4209a9da0..e0fd9bd1c 100644 --- a/wadsrc/static/zscript/games/duke/dukeactor.zs +++ b/wadsrc/static/zscript/games/duke/dukeactor.zs @@ -171,8 +171,8 @@ class DukeActor : CoreActor native native DukeActor spawn(Name type); native DukeActor spawnsprite(int type); // for cases where the map has a picnum stored. Avoid when possible. native DukeActor spawnweaponorammo(int type); - native void lotsofglass(int count); - native void lotsofcolourglass(int count); + native void lotsofglass(int count, walltype wal = null); + native void lotsofcolourglass(int count, walltype wal = null); native void makeitfall(); native void detonate(name type); native void checkhitdefault(DukeActor proj); diff --git a/wadsrc/static/zscript/games/duke/world/redneckbreak.zs b/wadsrc/static/zscript/games/duke/world/redneckbreak.zs new file mode 100644 index 000000000..3f4e72090 --- /dev/null +++ b/wadsrc/static/zscript/games/duke/world/redneckbreak.zs @@ -0,0 +1,22 @@ +// Container for handler functions that handle walls with breakable textures +struct RedneckBreakWalls +{ + + static void breakwall(TextureID newpn, DukeActor spr, walltype wal) + { + wal.SetTexture(walltype.main, newpn); + spr.PlayActorSound("VENT_BUST"); + spr.PlayActorSound("GLASS_HEAVYBREAK"); + spr.lotsofglass(10, wal); + } + + static void SinglePlayerBreak(walltype wal, TextureID newtex, Sound snd, DukeActor hitter) + { + if (ud.multimode < 2) + { + wal.SetTexture(walltype.main, newtex); + hitter.PlayActorSound(snd); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/maptypes.zs b/wadsrc/static/zscript/maptypes.zs index 2bee29735..ec6187da9 100644 --- a/wadsrc/static/zscript/maptypes.zs +++ b/wadsrc/static/zscript/maptypes.zs @@ -241,7 +241,8 @@ struct sectortype native native double, double getslopes(Vector2 pos); native sectortype nextsectorneighborz(double refz, int find); native bool CheckTexture(int place, Name tex); - native void SetTexture(int place, Name tex); + native void SetTextureName(int place, Name tex); + native void SetTexture(int place, TextureID tex); } @@ -253,6 +254,11 @@ struct sectortype native struct walltype native { + enum EPlane + { + main = 0, + over = 1, + } native readonly Vector2 pos; native readonly int point2; @@ -296,6 +302,8 @@ struct walltype native native double Length(); native void move(Vector2 vec); native void dragpoint(Vector2 vec); + native void SetTextureName(int place, Name tex); + native void SetTexture(int place, TextureID tex); } //=============================================================================