Skip to content

Commit

Permalink
Heretic|Scripting: Defining ambient sfx via scripts
Browse files Browse the repository at this point in the history
Audio.setAmbientSequence() is the user-facing API that translates the argument list to afxcmds and numeric parameters.

Defs.getSoundNum() was added because sounds aren't kept in a DEDRegister yet.

IssueID #2375
  • Loading branch information
skyjake committed Nov 12, 2020
1 parent 902bb02 commit 103dd7e
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 14 deletions.
18 changes: 17 additions & 1 deletion doomsday/apps/client/src/def_main.cpp
Expand Up @@ -80,6 +80,7 @@ RuntimeDefs runtimeDefs;

static bool defsInited;
static mobjinfo_t *gettingFor;
static Binder *defsBinder;

static inline FS1 &fileSys()
{
Expand All @@ -100,6 +101,11 @@ void RuntimeDefs::clear()
stateInfo.clear();
}

static Value *Function_Defs_GetSoundNum(Context &, const Function::ArgumentValues &args)
{
return new NumberValue(DED_Definitions()->getSoundNum(args.at(0)->asText()));
}

void Def_Init()
{
::runtimeDefs.clear();
Expand All @@ -108,7 +114,14 @@ void Def_Init()
auto &defs = *DED_Definitions();

// Make the definitions visible in the global namespace.
App::app().scriptSystem().addNativeModule("Defs", defs.names);
auto &scr = ScriptSystem::get();
scr.addNativeModule("Defs", defs.names);

/// TODO: Add a DEDRegister for sounds so this lookup is not needed and can be converted
/// to a utility script function.
defsBinder = new Binder;
defsBinder->init(defs.names)
<< DE_FUNC(Defs_GetSoundNum, "getSoundNum", "name");

// Constants for definitions.
DENG2_ADD_NUMBER_CONSTANT(defs.names, SN_SPAWN);
Expand All @@ -130,6 +143,9 @@ void Def_Init()

void Def_Destroy()
{
delete defsBinder;
defsBinder = nullptr;

App::app().scriptSystem().removeNativeModule("Defs");

DED_Definitions()->clear();
Expand Down
9 changes: 0 additions & 9 deletions doomsday/apps/client/src/world/base/clientserverworld.cpp
Expand Up @@ -682,15 +682,6 @@ DENG2_PIMPL(ClientServerWorld)
}
}

// Script to run after setup.
if (const String onSetupSrc = mapInfo.gets("onSetup"))
{
Script script(onSetupSrc);
Process proc;
proc.run(script);
proc.execute();
}

// Reset world time.
time = 0;

Expand Down
@@ -1,6 +1,6 @@
# Additional functions for games

import World, Math, Defs
import World, Math, Defs, Audio

def World.Thing.info()
return Defs.things.order[self.type()]
Expand Down Expand Up @@ -30,3 +30,40 @@ end
def World.Thing.setNoBlocking()
self.changeFlags(1, 0x2, False) # MF_SOLID in mo.flags
end

def Audio.setAmbientSequence(id, commands)
# Defines or redefines an ambient sound effect sequence (Heretic only).
# - id: Sequence ID. The built-in ones are 0-9.
# - commands: Text and argument values specying the sequence.

# These are the afxcmds defined in Heretic's p_spec.cpp.
AFXCMD = { # Parameters:
'play': 0, # (sound)
'playabsvol': 1, # (sound, volume)
'playrelvol': 2, # (sound, volume)
'delay': 3, # (ticks)
'delayrand': 4, # (andbits)
'end': 5
}

# Convert the commands to the internal representation.
seq = []
i = 0
while i < len(commands)
cmd = commands[i]
seq += [AFXCMD[cmd]]
# Parameters.
if cmd == 'play'
seq += [Defs.getSoundNum(commands[i + 1])]
i += 1
elsif cmd in ['playabsvol', 'playrelvol']
seq += [Defs.getSoundNum(commands[i + 1]), commands[i + 2]]
i += 2
elsif cmd in ['delay', 'delayrand']
seq += [commands[i + 1]]
i += 1
end
i += 1
end
Audio.defineAmbientSfx(id, seq)
end
13 changes: 13 additions & 0 deletions doomsday/apps/plugins/common/src/world/p_mapsetup.cpp
Expand Up @@ -25,6 +25,8 @@

#include <doomsday/world/entitydef.h>
#include <gamefw/mapspot.h>
#include <de/Script>
#include <de/Process>

#include <cmath>
#include <cctype> // isspace
Expand Down Expand Up @@ -914,6 +916,17 @@ void P_FinalizeMapChange(uri_s const *mapUri_)
P_InitCorpseQueue();
#endif

// Script to run during map setup. It is executed at this specific point so that it can
// initialize data for map spots and spawned things. Other script hooks could be added
// to be called at other points during map setup (before/after, for example).
if (const String onSetupSrc = G_MapInfoForMapUri(mapUri).gets("onSetup"))
{
Script script(onSetupSrc);
Process proc;
proc.run(script);
proc.execute();
}

initMapSpots();
spawnMapObjects();
PO_InitForMap();
Expand Down
6 changes: 3 additions & 3 deletions doomsday/apps/plugins/heretic/src/h_api.cpp
Expand Up @@ -159,14 +159,14 @@ static de::Value *Function_Thing_Attack(de::Context &ctx, const de::Function::Ar
}

static de::Value *
Function_Audio_SetAmbientSequence(de::Context &, const de::Function::ArgumentValues &args)
Function_Audio_DefineAmbientSfx(de::Context &, const de::Function::ArgumentValues &args)
{
std::vector<int> seq;
for (const auto *value : args.at(1)->as<ArrayValue>().elements())
{
seq.push_back(value->asInt());
}
seq.push_back(-1); // always undefined, treated as `afxcmd_end`
seq.push_back(-1); // always undefined, treated as `afxcmd_end` (with a warning)
P_DefineAmbientSfx(args.at(0)->asInt(), seq.data(), seq.size());
return nullptr;
}
Expand Down Expand Up @@ -206,7 +206,7 @@ DENG_ENTRYPOINT void DP_Load(void)
<< DENG2_FUNC_DEFS(Thing_Attack, "attack", "damage" << "missile", attackArgs);

Common_GameBindings().init(scr.nativeModule("Audio"))
<< DE_FUNC(Audio_SetAmbientSequence, "setAmbientSequence", "id" << "cmds");
<< DE_FUNC(Audio_DefineAmbientSfx, "defineAmbientSfx", "id" << "afxcmds");
}
}

Expand Down

0 comments on commit 103dd7e

Please sign in to comment.