Skip to content

Commit

Permalink
Heretic|Scripting: Scripted touch action for special things
Browse files Browse the repository at this point in the history
A Thing definition may specify an "On touch" script that gets run when the thing is touched. This replaces any hardcoded logic that might have affected the thing.

See the manual for an example: https://manual.dengine.net/ded/thing#on_touch

IssueID #2352
  • Loading branch information
skyjake committed Nov 16, 2019
1 parent 9870aa3 commit 004039c
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 2 deletions.
3 changes: 3 additions & 0 deletions doomsday/apps/libdoomsday/src/defs/dedparser.cpp
Expand Up @@ -1262,6 +1262,9 @@ DENG2_PIMPL(DEDParser)
RV_INT_ELEM("Misc2", (*mo)["misc"], 1)
RV_INT_ELEM("Misc3", (*mo)["misc"], 2)
RV_INT_ELEM("Misc4", (*mo)["misc"], 3)

RV_STR("On touch", (*mo)["onTouch"]) // script function (MF_SPECIAL)

RV_END
CHECKSC;
}
Expand Down
1 change: 1 addition & 0 deletions doomsday/apps/libdoomsday/src/defs/thing.cpp
Expand Up @@ -43,6 +43,7 @@ void Thing::resetToDefaults()
def().addNumber("height", 0);
def().addNumber("mass", 0);
def().addNumber("damage", 0);
def().addText ("onTouch", ""); // script function to call when touching a special thing
def().addArray ("flags").array().addMany(NUM_MOBJ_FLAGS, 0);
def().addArray ("misc").array().addMany(NUM_MOBJ_MISC, 0);
}
Expand Down
21 changes: 21 additions & 0 deletions doomsday/apps/plugins/common/include/mobj.h
Expand Up @@ -228,6 +228,27 @@ mobj_t *Mobj_LaunchMissile (mobj_t *mob, mobj_t *missile, coord_t const targetPo

void Mobj_InflictDamage(mobj_t *mob, mobj_t const *inflictor, int damage);

enum mobjtouchresult_e {
MTR_UNDEFINED,
MTR_KEEP,
MTR_MAKE_DORMANT,
MTR_HIDE,
MTR_DESTROY
};

/**
* Called when @a toucher comes into contact with special thing @a special that has a
* custom scripted touch action.
*
* @param mob Thing doing the touching.
* @param special Special thing being touched.
* @param result What to do with the special thing afterwards.
*
* @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);

#ifdef __cplusplus
} // extern "C"

Expand Down
63 changes: 63 additions & 0 deletions doomsday/apps/plugins/common/src/world/mobj.cpp
Expand Up @@ -28,6 +28,7 @@
#include <doomsday/world/mobjthinkerdata.h>
#include <de/String>
#include <de/mathutil.h>
#include <de/Log>
#include <QTextStream>

#include "dmu_lib.h"
Expand Down Expand Up @@ -1152,3 +1153,65 @@ 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)
{
using namespace de;

// 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");

const auto &self = THINKER_DATA(special->thinker, ThinkerData).objectNamespace();

// 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
// the DEDs. In the future, there might be an actual "onTouch" function in
// some Thing class that gets called instead (in this case, the Thing
// definition would be created in a script and not via DED).
//
// The function will perform any actions required for the touch interaction.
// "self" points to the special thing, "toucher" is given as argument to
// the function. The function returns a code that tells what to do with the
// special item afterwards: "keep", "dormant", "hide", "destroy".

String src = "def onTouch(toucher)\n";
src += onTouchSrc;
src += "\nend";

Record ns;
Script script(src);
Process proc(&ns);
proc.run(script);
proc.execute();

// Function is ready, call it now with the mobjs.
ns.add(QStringLiteral("self")).set(new RecordValue(self));
std::unique_ptr<Value> resultValue(
Process::scriptCall(Process::TakeResult,
ns,
QStringLiteral("onTouch"),
&THINKER_DATA(mob->thinker, ThinkerData)));
if (result)
{
*result = MTR_KEEP;
if (resultValue && !is<NoneValue>(resultValue.get()))
{
const String val = resultValue->asText();
if (val == "keep") *result = MTR_KEEP;
else if (val == "dormant") *result = MTR_MAKE_DORMANT;
else if (val == "hide") *result = MTR_HIDE;
else if (val == "destroy") *result = MTR_DESTROY;
else
{
LOG_SCR_ERROR("Invalid return value from function: \"%s\"")
<< resultValue->asText();
}
}
}
return true;
}
return false;
}
26 changes: 24 additions & 2 deletions doomsday/apps/plugins/heretic/src/p_inter.c
Expand Up @@ -511,6 +511,7 @@ typedef enum {
IT_ITEM_TORCH,
IT_ITEM_FIREBOMB,
IT_ITEM_TELEPORT,
IT_ITEM_CUSTOM, // scripted
IT_AMMO_WAND,
IT_AMMO_WAND_LARGE,
IT_AMMO_MACE,
Expand Down Expand Up @@ -953,6 +954,7 @@ void P_TouchSpecialMobj(mobj_t *special, mobj_t *toucher)
player_t *player;
coord_t delta;
itemtype_t item;
enum mobjtouchresult_e touchResult = MTR_UNDEFINED;

DENG_ASSERT(special != 0);
DENG_ASSERT(toucher != 0);
Expand All @@ -969,8 +971,24 @@ void P_TouchSpecialMobj(mobj_t *special, mobj_t *toucher)

player = toucher->player;

if (Mobj_TouchSpecialScriptedThing(toucher, special, &touchResult))
{
switch (touchResult)
{
case MTR_MAKE_DORMANT:
item = IT_ITEM_CUSTOM;
break;

case MTR_KEEP:
return; // Nothing further to do.

default:
item = IT_NONE;
break;
}
}
// Identify by sprite.
if((item = getItemTypeBySprite(special->sprite)) != IT_NONE)
else if ((item = getItemTypeBySprite(special->sprite)) != IT_NONE)
{
// In Heretic the number of rounds to give for an ammo type is defined
// by the 'health' of the mobj.
Expand Down Expand Up @@ -1003,11 +1021,13 @@ void P_TouchSpecialMobj(mobj_t *special, mobj_t *toucher)
case IT_ITEM_TORCH:
case IT_ITEM_FIREBOMB:
case IT_ITEM_TELEPORT:
case IT_ITEM_CUSTOM:
setDormantItem(special);
break;

default:
if(gfw_Rule(deathmatch) && !(special->flags & MF_DROPPED))
if(touchResult == MTR_HIDE ||
(gfw_Rule(deathmatch) && !(special->flags & MF_DROPPED)))
{
special->flags &= ~MF_SPECIAL;
special->flags2 |= MF2_DONTDRAW;
Expand All @@ -1019,7 +1039,9 @@ void P_TouchSpecialMobj(mobj_t *special, mobj_t *toucher)
}

if(!mapSetup)
{
player->bonusCount += BONUSADD;
}
break;
}
}
Expand Down

0 comments on commit 004039c

Please sign in to comment.