Skip to content

Dehardcoding spellcasting

Spurred by a discussion on Discord, i've concluded that the optimal path for dehardcoding some of my VR changes is to first dehardcode some or all combat functions of OpenMW.

The target for this MR is spellcasting.

The architecture that i've gone for is to introduce Lua Classes and implement as much of the spellcasting logic as possible using these classes. These classes are made available through the Classes interface, which acts as a centralized way of accessing and overriding lua classes (by overriding the interface).

See: https://openmw-vr.readthedocs.io/en/dehardcode-spellcast/reference/lua-scripting/interface_classes.html

The MR adds 8 .lua scripts to builtin.omwscripts

# Classes framework
NPC,CREATURE,PLAYER: scripts/omw/classes/local.lua
GLOBAL: scripts/omw/classes/global.lua

GLOBAL: scripts/omw/mechanics/globalcontroller.lua
CREATURE, NPC, PLAYER: scripts/omw/mechanics/actorcontroller.lua
CREATURE, NPC, PLAYER: scripts/omw/mechanics/spellcasting.lua
GLOBAL: scripts/omw/spellcasting/global.lua
CREATURE: scripts/omw/mechanics/creaturecontroller.lua
PLAYER: scripts/omw/mechanics/playercontroller.lua

And a set of common files

scripts/omw/classes/animation.lua
scripts/omw/classes/spell.lua
scripts/omw/classes/spellcast.lua

scripts/omw/mechanics/common.lua

The scripts create 1 handler

  • spellcasting.lua:onSpellCastHandlers -- Called when a spell is cast. Allows modifying all attributes of the spell before applying it to other actors / launching the projectile.

And 3 lua classes: https://openmw-vr.readthedocs.io/en/dehardcode-spellcast/reference/lua-scripting/interface_classes.html

  • Animation - Aims to simplify managing animations, callbacks, and save/load of these.
  • Spell - Wrapper around all logic related to reading out / computing effect params, costs, cast chance, etc.
  • Spellcast - Action object that performs a spellcast

A few examples of how to use these classes:

The following engine handler is added

  • onProjectileHit: Caused by Lua projectile impact. Handled by GlobalController which forwards magic lua projectiles to a MagicBoltHit event. Will later do equivalent for ammo-based projectiles.

The following global events are added

  • LaunchProjectile: (Handled in globalcontroller.lua) Takes a Projectile class, does world.launchProjectile(), and stores the Projectile class associated with the ID returned by world.launchProjectile()
  • ExplodeSpell: (Handled in spellcasting/global.lua) Takes a Spell class and calls spell:explode() on it w/ parameters.
  • Inflict: (Handled in spellcasting/global.lua) Inflicts a spell on a target based on options. Recommended instead of using ApplyMagicEffects events directly.
  • ApplyMagicEffects: (Handled in spellcasting/global.lua) Applies magic effects to inanimate objects.
  • MagicBoltHit: (Handled in spellcasting/global.lua) Magic bolt impact logic.
  • ConsumeItemCharge: (Handled in globalcontroller.lua) Reduces the amount of charge left in a specific item.
  • SpawnVfx: (Handled in globalcontroller.lua) Spawns a vfx at specific location
  • PlaySound3d: (Handled in globalcontroller.lua) Plays a 3d sound at a specific location
  • ConsumeItem: (Handled in globalcontroller.lua) Reduces the number of items in a stack

The following local events:

  • ApplyMagicEffects: (Handled in spellcasting.lua) Applies spell effects to the attached actor
  • SpellcastFailed: (Handled in spellcasting.lua) Prints spell failure message / plays spell failure sound
  • SpellcastComplete: (Handled in spellcasting.lua) Handles skill progression.
  • BreakInvisibility: (Handled in spellcasting.lua) Cancels all active invisibility effects.
  • ConsumeFatigue: (Handled in actorcontroller.lua) Consumes fatigue
  • ConsumeHealth: (Handled in actorcontroller.lua) Consumes health
  • ConsumeMagicka (Handled in actorcontroller.lua) Consumes magicka
  • AddVfx (Handled in actorcontroller.lua) Adds vfx to the attach actor's animation (forwards parameters to animation.addVfx)
  • PlaySound3d: (Handled in actorcontroller.lua) Plays a 3d sound on this actor

3 New interfaces are added

  • ActorMechanics -- Adds a few actor functions related to mechanics
  • SpellCasting -- Adds a few methods related to spells, for adding onSpellCast handlers, and notably the castSpell method.
  • Classes -- Single location to access Lua classes.
Edited by Mads Buvik Sandvei

Merge request reports