Skip to content

Implement misc spells for OpenMW#33

Open
Assumeru wants to merge 34 commits into
mainfrom
misc
Open

Implement misc spells for OpenMW#33
Assumeru wants to merge 34 commits into
mainfrom
misc

Conversation

@Assumeru

Copy link
Copy Markdown
Contributor

Includes #32.

Comment thread Data Files/scripts/TamrielData/global_magic.lua
Comment thread Data Files/scripts/TamrielData/global_magic.lua
requiredLuaApi = 129,
settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic",
settingsEnabledByDefault = true,
settingsKey = "Settings_TamrielData_page01Main_group02Magic_miscBlinkIndicator"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good if this setting were to be placed after the miscSpells setting. (perhaps it could be made to be toggleable only if the miscSpells is enabled, but not worth the effort imo) To achieve that this key needs a change. My suggestion:
Settings_TamrielData_page01Main_group02Magic_miscSpellsBlinkIndicator

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all these keys are obnoxiously long and we should be using the order property to order them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit, I made them that way because I wanted them to be unique (i.e. not unique within TD but among all players' games and their mods). We can work on changing that if it irks us too much.
(wait, there's an order property? had no idea)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of uniqueness I think we should do the same thing we do in the esms: anything that starts with one of our prefixes is ours and if another mod uses the same prefix that mod should be considered incompatible.

In this case that'd be something like Settings_T_ or the current Settings_TamrielData_. It's more so the part after that that is much longer than it has much need to be. Settings_TamrielData_miscSpellsBlinkIndicator seems like it should be just fine and doesn't take up such a large portion of my screen (especially in the yaml files.)

Definitely out of scope for this PR, though. And not particularly important regardless.

Comment thread Data Files/l10n/TamrielData/en.yaml Outdated
Comment thread Data Files/scripts/TamrielData/player_magic.lua

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO if a file is not a PLAYER/ACTOR/GLOBAL/MENU script in omwscripts, then it shouldn't have a player/actor/global/menu prefix in its naming. And this - in its current form - is a utility file with a function used by both the actor and player blink scripting. I suggest one of these options:

  • a rename - to magic_blink.lua
  • Or - if we'll have more of magic utils files like that (I don't see any more yet) - maybe even make a new directory magic for magic utilities and put this file in. I'd call it blink_utils.lua in that case
    • or move it to utils directory, although I think utils should include framework stuff only, not gameplay stuff

EDIT: On the other hand, even if the script is not marked directly in omwscripts as a PLAYER/ACTOR, it may be written in a way that makes it usable only by player/actor scripts (ex. it calls functions only accessible within that scope). One could say that such approach should warrant even utility files to have a prefix in their name. Maybe also a valid point. Will think on it, unless you have opinions. Not a gamebreaking thing, really

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong feelings on naming. I tried to match what was there mostly. Adding additional subdirectories could be worthwhile (whether magic or say global/menu/local.)

The only thing that really matters is that we're essentially locked in once we release. For any script that saves state anyway. So ideally we'd get it right the first time 😛

@trav5555 trav5555 Jul 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something low-effort - a secondary or helpers directory -- put the files not directly 'called' from omwscripts there (plus CUSTOMs). The actor/player prefixes stay as a guide showing the context which the scripts ought to be called from.

utils
secondary
├─ actor_magic_blink.lua
├─ player_magic_passwall.lua
├─ actor_summons.lua
└─ container_banish.lua
actor_magic.lua
global_magic.lua
global_miscspells.lua
global_mwscript_variable.lua
global_restrict_equipment.lua
global_summons.lua
load_magic.lua
menu_settings.lua
menu_version_warning.lua
player_magic.lua
player_restrict_equipment.lua

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That layout makes sense to me, but I don't know about the directory name. secondary doesn't tell me much. helpers seems better except it's too much like utils.

Maybe something like lib/library/include/incl/magic?

Comment thread Data Files/scripts/TamrielData/player_magic.lua Outdated
Comment thread Data Files/scripts/TamrielData/actor_magic.lua Outdated
Comment thread Data Files/scripts/TamrielData/actor_magic.lua
Comment thread Data Files/scripts/TamrielData/actor_magic.lua
Comment thread Data Files/scripts/TamrielData/global_miscspells.lua Outdated
Comment thread Data Files/scripts/TamrielData/global_miscspells.lua Outdated
Comment thread Data Files/scripts/TamrielData/actor_magic.lua Outdated
end
local items = {}
for _, item in pairs(actor.type.inventory(actor):getAll()) do
-- TODO: filter items. Don't copy MWSE, it doesn't account for script added items

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by that, exactly? You mean the getAll doesn;t really get all things, or it gets too much? I recall some 'invisible' light-emitting objects (welkynd enemies? aurorans? not sure) which were problematic for pwn's QuickLoot (you could pick them up). But are they problematic here, considering the new container is still using the engine backend for opening it? Assuming that's what you meant?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MWSE version purposely omits most items from the created container by comparing with the creature's base inventory. This means it fails to account for items added by scripts (e.g. OnDeath.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, I misread. Well, we I suggest maybe replacing this ingredient check with a hardcoded list of ingredients perhaps - least harm?

ingred_daedras_heart_01
ingred_daedra_skin_01
ingred_scamp_skin_01
t_ingcrea_dridreasilk_01
t_ingcrea_prismaticdust_01

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we shouldn't just drop the idea of filtering items entirely. In both implementations, of course. Is banishing that much easier than fighting?

Addendum for if we don't do that:

ingred_void_salts_01
ingred_fire_salts_01
ingred_frost_salts_01

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, banishing - assuming you can cast a strong enough spell - is a one-hit daedra defeat button. Not that Morrowind's combat is difficult.

I suspect the idea behind filtering was rather that since the banished daedra don't leave their body behind, then how could the player harvest their hearts or other parts.
Dropping the idea and just allow all items seems very tempting from the simplification perspective - may as well handwave the bodyparts thing as daedric shenanigans. The only thing that would stop me from simplifying this is respect for Kynes' implementation. I defer to you on that. Leaving it as-is (or hardcode the ingredient list) is likely least controversial.

Comment thread Data Files/scripts/TamrielData/actor_magic.lua Outdated
Comment thread Data Files/scripts/TamrielData/actor_magic.lua
Comment thread Data Files/scripts/TamrielData/actor_magic.lua
Comment thread Data Files/scripts/TamrielData/actor_summons.lua Outdated
Comment thread Data Files/scripts/TamrielData/actor_summons.lua
Comment on lines +196 to +197
--TODO cap
data.enchantmentCharge = data.enchantmentCharge + charge

@trav5555 trav5555 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's a dead code for now because of no I.SpellCasting (! 3029), but am I correct that getting the max charge here and in resartusEquipment can be extracted to a common function? Something like

local function getItemEnchantmentMaxCharge(item)
	local record = item.type.records[item.recordId]
	local maxCharge = 0
	if record.enchant then
		local enchantment = core.magic.enchantments.records[record.enchant]
		if enchantment then
			-- FIXME: this is incorrect for autocalc
			maxCharge = enchantment.charge
		end
	end
	return maxCharge
end

and then here you'd do

local maxCharge = getItemEnchantmentMaxCharge(item)
if data.enchantmentCharge + charge <= maxCharge then
    data.enchantmentCharge = data.enchantmentCharge + charge
elseif maxCharge > 0 then
    data.enchantmentCharge = maxCharge
end

?

(not sure on the function returning zero if invalid)

end
local record = target.type.records[target.recordId]
local script = record.mwscript
if script and not (script:find("t_scnpc") and not script:find("_were") or safeScripts[script]) then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably embarrassing for me, but I had to double check the operator precedence and even then I don't find that script condition readable. If you'd be doing any changes in this file, could you please put the brackets around the t_scnpc and not _were? Unless you don't want to.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh. I'm perhaps more comfortable mixing and and or than some. Did you see the MWSE line it's based on, though?

state.wabbajack[creature.id] = nil
local target = data.target
if target:isValid() then
target:teleport(creature.cell, creature.position, creature.rotation)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you cast wabbajack on a summoned creature (yours or the enemy's) and its summon duration expires while it's in the containment cell, the scripting hangs here, since the relevant creature is already gone:

[11:06:12.543 E] Global[scripts/tamrieldata/global_magic.lua] onUpdate failed. Lua error: Object is either removed or already in the process of teleporting

I think adding an and target.count > 0 condition to the if above resolves this, as that'd be the same as the one in https://gitlab.com/OpenMW/openmw/-/blob/master/apps/openmw/mwlua/objectbindings.cpp#L515.

I tested, seems to work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. Ideally the wabbajack creature would disappear immediately, but this is probably the best we can reasonably do.

Comment thread Data Files/l10n/TamrielData/en.yaml Outdated
@@ -5,6 +5,10 @@ Settings_TamrielData_page01Main_group01Main_restrictEquipment_Description: "Prev
Settings_TamrielData_page01Main_group02Magic: "Magic"
Settings_TamrielData_page01Main_group02Magic_miscSpells: "Add New Miscellaneous Spells"
Settings_TamrielData_page01Main_group02Magic_miscSpells_Description: "Adds new spells that do not fit into usual categories."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it needs a \nRequires restart. now.

return summons[effectId]
end

I.T_ActorMagic.addEffectStartHandler(function(caster, spell, effect, track)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add...Handler calls be hidden behind isFeatureEnabled checks in this file and global_miscspells also? I wonder about people using other mods adjusting/implementing unimplemented TD spells (like hyacinth's unofficial spellmod) and expecting them to work alongside Tamriel_Data. We probably don't want to (unintentionally) forbid that.

Replacing records in load_magic is barred by a setting, but, not the handler functions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can since we're using player scoped settings and those aren't available in global scripts.

Ideally we'd be using global settings, but those can't be set from menu scripts (yet.) There's some relevant talk on https://gitlab.com/OpenMW/openmw/-/merge_requests/5369

Magic_wabbajackAlready: "{target} is already Wabbajacked!"

Magic_summonDevourer: "Summon Devourer"
Magic_summonDevourerDesc: "This effect summons a devourer from Oblivion. It appears six feet in front of the caster and attacks any entity that attacks the caster until the effect ends or the summoning is killed. At death, or when the effect ends, the summoning disappears, returning to Oblivion. If summoned in town, the guards will attack you and the summoning on sight."

@trav5555 trav5555 Jul 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parts about guards attacking on sight -- not true in OpenMW. I wonder if we shouldn't have them removed. From l10n I mean.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh. It's a copy paste of the vanilla effect descriptions. That those all lie is admittedly silly, but we can just claim vanilla parity 😛

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants