From 977df190fcc19ade0e6adb6d00d0eb5865126da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= Date: Sat, 21 Dec 2019 12:18:16 +0200 Subject: [PATCH] Scripting|Doom|Heretic|Hexen: Added Thing "On death" script IssueID #2374 --- .../include/doomsday/world/thinker.h | 2 + .../apps/libdoomsday/src/defs/dedparser.cpp | 1 + doomsday/apps/libdoomsday/src/defs/thing.cpp | 1 + .../libdoomsday/src/doomsdayapp_bindings.cpp | 2 +- doomsday/apps/plugins/common/include/mobj.h | 4 +- .../apps/plugins/common/src/world/mobj.cpp | 49 +++++++++++++++++-- doomsday/apps/plugins/doom/src/p_inter.c | 2 + doomsday/apps/plugins/heretic/src/p_inter.c | 5 +- doomsday/apps/plugins/hexen/src/p_inter.c | 5 +- 9 files changed, 63 insertions(+), 8 deletions(-) diff --git a/doomsday/apps/libdoomsday/include/doomsday/world/thinker.h b/doomsday/apps/libdoomsday/include/doomsday/world/thinker.h index e3f2596eb1..123453614e 100644 --- a/doomsday/apps/libdoomsday/include/doomsday/world/thinker.h +++ b/doomsday/apps/libdoomsday/include/doomsday/world/thinker.h @@ -48,6 +48,8 @@ typedef struct thinker_s { #define THINKER_DATA(thinker, T) (reinterpret_cast((thinker).d)->as()) #define THINKER_DATA_MAYBE(thinker, T) (de::maybeAs(reinterpret_cast((thinker).d))) +#define THINKER_NS(thinker) (THINKER_DATA((thinker), ThinkerData).objectNamespace()) + #ifdef __cplusplus extern "C" { #endif diff --git a/doomsday/apps/libdoomsday/src/defs/dedparser.cpp b/doomsday/apps/libdoomsday/src/defs/dedparser.cpp index ae08d03635..90eb3dac41 100644 --- a/doomsday/apps/libdoomsday/src/defs/dedparser.cpp +++ b/doomsday/apps/libdoomsday/src/defs/dedparser.cpp @@ -1265,6 +1265,7 @@ DENG2_PIMPL(DEDParser) RV_INT_ELEM("Misc4", (*mo)["misc"], 3) RV_STR("On touch", (*mo)["onTouch"]) // script function (MF_SPECIAL) + RV_STR("On death", (*mo)["onDeath"]) // script function RV_END CHECKSC; diff --git a/doomsday/apps/libdoomsday/src/defs/thing.cpp b/doomsday/apps/libdoomsday/src/defs/thing.cpp index e9b6e22685..c7961ff02e 100644 --- a/doomsday/apps/libdoomsday/src/defs/thing.cpp +++ b/doomsday/apps/libdoomsday/src/defs/thing.cpp @@ -44,6 +44,7 @@ void Thing::resetToDefaults() def().addNumber("mass", 0); def().addNumber("damage", 0); def().addText ("onTouch", ""); // script function to call when touching a special thing + def().addText ("onDeath", ""); // script function to call when thing is killed def().addArray ("flags").array().addMany(NUM_MOBJ_FLAGS, 0); def().addArray ("misc").array().addMany(NUM_MOBJ_MISC, 0); } diff --git a/doomsday/apps/libdoomsday/src/doomsdayapp_bindings.cpp b/doomsday/apps/libdoomsday/src/doomsdayapp_bindings.cpp index aa55370a64..2c7c8c7a1c 100644 --- a/doomsday/apps/libdoomsday/src/doomsdayapp_bindings.cpp +++ b/doomsday/apps/libdoomsday/src/doomsdayapp_bindings.cpp @@ -57,7 +57,7 @@ static Value *Function_Player_Thing(Context &ctx, const Function::ArgumentValues const int plrNum = playerIndex(ctx); if (const mobj_t *mo = DoomsdayApp::players().at(plrNum).publicData().mo) { - return new RecordValue(THINKER_DATA(mo->thinker, ThinkerData).objectNamespace()); + return new RecordValue(THINKER_NS(mo->thinker)); } return nullptr; } diff --git a/doomsday/apps/plugins/common/include/mobj.h b/doomsday/apps/plugins/common/include/mobj.h index 3bcca926c7..2575a105fe 100644 --- a/doomsday/apps/plugins/common/include/mobj.h +++ b/doomsday/apps/plugins/common/include/mobj.h @@ -236,6 +236,8 @@ enum mobjtouchresult_e { MTR_DESTROY }; +void Mobj_RunScriptOnDeath(mobj_t *mob, mobj_t *killer); + /** * Called when @a toucher comes into contact with special thing @a special that has a * custom scripted touch action. @@ -247,7 +249,7 @@ enum mobjtouchresult_e { * @return @c true if a scripted action is defined for the object. In this case, @a result * will contain a valid value afterwards. */ -dd_bool Mobj_TouchSpecialScriptedThing(mobj_t *mob, mobj_t *special, enum mobjtouchresult_e *result); +dd_bool Mobj_RunScriptOnTouch(mobj_t *mob, mobj_t *special, enum mobjtouchresult_e *result); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/apps/plugins/common/src/world/mobj.cpp b/doomsday/apps/plugins/common/src/world/mobj.cpp index 90abb74a87..e0bfdff736 100644 --- a/doomsday/apps/plugins/common/src/world/mobj.cpp +++ b/doomsday/apps/plugins/common/src/world/mobj.cpp @@ -1154,17 +1154,59 @@ void Mobj_RestoreObjectState(mobj_t *mob, de::Info::BlockElement const &state) #endif } -dd_bool Mobj_TouchSpecialScriptedThing(mobj_t *mob, mobj_t *special, enum mobjtouchresult_e *result) +void Mobj_RunScriptOnDeath(mobj_t *mob, mobj_t *killer) { using namespace de; + if (IS_NETWORK_CLIENT) + { + // Clients don't do this, only the server will. + return; + } + + // Check Thing definition for an onDeath script. + const auto &thingDef = DED_Definitions()->things[mob->type]; + if (const String onDeathSrc = thingDef.gets(QStringLiteral("onDeath"))) + { + LOG_AS("Mobj_RunScriptOnDeath"); + + const auto &self = THINKER_NS(mob->thinker); + + Record ns; + ns.add(QStringLiteral("self")).set(new RecordValue(self)); + Variable &killerVar = ns.add(QStringLiteral("killer")); + if (killer) + { + killerVar.set(new RecordValue(THINKER_NS(killer->thinker))); + } + else + { + killerVar.set(new NoneValue); + } + Process proc(&ns); + Script script(onDeathSrc); + proc.run(script); + proc.execute(); + } +} + +dd_bool Mobj_RunScriptOnTouch(mobj_t *mob, mobj_t *special, enum mobjtouchresult_e *result) +{ + using namespace de; + + if (IS_NETWORK_CLIENT) + { + // Clients don't do this, only the server will. + return false; + } + // Check Thing definition for an onTouch script. const auto &thingDef = DED_Definitions()->things[special->type]; if (const String onTouchSrc = thingDef.gets(QStringLiteral("onTouch"))) { - LOG_AS("Mobj_TouchSpecialScriptedThing"); + LOG_AS("Mobj_RunScriptOnTouch"); - const auto &self = THINKER_DATA(special->thinker, ThinkerData).objectNamespace(); + const auto &self = THINKER_NS(special->thinker); // We will make it seem like the special thing has a script function // called "onTouch", even though we are only now parsing the script from @@ -1177,6 +1219,7 @@ dd_bool Mobj_TouchSpecialScriptedThing(mobj_t *mob, mobj_t *special, enum mobjto // the function. The function returns a code that tells what to do with the // special item afterwards: "keep", "dormant", "hide", "destroy". + // We are interested in the return value, so make it a function that can be called. String src = "def onTouch(toucher)\n"; src += onTouchSrc; src += "\nend"; diff --git a/doomsday/apps/plugins/doom/src/p_inter.c b/doomsday/apps/plugins/doom/src/p_inter.c index f49da60ca9..84b2d6e590 100644 --- a/doomsday/apps/plugins/doom/src/p_inter.c +++ b/doomsday/apps/plugins/doom/src/p_inter.c @@ -981,6 +981,8 @@ void P_KillMobj(mobj_t *source, mobj_t *target, dd_bool stomping) target->corpseTics = 0; target->height /= 2*2; + Mobj_RunScriptOnDeath(target, source); + if(source && source->player) { // Count for intermission. diff --git a/doomsday/apps/plugins/heretic/src/p_inter.c b/doomsday/apps/plugins/heretic/src/p_inter.c index 961f94de21..4edf4990c2 100644 --- a/doomsday/apps/plugins/heretic/src/p_inter.c +++ b/doomsday/apps/plugins/heretic/src/p_inter.c @@ -971,7 +971,7 @@ void P_TouchSpecialMobj(mobj_t *special, mobj_t *toucher) player = toucher->player; - if (Mobj_TouchSpecialScriptedThing(toucher, special, &touchResult)) + if (Mobj_RunScriptOnTouch(toucher, special, &touchResult)) { switch (touchResult) { @@ -1058,6 +1058,9 @@ static void killMobj(mobj_t *source, mobj_t *target) target->flags2 &= ~MF2_PASSMOBJ; target->corpseTics = 0; target->height /= 2*2; + + Mobj_RunScriptOnDeath(target, source); + if(source && source->player) { if(target->flags & MF_COUNTKILL) diff --git a/doomsday/apps/plugins/hexen/src/p_inter.c b/doomsday/apps/plugins/hexen/src/p_inter.c index 169998128e..708072b79b 100644 --- a/doomsday/apps/plugins/hexen/src/p_inter.c +++ b/doomsday/apps/plugins/hexen/src/p_inter.c @@ -1452,8 +1452,7 @@ void P_KillMobj(mobj_t *source, mobj_t *target) target->flags2 &= ~MF2_PASSMOBJ; target->height /= 2 * 2; - if((target->flags & MF_COUNTKILL || target->type == MT_ZBELL) && - target->special) + if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL) && target->special) { // Initiate monster death actions. if(target->type == MT_SORCBOSS) @@ -1466,6 +1465,8 @@ void P_KillMobj(mobj_t *source, mobj_t *target) } } + Mobj_RunScriptOnDeath(target, source); + if(source && source->player) { // Check for frag changes.