From 6f074c92394bf7642577476b3821cd016cb48caa Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 4 Apr 2026 17:18:33 +0200 Subject: [PATCH 01/12] Implement summon effects in OpenMW --- Data Files/Tamriel_Data.omwscripts | 4 + Data Files/l10n/TamrielData/en.yaml | 59 ++++++- .../scripts/TamrielData/actor_magic.lua | 147 ++++++++++++++++++ .../scripts/TamrielData/actor_summons.lua | 111 +++++++++++++ .../scripts/TamrielData/global_summons.lua | 27 ++++ Data Files/scripts/TamrielData/load_magic.lua | 101 ++++++++++++ 6 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 Data Files/scripts/TamrielData/actor_magic.lua create mode 100644 Data Files/scripts/TamrielData/actor_summons.lua create mode 100644 Data Files/scripts/TamrielData/global_summons.lua create mode 100644 Data Files/scripts/TamrielData/load_magic.lua diff --git a/Data Files/Tamriel_Data.omwscripts b/Data Files/Tamriel_Data.omwscripts index 3c47086..00a6b50 100644 --- a/Data Files/Tamriel_Data.omwscripts +++ b/Data Files/Tamriel_Data.omwscripts @@ -5,3 +5,7 @@ GLOBAL: scripts/TamrielData/global_mwscript_variable.lua PLAYER: scripts/TamrielData/player_magic.lua PLAYER: scripts/TamrielData/player_restrict_equipment.lua MENU: scripts/TamrielData/menu_version_warning.lua +PLAYER, NPC, CREATURE: scripts/TamrielData/actor_magic.lua +PLAYER, NPC, CREATURE: scripts/TamrielData/actor_summons.lua +GLOBAL: scripts/TamrielData/global_summons.lua +LOAD: scripts/TamrielData/load_magic.lua diff --git a/Data Files/l10n/TamrielData/en.yaml b/Data Files/l10n/TamrielData/en.yaml index 13047df..75040a6 100644 --- a/Data Files/l10n/TamrielData/en.yaml +++ b/Data Files/l10n/TamrielData/en.yaml @@ -21,4 +21,61 @@ TamrielData_magic_passwallWard: "You cannot pass through to there." TamrielData_magic_passwallAlpha: "You cannot pass through that." TamrielData_magic_passwallExterior: "You must be in a confined space." TamrielData_magic_passwallDoorExterior: "You cannot leave a confined space." -TamrielData_magic_passwallUnderwater: "You cannot be underwater." \ No newline at end of file +TamrielData_magic_passwallUnderwater: "You cannot be underwater." + +Magic_T_summon_Devourer: "Summon Devourer" +Magic_T_summon_DevourerDesc: "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." +Magic_T_summon_DremArch: "Summon Dremora Archer" +Magic_T_summon_DremArchDesc: "This effect summons a dremora archer 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." +Magic_T_summon_DremCast: "Summon Dremora Spellcaster" +Magic_T_summon_DremCastDesc: "This effect summons a dremora spellcaster 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." +Magic_T_summon_Guardian: "Summon Guardian" +Magic_T_summon_GuardianDesc: "This effect summons a guardian 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." +Magic_T_summon_LesserClfr: "Summon Rock Biter Clannfear" +Magic_T_summon_LesserClfrDesc: "This effect summons a rock biter clannfear 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." +Magic_T_summon_Ogrim: "Summon Ogrim" +Magic_T_summon_OgrimDesc: "This effect summons an ogrim 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." +Magic_T_summon_Seducer: "Summon Seducer" +Magic_T_summon_SeducerDesc: "This effect summons a seducer 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." +Magic_T_summon_SeducerDark: "Summon Dark Seducer" +Magic_T_summon_SeducerDarkDesc: "This effect summons a dark seducer 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." +Magic_T_summon_Vermai: "Summon Vermai" +Magic_T_summon_VermaiDesc: "This effect summons a vermai 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." +Magic_T_summon_AtroStormMon: "Summon Storm Monarch" +Magic_T_summon_AtroStormMonDesc: "This effect summons a storm monarch 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." +Magic_T_summon_IceWraith: "Summon Ice Wraith" +Magic_T_summon_IceWraithDesc: "This effect summons an ice wraith from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_DweSpectre: "Summon Dwarven Spectre" +Magic_T_summon_DweSpectreDesc: "This effect summons a dwarven spectre from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_SteamCent: "Summon Steam Centurion" +Magic_T_summon_SteamCentDesc: "This effect summons an steam centurion from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_SpiderCent: "Summon Centurion Spider" +Magic_T_summon_SpiderCentDesc: "This effect summons a centurion spider from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_WelkyndSpirit: "Summon Welkynd Spirit" +Magic_T_summon_WelkyndSpiritDesc: "This effect summons a welkynd spirit from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_Auroran: "Summon Auroran" +Magic_T_summon_AuroranDesc: "This effect summons an auroran 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." +Magic_T_summon_Herne: "Summon Herne" +Magic_T_summon_HerneDesc: "This effect summons a herne 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." +Magic_T_summon_Morphoid: "Summon Morphoid Daedra" +Magic_T_summon_MorphoidDesc: "This effect summons a morphoid daedra 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." +Magic_T_summon_Draugr: "Summon Draugr" +Magic_T_summon_DraugrDesc: "This effect summons a draugr from the Underworld. 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 the Underworld. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_Spriggan: "Summon Spriggan" +Magic_T_summon_SprigganDesc: "This effect summons a spriggan from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_BoneldGr: "Summon Bonelord Warder" +Magic_T_summon_BoneldGrDesc: "This effect summons a bonelord warder from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_Ghost: "Summon Ghost" +Magic_T_summon_GhostDesc: "This effect summons a ghost from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_Wraith: "Summon Wraith" +Magic_T_summon_WraithDesc: "This effect summons a wraith from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_Barrowguard: "Summon Barrowguard" +Magic_T_summon_BarrowguardDesc: "This effect summons a barrowguard from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_MinoBarrowguard: "Summon Minotaur Barrowguard" +Magic_T_summon_MinoBarrowguardDesc: "This effect summons a minotaur barrowguard from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_SkeletonChampion: "Summon Skeleton Champion" +Magic_T_summon_SkeletonChampionDesc: "This effect summons a skeleton champion from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_T_summon_AtroFrostMon: "Summon Frost Monarch" +Magic_T_summon_AtroFrostMonDesc: "This effect summons a frost monarch 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." +Magic_T_summon_SpiderDaedra: "Summon Spider Daedra" +Magic_T_summon_SpiderDaedraDesc: "This effect summons a spider daedra 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." diff --git a/Data Files/scripts/TamrielData/actor_magic.lua b/Data Files/scripts/TamrielData/actor_magic.lua new file mode 100644 index 0000000..9b57807 --- /dev/null +++ b/Data Files/scripts/TamrielData/actor_magic.lua @@ -0,0 +1,147 @@ +local core = require('openmw.core') + +if core.API_REVISION < 125 then + return +end + +local types = require('openmw.types') +local self = require('openmw.self') +local auxUtil = require('openmw_aux.util') + +local effectStartHandlers = {} +local effectUpdateHandlers = {} +local effectEndHandlers = {} + +local function onEffectStart(spell, effect) + auxUtil.callEventHandlers(effectStartHandlers, spell, effect) +end + +local function onEffectUpdate(spell, effect) + auxUtil.callEventHandlers(effectUpdateHandlers, spell, effect) +end + +local function onEffectEnd(id, index) + auxUtil.callEventHandlers(effectEndHandlers, id, index) +end + +local STATE_INIT = 0 +local STATE_ACTIVE = 1 +local STATE_ONCE = 2 + +local appliedOnce = {} +for _, effect in pairs(core.magic.effects.records) do + if effect.isAppliedOnce then + appliedOnce[effect.id] = true + end +end + +local state + +local activeSpells = types.Actor.activeSpells(self) + +-- This should all be replaced with built in OpenMW stuff, but that doesn't exist yet. This code cannot track effect lifecycles properly +local function updateEffects() + local active = {} + for _, spell in pairs(activeSpells) do + local id = spell.activeSpellId + active[id] = true + local effects = state[id] + if effects == nil then + effects = {} + state[id] = effects + for _, effect in pairs(spell.effects) do + effects[effect.index] = STATE_INIT + onEffectStart(spell, effect) + end + else + local activeIndices = {} + for _, effect in pairs(spell.effects) do + local index = effect.index + activeIndices[index] = true + local s = effects[index] + if s == nil then + effects[index] = STATE_INIT + onEffectStart(spell, effect) + elseif s == STATE_INIT then + if appliedOnce[effect.id] then + effects[index] = STATE_ONCE + else + s = STATE_ACTIVE + effects[index] = s + end + end + if s == STATE_ACTIVE then + onEffectUpdate(spell, effect) + end + end + for index, _ in pairs(effects) do + if activeIndices[index] == nil then + onEffectEnd(id, index) + effects[index] = nil + end + end + end + end + for id, effects in pairs(state) do + if active[id] == nil then + for index, _ in pairs(effects) do + onEffectEnd(id, index) + end + state[id] = nil + end + end +end + +local function onInit() + state = {} + for _, spell in pairs(activeSpells) do + local effects = {} + for _, effect in pairs(spell.effects) do + effects[effect.index] = STATE_INIT + end + state[spell.activeSpellId] = effects + end +end + +return { + engineHandlers = { + onInit = onInit, + onSave = function() + return state + end, + onLoad = function(data) + if data == nil then + onInit() + else + state = data + end + end, + onUpdate = updateEffects + }, + interfaceName = 'T_ActorMagic', + interface = { + version = 1, + addEffectStartHandler = function(handler) + effectStartHandlers[#effectStartHandlers + 1] = handler + end, + addEffectUpdateHandler = function(handler) + effectUpdateHandlers[#effectUpdateHandlers + 1] = handler + end, + addEffectEndHandler = function(handler) + effectEndHandlers[#effectEndHandlers + 1] = handler + end, + removeEffect = function(id, index) + -- This isn't possible and this implementation is slightly wrong, but it's better than nothing + local effects = state[id] + if effects == nil then + return + end + for i, _ in pairs(effects) do + if i ~= index then + return + end + end + activeSpells:remove(id) + end + } +} diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua new file mode 100644 index 0000000..0426b53 --- /dev/null +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -0,0 +1,111 @@ +local core = require('openmw.core') + +if core.API_REVISION < 125 then + return +end + +local I = require('openmw.interfaces') +local self = require('openmw.self') + +local summons = { + t_summon_devourer = 't_dae_cre_devourer_01', + t_summon_dremarch = 't_dae_cre_drem_arch_01', + t_summon_dremcast = 't_dae_cre_drem_cast_01', + t_summon_guardian = 't_dae_cre_guardian_01', + t_summon_lesserclfr = 't_dae_cre_lesserclfr_01', + t_summon_ogrim = 'ogrim', + t_summon_seducer = 't_dae_cre_seduc_01', + t_summon_seducerdark = 't_dae_cre_seducdark_02', + t_summon_vermai = 't_dae_cre_verm_01', + t_summon_atrostormmon = 't_dae_cre_monarchst_01', + t_summon_icewraith = 't_sky_cre_icewr_01', + t_summon_dwespectre = 'dwarven ghost', + t_summon_steamcent = 'centurion_steam', + t_summon_spidercent = 'centurion_spider', + t_summon_welkyndspirit = 't_ayl_cre_welkspr_01', + t_summon_auroran = 't_dae_cre_auroran_01', + t_summon_herne = 't_dae_cre_herne_01', + t_summon_morphoid = 't_dae_cre_morphoid_01', + t_summon_draugr = 't_sky_und_drgr_01', + t_summon_spriggan = 't_sky_cre_spriggan_01', + t_summon_boneldgr = 't_mw_und_boneldgr_01', + t_summon_ghost = 't_cyr_und_ghst_01', + t_summon_wraith = 't_cyr_und_wrth_01', + t_summon_barrowguard = 't_cyr_und_mum_01', + t_summon_minobarrowguard = 't_cyr_und_minobarrow_01', + t_summon_skeletonchampion = 't_glb_und_skelcmpgls_01', + t_summon_atrofrostmon = 't_dae_cre_monarchfr_01', + t_summon_spiderdaedra = 't_dae_cre_spiderdae_01', +} + +local state = { + summons = {} +} + +local function toKey(id, index) + return id .. ',' .. index +end + +I.T_ActorMagic.addEffectStartHandler(function(spell, effect) + local creature = summons[effect.id] + if creature == nil then + return + end + local id = spell.activeSpellId + local index = effect.index + local key = toKey(id, index) + state.summons[key] = { id = id, index = index } + core.sendGlobalEvent('T_Summon', { key = key, creature = creature, caster = self.object }) +end) + +I.T_ActorMagic.addEffectEndHandler(function(id, index) + local key = toKey(id, index) + local summon = state.summons[key] + if summon == nil then + return + end + local creature = summon.creature + if creature and creature:isValid() then + core.sendGlobalEvent('T_Unsummon', { creature = creature }) + end + state.summons[key] = nil +end) + +return { + eventHandlers = { + T_Summoned = function(data) + local summon = state.summons[data.key] + if summon == nil then + summon = {} + state.summons[data.key] = summon + end + summon.creature = data.creature + end, + T_SummonDied = function(data) + local summon = state.summons[data.key] + if summon ~= nil and summon.id ~= nil and summon.index ~= nil then + I.T_ActorMagic.removeEffect(summon.id, summon.index) + end + end, + T_MarkSummon = function(data) + state.caster = data.caster + state.key = data.key + end, + Died = function() + if state.key ~= nil then + core.sendGlobalEvent('T_Unsummon', { creature = self.object }) + if state.caster:isValid() then + state.caster:sendEvent('T_SummonDied', { key = state.key }) + end + end + end + }, + engineHandlers = { + onSave = function() + return state + end, + onLoad = function(data) + state = data + end + } +} diff --git a/Data Files/scripts/TamrielData/global_summons.lua b/Data Files/scripts/TamrielData/global_summons.lua new file mode 100644 index 0000000..64a8ee5 --- /dev/null +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -0,0 +1,27 @@ +local types = require('openmw.types') +local util = require('openmw.util') +local world = require('openmw.world') + +local distance = util.vector3(0, 120, 0) + +local startVfx = types.Static.records['VFX_Summon_Start'].model +local endVfx = types.Static.records['VFX_Summon_End'].model + +return { + eventHandlers = { + T_Summon = function(data) + local creature = world.createObject(data.creature) + local caster = data.caster + local position = caster.rotation:apply(distance) + caster.position + creature:teleport(caster.cell.name, position, { onGround = true, rotation = caster.rotation }) + creature:sendEvent('StartAIPackage', { type = 'Follow', target = caster }) + creature:sendEvent('T_MarkSummon', { key = data.key, caster = caster }) + caster:sendEvent('T_Summoned', { key = data.key, creature = creature }) + world.vfx.spawn(startVfx, position) + end, + T_Unsummon = function(data) + data.creature.enabled = false + world.vfx.spawn(startVfx, data.creature.position) + end + } +} diff --git a/Data Files/scripts/TamrielData/load_magic.lua b/Data Files/scripts/TamrielData/load_magic.lua new file mode 100644 index 0000000..ed88288 --- /dev/null +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -0,0 +1,101 @@ +local content = require('openmw.content') +local core = require('openmw.core') + +local summonTemplates = { + automaton = 'summoncenturionsphere', + creature = 'summonbear', + daedra = 'summonhunger', + undead = 'summonancestralghost' +} + +local summonEffects = { + T_summon_Devourer = { 52, 'td\\s\\td_s_summ_dev.dds', 'daedra' }, + T_summon_DremArch = { 33, 'td\\s\\td_s_sum_drm_arch.dds', 'daedra' }, + T_summon_DremCast = { 31, 'td\\s\\td_s_sum_drm_mage.dds', 'daedra' }, + T_summon_Guardian = { 69, 'td\\s\\td_s_sum_guard.dds', 'daedra' }, + T_summon_LesserClfr = { 19, 'td\\s\\td_s_sum_lsr_clan.dds', 'daedra' }, + T_summon_Ogrim = { 33, 'td\\s\\td_s_summ_ogrim.dds', 'daedra' }, + T_summon_Seducer = { 52, 'td\\s\\td_s_summ_sed.dds', 'daedra' }, + T_summon_SeducerDark = { 75, 'td\\s\\td_s_summ_d_sed.dds', 'daedra' }, + T_summon_Vermai = { 29, 'td\\s\\td_s_summ_vermai.dds', 'daedra' }, + T_summon_AtroStormMon = { 60, 'td\\s\\td_s_sum_stm_monch.dds', 'daedra' }, + T_summon_IceWraith = { 35, 'td\\s\\td_s_sum_ice_wrth.dds', 'undead' }, + T_summon_DweSpectre = { 17, 'td\\s\\td_s_sum_dwe_spctre.dds', 'undead' }, + T_summon_SteamCent = { 29, 'td\\s\\td_s_sum_dwe_cent.dds', 'automaton' }, + T_summon_SpiderCent = { 15, 'td\\s\\td_s_sum_dwe_spdr.dds', 'automaton' }, + T_summon_WelkyndSpirit = { 29, 'td\\s\\td_s_sum_welk_srt.dds', 'undead' }, + T_summon_Auroran = { 46, 'td\\s\\td_s_sum_auro.dds', 'daedra' }, + T_summon_Herne = { 18, 'td\\s\\td_s_sum_herne.dds', 'daedra' }, + T_summon_Morphoid = { 21, 'td\\s\\td_s_sum_morph.dds', 'daedra' }, + T_summon_Draugr = { 29, 'td\\s\\td_s_sum_draugr.dds', 'undead' }, + T_summon_Spriggan = { 48, 'td\\s\\td_s_sum_sprig.dds', 'creature' }, + T_summon_BoneldGr = { 71, 'td\\s\\td_s_sum_gtr_bnlrd.dds', 'undead' }, + T_summon_Ghost = { 7, 'td\\s\\td_s_summ_ghost.dds', 'undead' }, + T_summon_Wraith = { 49, 'td\\s\\td_s_summ_wraith.dds', 'undead' }, + T_summon_Barrowguard = { 11, 'td\\s\\td_s_summ_brwgurd.dds', 'undead' }, + T_summon_MinoBarrowguard = { 57, 'td\\s\\td_s_summ_mintur.dds', 'undead' }, + T_summon_SkeletonChampion = { 32, 'td\\s\\td_s_sum_skele_c.dds', 'undead' }, + T_summon_AtroFrostMon = { 47, 'td\\s\\td_s_sum_fst_monch.dds', 'daedra' }, + T_summon_SpiderDaedra = { 42, 'td\\s\\td_s_sum_spidr_dae.dds', 'daedra' }, +} + +local summonSpells = { + T_Com_Cnj_SummonDevourer = { 156, 'T_summon_Devourer', 60 }, + T_Com_Cnj_SummonDremoraArcher = { 98, 'T_summon_DremArch', 60 }, + T_Com_Cnj_SummonDremoraCaster = { 93, 'T_summon_DremCast', 60 }, + T_Com_Cnj_SummonGuardian = { 155, 'T_summon_Guardian', 45 }, + T_Com_Cnj_SummonLesserClannfear = { 57, 'T_summon_LesserClfr', 60 }, + T_Com_Cnj_SummonOgrim = { 99, 'T_summon_Ogrim', 60 }, + T_Com_Cnj_SummonSeducer = { 156, 'T_summon_Seducer', 60 }, + T_Com_Cnj_SummonSeducerDark = { 169, 'T_summon_SeducerDark', 45 }, + T_Com_Cnj_SummonVermai = { 88, 'T_summon_Vermai', 60 }, + T_Com_Cnj_SummonStormMonarch = { 180, 'T_summon_AtroStormMon', 60 }, + T_Nor_Cnj_SummonIceWraith = { 105, 'T_summon_IceWraith', 60 }, + T_Dwe_Cnj_Uni_SummonDweSpectre = { 52, 'T_summon_DweSpectre', 60 }, + T_Dwe_Cnj_Uni_SummonSteamCent = { 88, 'T_summon_SteamCent', 60 }, + T_Dwe_Cnj_Uni_SummonSpiderCent = { 45, 'T_summon_SpiderCent', 60 }, + T_Ayl_Cnj_SummonWelkyndSpirit = { 78, 'T_summon_WelkyndSpirit', 60 }, + T_Com_Cnj_SummonAuroran = { 138, 'T_summon_Auroran', 60 }, + T_Com_Cnj_SummonHerne = { 54, 'T_summon_Herne', 60 }, + T_Com_Cnj_SummonMorphoid = { 63, 'T_summon_Morphoid', 60 }, + T_Nor_Cnj_SummonDraugr = { 78, 'T_summon_Draugr', 60 }, + T_Nor_Cnj_SummonSpriggan = { 144, 'T_summon_Spriggan', 60 }, + T_De_Cnj_SummonGreaterBonelord = { 160, 'T_summon_BoneldGr', 45 }, + T_Cr_Cnj_AylSorcKSummon1 = { 40, 'T_summon_Auroran', 40 }, + T_Cr_Cnj_AylSorcKSummon3 = { 25, 'T_summon_WelkyndSpirit', 40 }, + T_Cyr_Cnj_SummonWraith = { 147, 'T_summon_Wraith', 60 }, + T_Cyr_Cnj_SummonBarrowguard = { 33, 'T_summon_Barrowguard', 60 }, + T_Cyr_Cnj_SummonMinoBarrowguard = { 171, 'T_summon_MinoBarrowguard', 60 }, + T_Com_Cnj_SummonSkeletonChamp = { 96, 'T_summon_SkeletonChampion', 60 }, + T_Com_Cnj_SummonFrostMonarch = { 141, 'T_summon_AtroFrostMon', 60 }, + T_Com_Cnj_SummonSpiderDaedra = { 126, 'T_summon_SpiderDaedra', 60 }, +} + +local l10n = core.l10n('TamrielData') + +local function addSummons() + local effects = content.magicEffects.records + for id, values in pairs(summonEffects) do + local cost = values[1] + local icon = values[2] + local template = values[3] + effects[id] = { template = effects[summonTemplates[template]], cost = cost, icon = icon, name = l10n('Magic_' .. id), description = l10n('Magic_' .. id .. 'Desc'), allowsSpellmaking = true, allowsEnchanting = true } + end + local spells = content.spells.records + local type = content.spells.TYPE.Spell + local range = content.RANGE.Self + for id, values in pairs(summonSpells) do + local cost = values[1] + local effect = values[2] + local duration = values[3] + spells[id] = { cost = cost, type = type, isAutocalc = false, starterSpellFlag = false, name = l10n('Magic_' .. effect), effects = { { duration = duration, id = effect, range = range } } } + end +end + +return { + engineHandlers = { + onContentFilesLoaded = function() + addSummons() + end + } +} From 67c1c52aae569fe46739d8ccb7178e4dde844438 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 5 Apr 2026 11:32:57 +0200 Subject: [PATCH 02/12] Fix positioning, vfx, hostility, and update effects upon going inactive --- Data Files/scripts/TamrielData/actor_magic.lua | 3 ++- Data Files/scripts/TamrielData/actor_summons.lua | 1 + Data Files/scripts/TamrielData/global_summons.lua | 9 +++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Data Files/scripts/TamrielData/actor_magic.lua b/Data Files/scripts/TamrielData/actor_magic.lua index 9b57807..900b122 100644 --- a/Data Files/scripts/TamrielData/actor_magic.lua +++ b/Data Files/scripts/TamrielData/actor_magic.lua @@ -116,7 +116,8 @@ return { state = data end end, - onUpdate = updateEffects + onUpdate = updateEffects, + onInactive = updateEffects }, interfaceName = 'T_ActorMagic', interface = { diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index 0426b53..2d8a4a8 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -90,6 +90,7 @@ return { T_MarkSummon = function(data) state.caster = data.caster state.key = data.key + self.type.stats.ai.fight(self).base = 30 -- we should probably be using dedicated creature variants end, Died = function() if state.key ~= nil then diff --git a/Data Files/scripts/TamrielData/global_summons.lua b/Data Files/scripts/TamrielData/global_summons.lua index 64a8ee5..1837249 100644 --- a/Data Files/scripts/TamrielData/global_summons.lua +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -2,7 +2,7 @@ local types = require('openmw.types') local util = require('openmw.util') local world = require('openmw.world') -local distance = util.vector3(0, 120, 0) +local distance = util.vector3(0, 120, 30) local startVfx = types.Static.records['VFX_Summon_Start'].model local endVfx = types.Static.records['VFX_Summon_End'].model @@ -12,12 +12,13 @@ return { T_Summon = function(data) local creature = world.createObject(data.creature) local caster = data.caster - local position = caster.rotation:apply(distance) + caster.position - creature:teleport(caster.cell.name, position, { onGround = true, rotation = caster.rotation }) + local rotation = util.transform.rotateZ(caster.rotation:getYaw()) + local position = rotation:apply(distance) + caster.position + creature:teleport(caster.cell.name, position, { onGround = true, rotation = rotation }) creature:sendEvent('StartAIPackage', { type = 'Follow', target = caster }) creature:sendEvent('T_MarkSummon', { key = data.key, caster = caster }) + creature:sendEvent('AddVfx', { model = startVfx }) caster:sendEvent('T_Summoned', { key = data.key, creature = creature }) - world.vfx.spawn(startVfx, position) end, T_Unsummon = function(data) data.creature.enabled = false From b37d9192b0df4c9c4200fa428a0bd7d7e07113fb Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 8 Apr 2026 17:12:09 +0200 Subject: [PATCH 03/12] Avoid spawning summons behind walls --- .../scripts/TamrielData/actor_summons.lua | 32 ++++++++++++++++++- .../scripts/TamrielData/global_summons.lua | 7 +--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index 2d8a4a8..a049e3b 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -5,7 +5,9 @@ if core.API_REVISION < 125 then end local I = require('openmw.interfaces') +local nearby = require('openmw.nearby') local self = require('openmw.self') +local util = require('openmw.util') local summons = { t_summon_devourer = 't_dae_cre_devourer_01', @@ -46,6 +48,34 @@ local function toKey(id, index) return id .. ',' .. index end +local FRONT = 0 +local BACK = 3 +local LEFT = 2 +local RIGHT = 1 +local collisionType = nearby.COLLISION_TYPE.World + nearby.COLLISION_TYPE.Door + +local function getSafeSpawn() + local origin = self.position + util.vector3(0, 0, 20) + local rotation = util.transform.rotateZ(self.rotation:getYaw()) + for direction = FRONT,BACK do + local spawn + if direction == FRONT then + spawn = origin + rotation:apply(util.vector3(0, 120, 10)) + elseif direction == BACK then + spawn = origin - rotation:apply(util.vector3(0, 120, 10)) + elseif direction == LEFT then + spawn = origin - rotation:apply(util.vector3(120, 0, 10)) + elseif direction == RIGHT then + spawn = origin + rotation:apply(util.vector3(120, 0, 10)) + end + local result = nearby.castRay(spawn, origin, { collisionType = collisionType }) + if not result.hit then + return spawn + end + end + return origin +end + I.T_ActorMagic.addEffectStartHandler(function(spell, effect) local creature = summons[effect.id] if creature == nil then @@ -55,7 +85,7 @@ I.T_ActorMagic.addEffectStartHandler(function(spell, effect) local index = effect.index local key = toKey(id, index) state.summons[key] = { id = id, index = index } - core.sendGlobalEvent('T_Summon', { key = key, creature = creature, caster = self.object }) + core.sendGlobalEvent('T_Summon', { key = key, creature = creature, caster = self.object, position = getSafeSpawn() }) end) I.T_ActorMagic.addEffectEndHandler(function(id, index) diff --git a/Data Files/scripts/TamrielData/global_summons.lua b/Data Files/scripts/TamrielData/global_summons.lua index 1837249..12c2a3c 100644 --- a/Data Files/scripts/TamrielData/global_summons.lua +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -1,9 +1,6 @@ local types = require('openmw.types') -local util = require('openmw.util') local world = require('openmw.world') -local distance = util.vector3(0, 120, 30) - local startVfx = types.Static.records['VFX_Summon_Start'].model local endVfx = types.Static.records['VFX_Summon_End'].model @@ -12,9 +9,7 @@ return { T_Summon = function(data) local creature = world.createObject(data.creature) local caster = data.caster - local rotation = util.transform.rotateZ(caster.rotation:getYaw()) - local position = rotation:apply(distance) + caster.position - creature:teleport(caster.cell.name, position, { onGround = true, rotation = rotation }) + creature:teleport(caster.cell.name, data.position, { onGround = true }) creature:sendEvent('StartAIPackage', { type = 'Follow', target = caster }) creature:sendEvent('T_MarkSummon', { key = data.key, caster = caster }) creature:sendEvent('AddVfx', { model = startVfx }) From 65171366407af1236e3517d0445c198d5960d01b Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 9 Apr 2026 21:23:54 +0200 Subject: [PATCH 04/12] Use MWSE data --- .../MWSE/mods/TamrielData/magicdata.lua | 59 ++++---- Data Files/l10n/TamrielData/en.yaml | 112 +++++++------- Data Files/l10n/TamrielData/fr.yaml | 59 +++++++- Data Files/l10n/TamrielData/pl.yaml | 59 +++++++- .../scripts/TamrielData/actor_summons.lua | 35 +---- Data Files/scripts/TamrielData/load_magic.lua | 138 +++++++----------- 6 files changed, 263 insertions(+), 199 deletions(-) diff --git a/Data Files/MWSE/mods/TamrielData/magicdata.lua b/Data Files/MWSE/mods/TamrielData/magicdata.lua index 618bf18..393c717 100644 --- a/Data Files/MWSE/mods/TamrielData/magicdata.lua +++ b/Data Files/MWSE/mods/TamrielData/magicdata.lua @@ -1,35 +1,38 @@ +-- NB: This file is shared between the MWSE and OpenMW implementations + + -- The effect costs for most summons were initially calculated by mort using a formula (dependent on a creature's health and soul) that is now lost and were then adjusted as seemed reasonable. -- Calculations have provided a new formula: Effect Cost = (.16 * Health) + (.035 * Soul); most of the old values are in close agreement with the new formula and have thus been left unchanged. -- effect id, effect name, creature id, effect mana cost, icon, effect description local td_summon_effects = { - { "T_summon_Devourer", "summonDevourer", "T_Dae_Cre_Devourer_01", 52, "td\\s\\td_s_summ_dev.dds", "summonDevourerDesc" }, - { "T_summon_DremArch", "summonDremoraArcher", "T_Dae_Cre_Drem_Arch_01", 33, "td\\s\\td_s_sum_drm_arch.dds", "summonDremoraArcherDesc" }, - { "T_summon_DremCast", "summonDremoraCaster", "T_Dae_Cre_Drem_Cast_01", 31, "td\\s\\td_s_sum_drm_mage.dds", "summonDremoraCasterDesc" }, - { "T_summon_Guardian", "summonGuardian", "T_Dae_Cre_Guardian_01", 69, "td\\s\\td_s_sum_guard.dds", "summonGuardianDesc" }, - { "T_summon_LesserClfr", "summonLesserClannfear", "T_Dae_Cre_LesserClfr_01", 19, "td\\s\\td_s_sum_lsr_clan.dds", "summonLesserClannfearDesc" }, - { "T_summon_Ogrim", "summonOgrim", "ogrim", 33, "td\\s\\td_s_summ_ogrim.dds", "summonOgrimDesc" }, - { "T_summon_Seducer", "summonSeducer", "T_Dae_Cre_Seduc_01", 52, "td\\s\\td_s_summ_sed.dds", "summonSeducerDesc" }, - { "T_summon_SeducerDark", "summonSeducerDark", "T_Dae_Cre_SeducDark_02", 75, "td\\s\\td_s_summ_d_sed.dds", "summonSeducerDarkDesc" }, - { "T_summon_Vermai", "summonVermai", "T_Dae_Cre_Verm_01", 29, "td\\s\\td_s_summ_vermai.dds", "summonVermaiDesc" }, - { "T_summon_AtroStormMon", "summonStormMonarch", "T_Dae_Cre_MonarchSt_01", 60, "td\\s\\td_s_sum_stm_monch.dds", "summonStormMonarchDesc" }, - { "T_summon_IceWraith", "summonIceWraith", "T_Sky_Cre_IceWr_01", 35, "td\\s\\td_s_sum_ice_wrth.dds", "summonIceWraithDesc" }, - { "T_summon_DweSpectre", "summonDweSpectre", "dwarven ghost", 17, "td\\s\\td_s_sum_dwe_spctre.dds", "summonDweSpectreDesc" }, - { "T_summon_SteamCent", "summonSteamCent", "centurion_steam", 29, "td\\s\\td_s_sum_dwe_cent.dds", "summonSteamCentDesc" }, - { "T_summon_SpiderCent", "summonSpiderCent", "centurion_spider", 15, "td\\s\\td_s_sum_dwe_spdr.dds", "summonSpiderCentDesc" }, - { "T_summon_WelkyndSpirit", "summonWelkyndSpirit", "T_Ayl_Cre_WelkSpr_01", 29, "td\\s\\td_s_sum_welk_srt.dds", "summonWelkyndSpiritDesc" }, - { "T_summon_Auroran", "summonAuroran", "T_Dae_Cre_Auroran_01", 46, "td\\s\\td_s_sum_auro.dds", "summonAuroranDesc" }, - { "T_summon_Herne", "summonHerne", "T_Dae_Cre_Herne_01", 18, "td\\s\\td_s_sum_herne.dds", "summonHerneDesc" }, - { "T_summon_Morphoid", "summonMorphoid", "T_Dae_Cre_Morphoid_01", 21, "td\\s\\td_s_sum_morph.dds", "summonMorphoidDesc" }, - { "T_summon_Draugr", "summonDraugr", "T_Sky_Und_Drgr_01", 29, "td\\s\\td_s_sum_draugr.dds", "summonDraugrDesc" }, - { "T_summon_Spriggan", "summonSpriggan", "T_Sky_Cre_Spriggan_01", 48, "td\\s\\td_s_sum_sprig.dds", "summonSprigganDesc" }, - { "T_summon_BoneldGr", "summonGreaterBonelord", "T_Mw_Und_BoneldGr_01", 71, "td\\s\\td_s_sum_gtr_bnlrd.dds", "summonGreaterBonelordDesc" }, - { "T_summon_Ghost", "summonGhost", "T_Cyr_Und_Ghst_01", 7, "td\\s\\td_s_summ_ghost.dds", "summonGhostDesc" }, - { "T_summon_Wraith", "summonWraith", "T_Cyr_Und_Wrth_01", 49, "td\\s\\td_s_summ_wraith.dds", "summonWraithDesc" }, - { "T_summon_Barrowguard", "summonBarrowguard", "T_Cyr_Und_Mum_01", 11, "td\\s\\td_s_summ_brwgurd.dds", "summonBarrowguardDesc" }, - { "T_summon_MinoBarrowguard", "summonMinoBarrowguard", "T_Cyr_Und_MinoBarrow_01", 57, "td\\s\\td_s_summ_mintur.dds", "summonMinoBarrowguardDesc" }, - { "T_summon_SkeletonChampion", "summonSkeletonChampion", "T_Glb_Und_SkelCmpGls_01", 32, "td\\s\\td_s_sum_skele_c.dds", "summonSkeletonChampionDesc" }, - { "T_summon_AtroFrostMon", "summonFrostMonarch", "T_Dae_Cre_MonarchFr_01", 47, "td\\s\\td_s_sum_fst_monch.dds", "summonFrostMonarchDesc" }, - { "T_summon_SpiderDaedra", "summonSpiderDaedra", "T_Dae_Cre_SpiderDae_01", 42, "td\\s\\td_s_sum_spidr_dae.dds", "summonSpiderDaedraDesc" }, + { "T_summon_Devourer", "summonDevourer", "T_Dae_Cre_Devourer_01", 52, "td\\s\\td_s_summ_dev.dds", "summonDevourerDesc", "summonHunger" }, + { "T_summon_DremArch", "summonDremoraArcher", "T_Dae_Cre_Drem_Arch_01", 33, "td\\s\\td_s_sum_drm_arch.dds", "summonDremoraArcherDesc", "summonHunger" }, + { "T_summon_DremCast", "summonDremoraCaster", "T_Dae_Cre_Drem_Cast_01", 31, "td\\s\\td_s_sum_drm_mage.dds", "summonDremoraCasterDesc", "summonHunger" }, + { "T_summon_Guardian", "summonGuardian", "T_Dae_Cre_Guardian_01", 69, "td\\s\\td_s_sum_guard.dds", "summonGuardianDesc", "summonHunger" }, + { "T_summon_LesserClfr", "summonLesserClannfear", "T_Dae_Cre_LesserClfr_01", 19, "td\\s\\td_s_sum_lsr_clan.dds", "summonLesserClannfearDesc", "summonHunger" }, + { "T_summon_Ogrim", "summonOgrim", "ogrim", 33, "td\\s\\td_s_summ_ogrim.dds", "summonOgrimDesc", "summonHunger" }, + { "T_summon_Seducer", "summonSeducer", "T_Dae_Cre_Seduc_01", 52, "td\\s\\td_s_summ_sed.dds", "summonSeducerDesc", "summonHunger" }, + { "T_summon_SeducerDark", "summonSeducerDark", "T_Dae_Cre_SeducDark_02", 75, "td\\s\\td_s_summ_d_sed.dds", "summonSeducerDarkDesc", "summonHunger" }, + { "T_summon_Vermai", "summonVermai", "T_Dae_Cre_Verm_01", 29, "td\\s\\td_s_summ_vermai.dds", "summonVermaiDesc", "summonHunger" }, + { "T_summon_AtroStormMon", "summonStormMonarch", "T_Dae_Cre_MonarchSt_01", 60, "td\\s\\td_s_sum_stm_monch.dds", "summonStormMonarchDesc", "summonHunger" }, + { "T_summon_IceWraith", "summonIceWraith", "T_Sky_Cre_IceWr_01", 35, "td\\s\\td_s_sum_ice_wrth.dds", "summonIceWraithDesc", "callBear" }, + { "T_summon_DweSpectre", "summonDweSpectre", "dwarven ghost", 17, "td\\s\\td_s_sum_dwe_spctre.dds", "summonDweSpectreDesc", "summonAncestralGhost" }, + { "T_summon_SteamCent", "summonSteamCent", "centurion_steam", 29, "td\\s\\td_s_sum_dwe_cent.dds", "summonSteamCentDesc", "summonCenturionSphere" }, + { "T_summon_SpiderCent", "summonSpiderCent", "centurion_spider", 15, "td\\s\\td_s_sum_dwe_spdr.dds", "summonSpiderCentDesc", "summonCenturionSphere" }, + { "T_summon_WelkyndSpirit", "summonWelkyndSpirit", "T_Ayl_Cre_WelkSpr_01", 29, "td\\s\\td_s_sum_welk_srt.dds", "summonWelkyndSpiritDesc", "callBear" }, + { "T_summon_Auroran", "summonAuroran", "T_Dae_Cre_Auroran_01", 46, "td\\s\\td_s_sum_auro.dds", "summonAuroranDesc", "summonHunger" }, + { "T_summon_Herne", "summonHerne", "T_Dae_Cre_Herne_01", 18, "td\\s\\td_s_sum_herne.dds", "summonHerneDesc", "summonHunger" }, + { "T_summon_Morphoid", "summonMorphoid", "T_Dae_Cre_Morphoid_01", 21, "td\\s\\td_s_sum_morph.dds", "summonMorphoidDesc", "summonHunger" }, + { "T_summon_Draugr", "summonDraugr", "T_Sky_Und_Drgr_01", 29, "td\\s\\td_s_sum_draugr.dds", "summonDraugrDesc", "summonAncestralGhost" }, + { "T_summon_Spriggan", "summonSpriggan", "T_Sky_Cre_Spriggan_01", 48, "td\\s\\td_s_sum_sprig.dds", "summonSprigganDesc", "callBear" }, + { "T_summon_BoneldGr", "summonGreaterBonelord", "T_Mw_Und_BoneldGr_01", 71, "td\\s\\td_s_sum_gtr_bnlrd.dds", "summonGreaterBonelordDesc", "summonAncestralGhost" }, + { "T_summon_Ghost", "summonGhost", "T_Cyr_Und_Ghst_01", 7, "td\\s\\td_s_summ_ghost.dds", "summonGhostDesc", "summonAncestralGhost" }, + { "T_summon_Wraith", "summonWraith", "T_Cyr_Und_Wrth_01", 49, "td\\s\\td_s_summ_wraith.dds", "summonWraithDesc", "summonAncestralGhost" }, + { "T_summon_Barrowguard", "summonBarrowguard", "T_Cyr_Und_Mum_01", 11, "td\\s\\td_s_summ_brwgurd.dds", "summonBarrowguardDesc", "summonAncestralGhost" }, + { "T_summon_MinoBarrowguard", "summonMinoBarrowguard", "T_Cyr_Und_MinoBarrow_01", 57, "td\\s\\td_s_summ_mintur.dds", "summonMinoBarrowguardDesc", "summonAncestralGhost" }, + { "T_summon_SkeletonChampion", "summonSkeletonChampion", "T_Glb_Und_SkelCmpGls_01", 32, "td\\s\\td_s_sum_skele_c.dds", "summonSkeletonChampionDesc", "summonAncestralGhost" }, + { "T_summon_AtroFrostMon", "summonFrostMonarch", "T_Dae_Cre_MonarchFr_01", 47, "td\\s\\td_s_sum_fst_monch.dds", "summonFrostMonarchDesc", "summonHunger" }, + { "T_summon_SpiderDaedra", "summonSpiderDaedra", "T_Dae_Cre_SpiderDae_01", 42, "td\\s\\td_s_sum_spidr_dae.dds", "summonSpiderDaedraDesc", "summonHunger" }, } -- effect id, effect name, item id, 2nd item ID, effect mana cost, icon, effect description diff --git a/Data Files/l10n/TamrielData/en.yaml b/Data Files/l10n/TamrielData/en.yaml index 75040a6..7db6d76 100644 --- a/Data Files/l10n/TamrielData/en.yaml +++ b/Data Files/l10n/TamrielData/en.yaml @@ -23,59 +23,59 @@ TamrielData_magic_passwallExterior: "You must be in a confined space." TamrielData_magic_passwallDoorExterior: "You cannot leave a confined space." TamrielData_magic_passwallUnderwater: "You cannot be underwater." -Magic_T_summon_Devourer: "Summon Devourer" -Magic_T_summon_DevourerDesc: "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." -Magic_T_summon_DremArch: "Summon Dremora Archer" -Magic_T_summon_DremArchDesc: "This effect summons a dremora archer 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." -Magic_T_summon_DremCast: "Summon Dremora Spellcaster" -Magic_T_summon_DremCastDesc: "This effect summons a dremora spellcaster 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." -Magic_T_summon_Guardian: "Summon Guardian" -Magic_T_summon_GuardianDesc: "This effect summons a guardian 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." -Magic_T_summon_LesserClfr: "Summon Rock Biter Clannfear" -Magic_T_summon_LesserClfrDesc: "This effect summons a rock biter clannfear 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." -Magic_T_summon_Ogrim: "Summon Ogrim" -Magic_T_summon_OgrimDesc: "This effect summons an ogrim 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." -Magic_T_summon_Seducer: "Summon Seducer" -Magic_T_summon_SeducerDesc: "This effect summons a seducer 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." -Magic_T_summon_SeducerDark: "Summon Dark Seducer" -Magic_T_summon_SeducerDarkDesc: "This effect summons a dark seducer 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." -Magic_T_summon_Vermai: "Summon Vermai" -Magic_T_summon_VermaiDesc: "This effect summons a vermai 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." -Magic_T_summon_AtroStormMon: "Summon Storm Monarch" -Magic_T_summon_AtroStormMonDesc: "This effect summons a storm monarch 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." -Magic_T_summon_IceWraith: "Summon Ice Wraith" -Magic_T_summon_IceWraithDesc: "This effect summons an ice wraith from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_DweSpectre: "Summon Dwarven Spectre" -Magic_T_summon_DweSpectreDesc: "This effect summons a dwarven spectre from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_SteamCent: "Summon Steam Centurion" -Magic_T_summon_SteamCentDesc: "This effect summons an steam centurion from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_SpiderCent: "Summon Centurion Spider" -Magic_T_summon_SpiderCentDesc: "This effect summons a centurion spider from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_WelkyndSpirit: "Summon Welkynd Spirit" -Magic_T_summon_WelkyndSpiritDesc: "This effect summons a welkynd spirit from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_Auroran: "Summon Auroran" -Magic_T_summon_AuroranDesc: "This effect summons an auroran 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." -Magic_T_summon_Herne: "Summon Herne" -Magic_T_summon_HerneDesc: "This effect summons a herne 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." -Magic_T_summon_Morphoid: "Summon Morphoid Daedra" -Magic_T_summon_MorphoidDesc: "This effect summons a morphoid daedra 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." -Magic_T_summon_Draugr: "Summon Draugr" -Magic_T_summon_DraugrDesc: "This effect summons a draugr from the Underworld. 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 the Underworld. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_Spriggan: "Summon Spriggan" -Magic_T_summon_SprigganDesc: "This effect summons a spriggan from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_BoneldGr: "Summon Bonelord Warder" -Magic_T_summon_BoneldGrDesc: "This effect summons a bonelord warder from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_Ghost: "Summon Ghost" -Magic_T_summon_GhostDesc: "This effect summons a ghost from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_Wraith: "Summon Wraith" -Magic_T_summon_WraithDesc: "This effect summons a wraith from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_Barrowguard: "Summon Barrowguard" -Magic_T_summon_BarrowguardDesc: "This effect summons a barrowguard from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_MinoBarrowguard: "Summon Minotaur Barrowguard" -Magic_T_summon_MinoBarrowguardDesc: "This effect summons a minotaur barrowguard from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_SkeletonChampion: "Summon Skeleton Champion" -Magic_T_summon_SkeletonChampionDesc: "This effect summons a skeleton champion from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." -Magic_T_summon_AtroFrostMon: "Summon Frost Monarch" -Magic_T_summon_AtroFrostMonDesc: "This effect summons a frost monarch 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." -Magic_T_summon_SpiderDaedra: "Summon Spider Daedra" -Magic_T_summon_SpiderDaedraDesc: "This effect summons a spider daedra 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." +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." +Magic_summonDremoraArcher: "Summon Dremora Archer" +Magic_summonDremoraArcherDesc: "This effect summons a dremora archer 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." +Magic_summonDremoraCaster: "Summon Dremora Spellcaster" +Magic_summonDremoraCasterDesc: "This effect summons a dremora spellcaster 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." +Magic_summonGuardian: "Summon Guardian" +Magic_summonGuardianDesc: "This effect summons a guardian 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." +Magic_summonLesserClannfear: "Summon Rock Biter Clannfear" +Magic_summonLesserClannfearDesc: "This effect summons a rock biter clannfear 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." +Magic_summonOgrim: "Summon Ogrim" +Magic_summonOgrimDesc: "This effect summons an ogrim 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." +Magic_summonSeducer: "Summon Seducer" +Magic_summonSeducerDesc: "This effect summons a seducer 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." +Magic_summonSeducerDark: "Summon Dark Seducer" +Magic_summonSeducerDarkDesc: "This effect summons a dark seducer 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." +Magic_summonVermai: "Summon Vermai" +Magic_summonVermaiDesc: "This effect summons a vermai 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." +Magic_summonStormMonarch: "Summon Storm Monarch" +Magic_summonStormMonarchDesc: "This effect summons a storm monarch 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." +Magic_summonIceWraith: "Summon Ice Wraith" +Magic_summonIceWraithDesc: "This effect summons an ice wraith from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonDweSpectre: "Summon Dwarven Spectre" +Magic_summonDweSpectreDesc: "This effect summons a dwarven spectre from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonSteamCent: "Summon Steam Centurion" +Magic_summonSteamCentDesc: "This effect summons an steam centurion from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonSpiderCent: "Summon Centurion Spider" +Magic_summonSpiderCentDesc: "This effect summons a centurion spider from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonWelkyndSpirit: "Summon Welkynd Spirit" +Magic_summonWelkyndSpiritDesc: "This effect summons a welkynd spirit from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonAuroran: "Summon Auroran" +Magic_summonAuroranDesc: "This effect summons an auroran 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." +Magic_summonHerne: "Summon Herne" +Magic_summonHerneDesc: "This effect summons a herne 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." +Magic_summonMorphoid: "Summon Morphoid Daedra" +Magic_summonMorphoidDesc: "This effect summons a morphoid daedra 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." +Magic_summonDraugr: "Summon Draugr" +Magic_summonDraugrDesc: "This effect summons a draugr from the Underworld. 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 the Underworld. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonSpriggan: "Summon Spriggan" +Magic_summonSprigganDesc: "This effect summons a spriggan from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonGreaterBonelord: "Summon Bonelord Warder" +Magic_summonGreaterBonelordDesc: "This effect summons a bonelord warder from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonGhost: "Summon Ghost" +Magic_summonGhostDesc: "This effect summons a ghost from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonWraith: "Summon Wraith" +Magic_summonWraithDesc: "This effect summons a wraith from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonBarrowguard: "Summon Barrowguard" +Magic_summonBarrowguardDesc: "This effect summons a barrowguard from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonMinoBarrowguard: "Summon Minotaur Barrowguard" +Magic_summonMinoBarrowguardDesc: "This effect summons a minotaur barrowguard from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonSkeletonChampion: "Summon Skeleton Champion" +Magic_summonSkeletonChampionDesc: "This effect summons a skeleton champion from the Outer Realms. 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 the Outer Realms. If summoned in town, the guards will attack you and the summoning on sight." +Magic_summonFrostMonarch: "Summon Frost Monarch" +Magic_summonFrostMonarchDesc: "This effect summons a frost monarch 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." +Magic_summonSpiderDaedra: "Summon Spider Daedra" +Magic_summonSpiderDaedraDesc: "This effect summons a spider daedra 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." diff --git a/Data Files/l10n/TamrielData/fr.yaml b/Data Files/l10n/TamrielData/fr.yaml index b08c38a..1a53f26 100644 --- a/Data Files/l10n/TamrielData/fr.yaml +++ b/Data Files/l10n/TamrielData/fr.yaml @@ -21,4 +21,61 @@ TamrielData_magic_passwallWard: "Vous ne pouvez pas passer jusque-là." TamrielData_magic_passwallAlpha: "Vous ne pouvez pas passer à travers ceci." TamrielData_magic_passwallExterior: "Vous devez vous trouver dans un espace confiné." TamrielData_magic_passwallDoorExterior: "Vous ne pouvez pas quitter un espace confiné." -TamrielData_magic_passwallUnderwater: "Vous ne pouvez pas vous trouver sous l'eau." \ No newline at end of file +TamrielData_magic_passwallUnderwater: "Vous ne pouvez pas vous trouver sous l'eau." + +Magic_summonDevourer: "Appel de consummeur" +Magic_summonDevourerDesc: "Cet effet permet d'invoquer un consummeur des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonDremoraArcher: "Appel d'archer drémora" +Magic_summonDremoraArcherDesc: "Cet effet permet d'invoquer un archer drémora des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonDremoraCaster: "Appel lanceur de sorts drémora" +Magic_summonDremoraCasterDesc: "Cet effet permet d'invoquer un lanceur de sorts drémora des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonGuardian: "Appel de gardien" +Magic_summonGuardianDesc: "Cet effet permet d'invoquer un gardien des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonLesserClannfear: "Appel faucheclan mange-rocher" +Magic_summonLesserClannfearDesc: "Cet effet permet d'invoquer un faucheclan mange-rocher des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonOgrim: "Appel d'ogrim" +Magic_summonOgrimDesc: "Cet effet permet d'invoquer un ogrim des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSeducer: "Appel de séductrice" +Magic_summonSeducerDesc: "Cet effet permet d'invoquer une séductrice des Royaumes extérieurs. Elle apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'elle soit tuée. Quand elle meurt ou que le sort prend fin, elle disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSeducerDark: "Appel de sombre séductrice" +Magic_summonSeducerDarkDesc: "Cet effet permet d'invoquer une sombre séductrice des Royaumes extérieurs. Elle apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'elle soit tuée. Quand elle meurt ou que le sort prend fin, elle disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonVermai: "Appel de vermaï" +Magic_summonVermaiDesc: "Cet effet permet d'invoquer un vermaï des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonStormMonarch: "Appel de monarque des tempêtes" +Magic_summonStormMonarchDesc: "Cet effet permet d'invoquer un monarque des tempêtes des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonIceWraith: "Appel de spectre des glaces" +Magic_summonIceWraithDesc: "Cet effet permet d'invoquer un spectre des glaces des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonDweSpectre: "Appel de spectre dwemer" +Magic_summonDweSpectreDesc: "Cet effet permet d'invoquer un spectre dwemer des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSteamCent: "Appel de centurion à vapeur" +Magic_summonSteamCentDesc: "Cet effet permet d'invoquer un centurion à vapeur des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSpiderCent: "Appel d'araignée-centurion" +Magic_summonSpiderCentDesc: "Cet effet permet d'invoquer une araignée-centurion des Royaumes extérieurs. Elle apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'elle soit tuée. Quand elle meurt ou que le sort prend fin, elle disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonWelkyndSpirit: "Appel d'esprit de Welkynd" +Magic_summonWelkyndSpiritDesc: "Cet effet permet d'invoquer un esprit de Welkynd des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonAuroran: "Appel d'aurorien" +Magic_summonAuroranDesc: "Cet effet permet d'invoquer un aurorien des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonHerne: "Appel d'herne" +Magic_summonHerneDesc: "Cet effet permet d'invoquer un herne des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonMorphoid: "Appel de Daedra morphoïde" +Magic_summonMorphoidDesc: "Cet effet permet d'invoquer un Daedra morphoïde des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonDraugr: "Appel de draugr" +Magic_summonDraugrDesc: "Cet effet permet d'invoquer un draugr des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSpriggan: "Appel de spriggane" +Magic_summonSprigganDesc: "Cet effet permet d'invoquer une spriggane des Royaumes extérieurs. Elle apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'elle soit tuée. Quand elle meurt ou que le sort prend fin, elle disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonGreaterBonelord: "Appel gardien seigneur ossement" +Magic_summonGreaterBonelordDesc: "Cet effet permet d'invoquer un gardien seigneur des ossements des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonGhost: "Appel de fantôme" +Magic_summonGhostDesc: "Cet effet permet d'invoquer un fantôme des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonWraith: "Appel de spectre" +Magic_summonWraithDesc: "Cet effet permet d'invoquer un spectre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonBarrowguard: "Appel de gardien de tertre" +Magic_summonBarrowguardDesc: "Cet effet permet d'invoquer un gardien de tertre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonMinoBarrowguard: "Appel minotaure gardien tertre" +Magic_summonMinoBarrowguardDesc: "Cet effet permet d'invoquer un minotaure gardien de tertre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSkeletonChampion: "Appel de squelette champion" +Magic_summonSkeletonChampionDesc: "Cet effet permet d'invoquer un squelette champion des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonFrostMonarch: "Appel de monarque de givre" +Magic_summonFrostMonarchDesc: "Cet effet permet d'invoquer un monarque de givre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." +Magic_summonSpiderDaedra: "Appel d'araignée daedra" +Magic_summonSpiderDaedraDesc: "Cet effet permet d'invoquer un monarque de givre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." diff --git a/Data Files/l10n/TamrielData/pl.yaml b/Data Files/l10n/TamrielData/pl.yaml index f82947c..574370d 100644 --- a/Data Files/l10n/TamrielData/pl.yaml +++ b/Data Files/l10n/TamrielData/pl.yaml @@ -1 +1,58 @@ -TamrielData_main_imgaHelm: "Samce Imga nie mogą nosić hełmów." \ No newline at end of file +TamrielData_main_imgaHelm: "Samce Imga nie mogą nosić hełmów." + +Magic_summonDevourer: "Przywołanie Pożeracza" +Magic_summonDevourerDesc: "Przywołuje z Otchłani pożeracza. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonDremoraArcher: "Przywołanie Dremory-Łucznika" +Magic_summonDremoraArcherDesc: "Przywołuje z Otchłani Dremorę-łucznika. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonDremoraCaster: "Przywołanie Dremory-Czarodzieja" +Magic_summonDremoraCasterDesc: "Przywołuje z Otchłani Dremorę-czarodzieja. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonGuardian: "Przywołanie Stróża" +Magic_summonGuardianDesc: "Przywołuje z Otchłani stróża. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonLesserClannfear: "Przewołanie Postrachu Klanów-Głazożera" +Magic_summonLesserClannfearDesc: "Przywołuje z Otchłani postrach klanów-głazożera. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonOgrim: "Przywołanie Ogrima" +Magic_summonOgrimDesc: "Przywołuje z Otchłani ogrima. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSeducer: "Przywołanie Uwodzicielki" +Magic_summonSeducerDesc: "Przywołuje z Otchłani uwodzicielkę. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSeducerDark: "Przywołanie Mrocznej Uwodzicielki" +Magic_summonSeducerDarkDesc: "Przywołuje z Otchłani mroczną uwodzicielkę. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonVermai: "Przywołanie Vermai" +Magic_summonVermaiDesc: "Przywołuje z Otchłani vermai. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonStormMonarch: "Przywołanie Monarchy Burz" +Magic_summonStormMonarchDesc: "Przywołuje z Otchłani monarchę burz. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonIceWraith: "Przywołanie Lodowego Upiora" +Magic_summonIceWraithDesc: "Przywołuje lodowego upiora. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonDweSpectre: "Przywołanie Krasnoludzkiego Widma" +Magic_summonDweSpectreDesc: "Przywołuje krasnoludzkie widmo. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSteamCent: "Przywołanie Parowego Centuriona" +Magic_summonSteamCentDesc: "Przywołuje parowego centuriona. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSpiderCent: "Przywołanie Pajęczego Centuriona" +Magic_summonSpiderCentDesc: "Przywołuje pajęczego centuriona. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonWelkyndSpirit: "Przywołanie Zjawy Welkynd" +Magic_summonWelkyndSpiritDesc: "Przywołuje zjawę welkynd. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonAuroran: "Przywołanie Aurorana" +Magic_summonAuroranDesc: "Przywołuje z Otchłani aurorana. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonHerne: "Przywołanie Herna" +Magic_summonHerneDesc: "Przywołuje z Otchłani herna. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonMorphoid: "Przywołanie Morphoida" +Magic_summonMorphoidDesc: "Przywołuje z Otchłani morphoida. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonDraugr: "Przywołanie Draugra" +Magic_summonDraugrDesc: "Przywołuje draugra. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSpriggan: "Przywołanie Spriggana" +Magic_summonSprigganDesc: "Przywołuje spriggana. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonGreaterBonelord: "Przywołanie Potężniejszego Kościeja" +Magic_summonGreaterBonelordDesc: "Przywołuje potężniejszego kościeja. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonGhost: "Przywołanie Ducha" +Magic_summonGhostDesc: "Przywołuje ducha. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonWraith: "Przywołanie Upiora" +Magic_summonWraithDesc: "Przywołuje upiora. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonBarrowguard: "Przywołanie Strażnika Kurhanu" +Magic_summonBarrowguardDesc: "Przywołuje strażnika kurhanu. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonMinoBarrowguard: "Przywołanie Minotaura-Strażnika Kurhanu" +Magic_summonMinoBarrowguardDesc: "Przywołuje minotaura-strażnika kurhanu. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSkeletonChampion: "Przywołanie Szkieletu-Bohatera" +Magic_summonSkeletonChampionDesc: "Przywołuje szkielet-bohatera. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do swojego wymiaru. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonFrostMonarch: "Przywołanie Monarchy Mrozu" +Magic_summonFrostMonarchDesc: "Przywołuje z Otchłani monarchę mrozu. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" +Magic_summonSpiderDaedra: "Przywołanie Pajęczej Daedry" +Magic_summonSpiderDaedraDesc: "Przywołuje z Otchłani pajęczą daedrę. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" \ No newline at end of file diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index a049e3b..3abbadd 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -8,37 +8,12 @@ local I = require('openmw.interfaces') local nearby = require('openmw.nearby') local self = require('openmw.self') local util = require('openmw.util') +local magicData = require('MWSE.mods.TamrielData.magicdata') -local summons = { - t_summon_devourer = 't_dae_cre_devourer_01', - t_summon_dremarch = 't_dae_cre_drem_arch_01', - t_summon_dremcast = 't_dae_cre_drem_cast_01', - t_summon_guardian = 't_dae_cre_guardian_01', - t_summon_lesserclfr = 't_dae_cre_lesserclfr_01', - t_summon_ogrim = 'ogrim', - t_summon_seducer = 't_dae_cre_seduc_01', - t_summon_seducerdark = 't_dae_cre_seducdark_02', - t_summon_vermai = 't_dae_cre_verm_01', - t_summon_atrostormmon = 't_dae_cre_monarchst_01', - t_summon_icewraith = 't_sky_cre_icewr_01', - t_summon_dwespectre = 'dwarven ghost', - t_summon_steamcent = 'centurion_steam', - t_summon_spidercent = 'centurion_spider', - t_summon_welkyndspirit = 't_ayl_cre_welkspr_01', - t_summon_auroran = 't_dae_cre_auroran_01', - t_summon_herne = 't_dae_cre_herne_01', - t_summon_morphoid = 't_dae_cre_morphoid_01', - t_summon_draugr = 't_sky_und_drgr_01', - t_summon_spriggan = 't_sky_cre_spriggan_01', - t_summon_boneldgr = 't_mw_und_boneldgr_01', - t_summon_ghost = 't_cyr_und_ghst_01', - t_summon_wraith = 't_cyr_und_wrth_01', - t_summon_barrowguard = 't_cyr_und_mum_01', - t_summon_minobarrowguard = 't_cyr_und_minobarrow_01', - t_summon_skeletonchampion = 't_glb_und_skelcmpgls_01', - t_summon_atrofrostmon = 't_dae_cre_monarchfr_01', - t_summon_spiderdaedra = 't_dae_cre_spiderdae_01', -} +local summons = {} +for _, values in pairs(magicData.td_summon_effects) do + summons[values[1]:lower()] = values[3] +end local state = { summons = {} diff --git a/Data Files/scripts/TamrielData/load_magic.lua b/Data Files/scripts/TamrielData/load_magic.lua index ed88288..98a1eb3 100644 --- a/Data Files/scripts/TamrielData/load_magic.lua +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -1,94 +1,65 @@ local content = require('openmw.content') local core = require('openmw.core') +local magicData = require('MWSE.mods.TamrielData.magicdata') -local summonTemplates = { - automaton = 'summoncenturionsphere', - creature = 'summonbear', - daedra = 'summonhunger', - undead = 'summonancestralghost' -} - -local summonEffects = { - T_summon_Devourer = { 52, 'td\\s\\td_s_summ_dev.dds', 'daedra' }, - T_summon_DremArch = { 33, 'td\\s\\td_s_sum_drm_arch.dds', 'daedra' }, - T_summon_DremCast = { 31, 'td\\s\\td_s_sum_drm_mage.dds', 'daedra' }, - T_summon_Guardian = { 69, 'td\\s\\td_s_sum_guard.dds', 'daedra' }, - T_summon_LesserClfr = { 19, 'td\\s\\td_s_sum_lsr_clan.dds', 'daedra' }, - T_summon_Ogrim = { 33, 'td\\s\\td_s_summ_ogrim.dds', 'daedra' }, - T_summon_Seducer = { 52, 'td\\s\\td_s_summ_sed.dds', 'daedra' }, - T_summon_SeducerDark = { 75, 'td\\s\\td_s_summ_d_sed.dds', 'daedra' }, - T_summon_Vermai = { 29, 'td\\s\\td_s_summ_vermai.dds', 'daedra' }, - T_summon_AtroStormMon = { 60, 'td\\s\\td_s_sum_stm_monch.dds', 'daedra' }, - T_summon_IceWraith = { 35, 'td\\s\\td_s_sum_ice_wrth.dds', 'undead' }, - T_summon_DweSpectre = { 17, 'td\\s\\td_s_sum_dwe_spctre.dds', 'undead' }, - T_summon_SteamCent = { 29, 'td\\s\\td_s_sum_dwe_cent.dds', 'automaton' }, - T_summon_SpiderCent = { 15, 'td\\s\\td_s_sum_dwe_spdr.dds', 'automaton' }, - T_summon_WelkyndSpirit = { 29, 'td\\s\\td_s_sum_welk_srt.dds', 'undead' }, - T_summon_Auroran = { 46, 'td\\s\\td_s_sum_auro.dds', 'daedra' }, - T_summon_Herne = { 18, 'td\\s\\td_s_sum_herne.dds', 'daedra' }, - T_summon_Morphoid = { 21, 'td\\s\\td_s_sum_morph.dds', 'daedra' }, - T_summon_Draugr = { 29, 'td\\s\\td_s_sum_draugr.dds', 'undead' }, - T_summon_Spriggan = { 48, 'td\\s\\td_s_sum_sprig.dds', 'creature' }, - T_summon_BoneldGr = { 71, 'td\\s\\td_s_sum_gtr_bnlrd.dds', 'undead' }, - T_summon_Ghost = { 7, 'td\\s\\td_s_summ_ghost.dds', 'undead' }, - T_summon_Wraith = { 49, 'td\\s\\td_s_summ_wraith.dds', 'undead' }, - T_summon_Barrowguard = { 11, 'td\\s\\td_s_summ_brwgurd.dds', 'undead' }, - T_summon_MinoBarrowguard = { 57, 'td\\s\\td_s_summ_mintur.dds', 'undead' }, - T_summon_SkeletonChampion = { 32, 'td\\s\\td_s_sum_skele_c.dds', 'undead' }, - T_summon_AtroFrostMon = { 47, 'td\\s\\td_s_sum_fst_monch.dds', 'daedra' }, - T_summon_SpiderDaedra = { 42, 'td\\s\\td_s_sum_spidr_dae.dds', 'daedra' }, -} +local l10n = core.l10n('TamrielData') -local summonSpells = { - T_Com_Cnj_SummonDevourer = { 156, 'T_summon_Devourer', 60 }, - T_Com_Cnj_SummonDremoraArcher = { 98, 'T_summon_DremArch', 60 }, - T_Com_Cnj_SummonDremoraCaster = { 93, 'T_summon_DremCast', 60 }, - T_Com_Cnj_SummonGuardian = { 155, 'T_summon_Guardian', 45 }, - T_Com_Cnj_SummonLesserClannfear = { 57, 'T_summon_LesserClfr', 60 }, - T_Com_Cnj_SummonOgrim = { 99, 'T_summon_Ogrim', 60 }, - T_Com_Cnj_SummonSeducer = { 156, 'T_summon_Seducer', 60 }, - T_Com_Cnj_SummonSeducerDark = { 169, 'T_summon_SeducerDark', 45 }, - T_Com_Cnj_SummonVermai = { 88, 'T_summon_Vermai', 60 }, - T_Com_Cnj_SummonStormMonarch = { 180, 'T_summon_AtroStormMon', 60 }, - T_Nor_Cnj_SummonIceWraith = { 105, 'T_summon_IceWraith', 60 }, - T_Dwe_Cnj_Uni_SummonDweSpectre = { 52, 'T_summon_DweSpectre', 60 }, - T_Dwe_Cnj_Uni_SummonSteamCent = { 88, 'T_summon_SteamCent', 60 }, - T_Dwe_Cnj_Uni_SummonSpiderCent = { 45, 'T_summon_SpiderCent', 60 }, - T_Ayl_Cnj_SummonWelkyndSpirit = { 78, 'T_summon_WelkyndSpirit', 60 }, - T_Com_Cnj_SummonAuroran = { 138, 'T_summon_Auroran', 60 }, - T_Com_Cnj_SummonHerne = { 54, 'T_summon_Herne', 60 }, - T_Com_Cnj_SummonMorphoid = { 63, 'T_summon_Morphoid', 60 }, - T_Nor_Cnj_SummonDraugr = { 78, 'T_summon_Draugr', 60 }, - T_Nor_Cnj_SummonSpriggan = { 144, 'T_summon_Spriggan', 60 }, - T_De_Cnj_SummonGreaterBonelord = { 160, 'T_summon_BoneldGr', 45 }, - T_Cr_Cnj_AylSorcKSummon1 = { 40, 'T_summon_Auroran', 40 }, - T_Cr_Cnj_AylSorcKSummon3 = { 25, 'T_summon_WelkyndSpirit', 40 }, - T_Cyr_Cnj_SummonWraith = { 147, 'T_summon_Wraith', 60 }, - T_Cyr_Cnj_SummonBarrowguard = { 33, 'T_summon_Barrowguard', 60 }, - T_Cyr_Cnj_SummonMinoBarrowguard = { 171, 'T_summon_MinoBarrowguard', 60 }, - T_Com_Cnj_SummonSkeletonChamp = { 96, 'T_summon_SkeletonChampion', 60 }, - T_Com_Cnj_SummonFrostMonarch = { 141, 'T_summon_AtroFrostMon', 60 }, - T_Com_Cnj_SummonSpiderDaedra = { 126, 'T_summon_SpiderDaedra', 60 }, -} +local function t(key) + if not key then + return '' + end + return l10n('Magic_' .. key) +end -local l10n = core.l10n('TamrielData') +local function replaceSpells(table) + local types = { + spell = content.spells.TYPE.Spell, + ability = content.spells.TYPE.Ability, + blight = content.spells.TYPE.Blight, + disease = content.spells.TYPE.Disease, + curse = content.spells.TYPE.Curse, + power = content.spells.TYPE.Power, + } + local range = { + self = content.RANGE.Self, + touch = content.RANGE.Touch, + target = content.RANGE.Target + } + local spells = content.spells.records + for _, values in pairs(table) do + local id = values[1] + local type = values[2] + local name = values[3] + local cost = values[4] + local effects = {} + for i = 1,8 do + local row = values[4 + i] + if not row then + break + end + effects[i] = row + row.range = range[row.range] + end + local spell = spells[id] + if cost then + spell.cost = cost + end + spell.type = types[type] + if name then + spell.name = t(name) + end + spell.effects = effects + end +end local function addSummons() local effects = content.magicEffects.records - for id, values in pairs(summonEffects) do - local cost = values[1] - local icon = values[2] - local template = values[3] - effects[id] = { template = effects[summonTemplates[template]], cost = cost, icon = icon, name = l10n('Magic_' .. id), description = l10n('Magic_' .. id .. 'Desc'), allowsSpellmaking = true, allowsEnchanting = true } - end - local spells = content.spells.records - local type = content.spells.TYPE.Spell - local range = content.RANGE.Self - for id, values in pairs(summonSpells) do - local cost = values[1] - local effect = values[2] - local duration = values[3] - spells[id] = { cost = cost, type = type, isAutocalc = false, starterSpellFlag = false, name = l10n('Magic_' .. effect), effects = { { duration = duration, id = effect, range = range } } } + for _, values in pairs(magicData.td_summon_effects) do + local id, name, creature, cost, icon, description, template = unpack(values) + if template == 'callBear' then + template = 'summonbear' + end + effects[id] = { template = effects[template], cost = cost, icon = icon, name = t(name), description = t(desc), allowsSpellmaking = true, allowsEnchanting = true } end end @@ -96,6 +67,7 @@ return { engineHandlers = { onContentFilesLoaded = function() addSummons() + replaceSpells(magicData.td_summon_spells) end } } From c0308a1a2c1fc1974f74ee9fab5ef1e6cbb16ebf Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 11 Apr 2026 12:01:02 +0200 Subject: [PATCH 05/12] Improve performance --- .../scripts/TamrielData/actor_magic.lua | 100 +++++++++++------- .../scripts/TamrielData/actor_summons.lua | 3 +- 2 files changed, 65 insertions(+), 38 deletions(-) diff --git a/Data Files/scripts/TamrielData/actor_magic.lua b/Data Files/scripts/TamrielData/actor_magic.lua index 900b122..a670a1e 100644 --- a/Data Files/scripts/TamrielData/actor_magic.lua +++ b/Data Files/scripts/TamrielData/actor_magic.lua @@ -13,11 +13,15 @@ local effectUpdateHandlers = {} local effectEndHandlers = {} local function onEffectStart(spell, effect) - auxUtil.callEventHandlers(effectStartHandlers, spell, effect) + local track = { ignore = true } + auxUtil.callEventHandlers(effectStartHandlers, spell, effect, track) + return track.ignore end local function onEffectUpdate(spell, effect) - auxUtil.callEventHandlers(effectUpdateHandlers, spell, effect) + local track = { ignore = false } + auxUtil.callEventHandlers(effectUpdateHandlers, spell, effect, track) + return track.ignore end local function onEffectEnd(id, index) @@ -27,6 +31,7 @@ end local STATE_INIT = 0 local STATE_ACTIVE = 1 local STATE_ONCE = 2 +local STATE_IGNORE = 3 local appliedOnce = {} for _, effect in pairs(core.magic.effects.records) do @@ -35,74 +40,85 @@ for _, effect in pairs(core.magic.effects.records) do end end -local state +local state = { + delayUpdateChecks = true, + spells = {} +} local activeSpells = types.Actor.activeSpells(self) -- This should all be replaced with built in OpenMW stuff, but that doesn't exist yet. This code cannot track effect lifecycles properly local function updateEffects() + state.delayUpdateChecks = true local active = {} for _, spell in pairs(activeSpells) do local id = spell.activeSpellId active[id] = true - local effects = state[id] + local effects = state.spells[id] if effects == nil then effects = {} - state[id] = effects - for _, effect in pairs(spell.effects) do - effects[effect.index] = STATE_INIT - onEffectStart(spell, effect) - end - else - local activeIndices = {} - for _, effect in pairs(spell.effects) do - local index = effect.index - activeIndices[index] = true - local s = effects[index] - if s == nil then - effects[index] = STATE_INIT - onEffectStart(spell, effect) - elseif s == STATE_INIT then - if appliedOnce[effect.id] then - effects[index] = STATE_ONCE - else - s = STATE_ACTIVE - effects[index] = s - end + state.spells[id] = effects + end + local activeIndices = {} + for _, effect in pairs(spell.effects) do + local index = effect.index + activeIndices[index] = true + local s = effects[index] + if s == nil then + effects[index] = STATE_INIT + if onEffectStart(spell, effect) then + effects[index] = STATE_IGNORE + else + state.delayUpdateChecks = false end - if s == STATE_ACTIVE then - onEffectUpdate(spell, effect) + elseif s == STATE_INIT then + if appliedOnce[effect.id] then + effects[index] = STATE_ONCE + else + s = STATE_ACTIVE + effects[index] = s end end - for index, _ in pairs(effects) do - if activeIndices[index] == nil then + if s == STATE_ACTIVE then + if onEffectUpdate(spell, effect) then + effects[index] = STATE_IGNORE + else + state.delayUpdateChecks = false + end + end + end + for index, s in pairs(effects) do + if activeIndices[index] == nil then + if s ~= STATE_IGNORE then onEffectEnd(id, index) - effects[index] = nil end + effects[index] = nil end end end - for id, effects in pairs(state) do + for id, effects in pairs(state.spells) do if active[id] == nil then for index, _ in pairs(effects) do onEffectEnd(id, index) end - state[id] = nil + state.spells[id] = nil end end end local function onInit() - state = {} for _, spell in pairs(activeSpells) do local effects = {} for _, effect in pairs(spell.effects) do - effects[effect.index] = STATE_INIT + effects[effect.index] = STATE_IGNORE end - state[spell.activeSpellId] = effects + state.spells[spell.activeSpellId] = effects end end +local MAX_WAIT = 0.25 +local waited = math.random() + return { engineHandlers = { onInit = onInit, @@ -116,7 +132,17 @@ return { state = data end end, - onUpdate = updateEffects, + onUpdate = function(dt) + if state.delayUpdateChecks then + waited = waited + dt + if waited < MAX_WAIT then + return + else + waited = waited - MAX_WAIT + end + end + updateEffects() + end, onInactive = updateEffects }, interfaceName = 'T_ActorMagic', @@ -133,7 +159,7 @@ return { end, removeEffect = function(id, index) -- This isn't possible and this implementation is slightly wrong, but it's better than nothing - local effects = state[id] + local effects = state.spells[id] if effects == nil then return end diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index 3abbadd..94eac41 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -51,7 +51,7 @@ local function getSafeSpawn() return origin end -I.T_ActorMagic.addEffectStartHandler(function(spell, effect) +I.T_ActorMagic.addEffectStartHandler(function(spell, effect, track) local creature = summons[effect.id] if creature == nil then return @@ -61,6 +61,7 @@ I.T_ActorMagic.addEffectStartHandler(function(spell, effect) local key = toKey(id, index) state.summons[key] = { id = id, index = index } core.sendGlobalEvent('T_Summon', { key = key, creature = creature, caster = self.object, position = getSafeSpawn() }) + track.ignore = false end) I.T_ActorMagic.addEffectEndHandler(function(id, index) From e4eff0f98400220a08c0e724a7a2ad942c0ac03c Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 11 Apr 2026 13:37:33 +0200 Subject: [PATCH 06/12] Add setting --- Data Files/l10n/TamrielData/en.yaml | 2 ++ Data Files/l10n/TamrielData/fr.yaml | 2 ++ Data Files/l10n/TamrielData/pl.yaml | 3 +++ .../scripts/TamrielData/actor_summons.lua | 2 +- Data Files/scripts/TamrielData/load_magic.lua | 23 +++++++++++-------- .../TamrielData/utils/feature_data.lua | 6 +++++ .../TamrielData/utils/version_check.lua | 12 ++++++++-- 7 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Data Files/l10n/TamrielData/en.yaml b/Data Files/l10n/TamrielData/en.yaml index 7db6d76..814a3de 100644 --- a/Data Files/l10n/TamrielData/en.yaml +++ b/Data Files/l10n/TamrielData/en.yaml @@ -5,6 +5,8 @@ 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." +Settings_TamrielData_page01Main_group02Magic_summoningSpells: "Add New Summoning Spells" +Settings_TamrielData_page01Main_group02Magic_summoningSpells_Description: "Adds new summoning spells using creatures added by Tamriel Data, such as Devourers, Herne, Dark Seducers, and Aurorans.\nRequires restart.\n\nDefault: On\n\n" Settings_TamrielData_page01Main_group99Misc: "Miscellaneous" Settings_TamrielData_page01Main_group99Misc_debugLogging: "Debug Logging" Settings_TamrielData_page01Main_group99Misc_debugLogging_Description: "Adds more logs, for example in F10 OpenMW logs. Enable this if you want to report an issue with the scripts, so that you can provide more information about it." diff --git a/Data Files/l10n/TamrielData/fr.yaml b/Data Files/l10n/TamrielData/fr.yaml index 1a53f26..0f9fe77 100644 --- a/Data Files/l10n/TamrielData/fr.yaml +++ b/Data Files/l10n/TamrielData/fr.yaml @@ -5,6 +5,8 @@ Settings_TamrielData_page01Main_group01Main_restrictEquipment_Description: "Emp Settings_TamrielData_page01Main_group02Magic: "Magie" Settings_TamrielData_page01Main_group02Magic_miscSpells: "Ajout de nouveaux sorts divers" Settings_TamrielData_page01Main_group02Magic_miscSpells_Description: "Ajoute de nouveaux sorts qui ne rentrent pas dans les catégories habituelles." +Settings_TamrielData_page01Main_group02Magic_summoningSpells: "Ajout de nouveaux sorts d'Invocation" +Settings_TamrielData_page01Main_group02Magic_summoningSpells_Description: "Ajoute de nouveaux sorts d'Invocation utilisant des créatures de Ressources communes de Tamriel comme les consummeurs, les hernes, les sombres séductrices, et les auroriens.\nRequiert un redémarrage.\n\nPar défaut : activé\n\n" Settings_TamrielData_page01Main_group99Misc: "Divers" Settings_TamrielData_page01Main_group99Misc_debugLogging: "Journalisation des messages de débug" Settings_TamrielData_page01Main_group99Misc_debugLogging_Description: "Ajoute plus de logs, par exemple dans les logs d'OpenMW affichés avec la touche F10. Activez cette option si vous souhaitez signaler un problème avec les scripts afin de pouvoir fournir plus d'informations à ce sujet." diff --git a/Data Files/l10n/TamrielData/pl.yaml b/Data Files/l10n/TamrielData/pl.yaml index 574370d..010359a 100644 --- a/Data Files/l10n/TamrielData/pl.yaml +++ b/Data Files/l10n/TamrielData/pl.yaml @@ -1,5 +1,8 @@ TamrielData_main_imgaHelm: "Samce Imga nie mogą nosić hełmów." +Settings_TamrielData_page01Main_group02Magic_summoningSpells: "Nowe Zaklęcia Przywołania" +Settings_TamrielData_page01Main_group02Magic_summoningSpells_Description: "Dodaje nowe zaklęcia przywołania używające istoty dodane w Tamriel Data, takie jak Pożeracze, Herny, Mroczne Uwodzicielki czy Auroranie.\nWymaga ponownego wczytania gry.\n\nDomyślnie: Wł.\n\n" + Magic_summonDevourer: "Przywołanie Pożeracza" Magic_summonDevourerDesc: "Przywołuje z Otchłani pożeracza. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" Magic_summonDremoraArcher: "Przywołanie Dremory-Łucznika" diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index 94eac41..87001d9 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -1,6 +1,6 @@ local core = require('openmw.core') -if core.API_REVISION < 125 then +if not core.magic.effects.records['T_summon_Devourer'] then return end diff --git a/Data Files/scripts/TamrielData/load_magic.lua b/Data Files/scripts/TamrielData/load_magic.lua index 98a1eb3..521a27c 100644 --- a/Data Files/scripts/TamrielData/load_magic.lua +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -1,6 +1,7 @@ local content = require('openmw.content') local core = require('openmw.core') local magicData = require('MWSE.mods.TamrielData.magicdata') +local version_check = require('scripts.TamrielData.utils.version_check') local l10n = core.l10n('TamrielData') @@ -41,14 +42,16 @@ local function replaceSpells(table) row.range = range[row.range] end local spell = spells[id] - if cost then - spell.cost = cost - end - spell.type = types[type] - if name then - spell.name = t(name) + if spell then + if cost then + spell.cost = cost + end + spell.type = types[type] + if name then + spell.name = t(name) + end + spell.effects = effects end - spell.effects = effects end end @@ -66,8 +69,10 @@ end return { engineHandlers = { onContentFilesLoaded = function() - addSummons() - replaceSpells(magicData.td_summon_spells) + if version_check.isFeatureEnabled('summoningSpells') then + addSummons() + replaceSpells(magicData.td_summon_spells) + end end } } diff --git a/Data Files/scripts/TamrielData/utils/feature_data.lua b/Data Files/scripts/TamrielData/utils/feature_data.lua index fb2ff48..7ee5801 100644 --- a/Data Files/scripts/TamrielData/utils/feature_data.lua +++ b/Data Files/scripts/TamrielData/utils/feature_data.lua @@ -18,6 +18,12 @@ features["miscSpells"] = { settingsEnabledByDefault = true, settingsKey = "Settings_TamrielData_page01Main_group02Magic_miscSpells" } +features["summoningSpells"] = { + requiredLuaApi = 126, + settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic", + settingsEnabledByDefault = true, + settingsKey = "Settings_TamrielData_page01Main_group02Magic_summoningSpells" +} features["debugLogging"] = { requiredLuaApi = 44, settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group99Misc", diff --git a/Data Files/scripts/TamrielData/utils/version_check.lua b/Data Files/scripts/TamrielData/utils/version_check.lua index 647aee5..62debf2 100644 --- a/Data Files/scripts/TamrielData/utils/version_check.lua +++ b/Data Files/scripts/TamrielData/utils/version_check.lua @@ -9,8 +9,16 @@ function V.isFeatureSupported(featureName) end function V.isFeatureEnabled(featureName) - local featureSettingsStorage = feature_data[featureName] and storage.playerSection(feature_data[featureName].settingsPlayerSectionStorageId) - return featureSettingsStorage and featureSettingsStorage:get(feature_data[featureName].settingsKey) + local feature = feature_data[featureName] + if not feature then + return + end + local featureSettingsStorage = storage.playerSection(feature.settingsPlayerSectionStorageId) + local value = featureSettingsStorage and featureSettingsStorage:get(feature.settingsKey) + if value == nil then + return feature.settingsEnabledByDefault + end + return value end return V \ No newline at end of file From 0d154e25675443ba5713812a0e3b01c4983fc2e7 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 11 Apr 2026 15:17:06 +0200 Subject: [PATCH 07/12] Support hypothetical multiplayer --- Data Files/Tamriel_Data.omwscripts | 3 +- .../scripts/TamrielData/actor_magic.lua | 169 +------------ .../scripts/TamrielData/actor_summons.lua | 67 +---- .../scripts/TamrielData/global_magic.lua | 232 ++++++++++++++++++ .../scripts/TamrielData/global_summons.lua | 68 ++++- 5 files changed, 310 insertions(+), 229 deletions(-) create mode 100644 Data Files/scripts/TamrielData/global_magic.lua diff --git a/Data Files/Tamriel_Data.omwscripts b/Data Files/Tamriel_Data.omwscripts index 00a6b50..7aeef41 100644 --- a/Data Files/Tamriel_Data.omwscripts +++ b/Data Files/Tamriel_Data.omwscripts @@ -5,7 +5,8 @@ GLOBAL: scripts/TamrielData/global_mwscript_variable.lua PLAYER: scripts/TamrielData/player_magic.lua PLAYER: scripts/TamrielData/player_restrict_equipment.lua MENU: scripts/TamrielData/menu_version_warning.lua +GLOBAL: scripts/TamrielData/global_magic.lua +GLOBAL: scripts/TamrielData/global_summons.lua PLAYER, NPC, CREATURE: scripts/TamrielData/actor_magic.lua PLAYER, NPC, CREATURE: scripts/TamrielData/actor_summons.lua -GLOBAL: scripts/TamrielData/global_summons.lua LOAD: scripts/TamrielData/load_magic.lua diff --git a/Data Files/scripts/TamrielData/actor_magic.lua b/Data Files/scripts/TamrielData/actor_magic.lua index a670a1e..bd69ee9 100644 --- a/Data Files/scripts/TamrielData/actor_magic.lua +++ b/Data Files/scripts/TamrielData/actor_magic.lua @@ -1,174 +1,9 @@ local core = require('openmw.core') -if core.API_REVISION < 125 then - return -end - -local types = require('openmw.types') -local self = require('openmw.self') -local auxUtil = require('openmw_aux.util') - -local effectStartHandlers = {} -local effectUpdateHandlers = {} -local effectEndHandlers = {} - -local function onEffectStart(spell, effect) - local track = { ignore = true } - auxUtil.callEventHandlers(effectStartHandlers, spell, effect, track) - return track.ignore -end - -local function onEffectUpdate(spell, effect) - local track = { ignore = false } - auxUtil.callEventHandlers(effectUpdateHandlers, spell, effect, track) - return track.ignore -end - -local function onEffectEnd(id, index) - auxUtil.callEventHandlers(effectEndHandlers, id, index) -end - -local STATE_INIT = 0 -local STATE_ACTIVE = 1 -local STATE_ONCE = 2 -local STATE_IGNORE = 3 - -local appliedOnce = {} -for _, effect in pairs(core.magic.effects.records) do - if effect.isAppliedOnce then - appliedOnce[effect.id] = true - end -end - -local state = { - delayUpdateChecks = true, - spells = {} -} - -local activeSpells = types.Actor.activeSpells(self) - --- This should all be replaced with built in OpenMW stuff, but that doesn't exist yet. This code cannot track effect lifecycles properly -local function updateEffects() - state.delayUpdateChecks = true - local active = {} - for _, spell in pairs(activeSpells) do - local id = spell.activeSpellId - active[id] = true - local effects = state.spells[id] - if effects == nil then - effects = {} - state.spells[id] = effects - end - local activeIndices = {} - for _, effect in pairs(spell.effects) do - local index = effect.index - activeIndices[index] = true - local s = effects[index] - if s == nil then - effects[index] = STATE_INIT - if onEffectStart(spell, effect) then - effects[index] = STATE_IGNORE - else - state.delayUpdateChecks = false - end - elseif s == STATE_INIT then - if appliedOnce[effect.id] then - effects[index] = STATE_ONCE - else - s = STATE_ACTIVE - effects[index] = s - end - end - if s == STATE_ACTIVE then - if onEffectUpdate(spell, effect) then - effects[index] = STATE_IGNORE - else - state.delayUpdateChecks = false - end - end - end - for index, s in pairs(effects) do - if activeIndices[index] == nil then - if s ~= STATE_IGNORE then - onEffectEnd(id, index) - end - effects[index] = nil - end - end - end - for id, effects in pairs(state.spells) do - if active[id] == nil then - for index, _ in pairs(effects) do - onEffectEnd(id, index) - end - state.spells[id] = nil - end - end -end - -local function onInit() - for _, spell in pairs(activeSpells) do - local effects = {} - for _, effect in pairs(spell.effects) do - effects[effect.index] = STATE_IGNORE - end - state.spells[spell.activeSpellId] = effects - end -end - -local MAX_WAIT = 0.25 -local waited = math.random() - return { engineHandlers = { - onInit = onInit, - onSave = function() - return state - end, - onLoad = function(data) - if data == nil then - onInit() - else - state = data - end - end, - onUpdate = function(dt) - if state.delayUpdateChecks then - waited = waited + dt - if waited < MAX_WAIT then - return - else - waited = waited - MAX_WAIT - end - end - updateEffects() - end, - onInactive = updateEffects - }, - interfaceName = 'T_ActorMagic', - interface = { - version = 1, - addEffectStartHandler = function(handler) - effectStartHandlers[#effectStartHandlers + 1] = handler - end, - addEffectUpdateHandler = function(handler) - effectUpdateHandlers[#effectUpdateHandlers + 1] = handler - end, - addEffectEndHandler = function(handler) - effectEndHandlers[#effectEndHandlers + 1] = handler - end, - removeEffect = function(id, index) - -- This isn't possible and this implementation is slightly wrong, but it's better than nothing - local effects = state.spells[id] - if effects == nil then - return - end - for i, _ in pairs(effects) do - if i ~= index then - return - end - end - activeSpells:remove(id) + onInactive = function() + core.sendGlobalEvent('T_ActorInactive', self.object) end } } diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index 87001d9..acfd683 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -8,20 +8,6 @@ local I = require('openmw.interfaces') local nearby = require('openmw.nearby') local self = require('openmw.self') local util = require('openmw.util') -local magicData = require('MWSE.mods.TamrielData.magicdata') - -local summons = {} -for _, values in pairs(magicData.td_summon_effects) do - summons[values[1]:lower()] = values[3] -end - -local state = { - summons = {} -} - -local function toKey(id, index) - return id .. ',' .. index -end local FRONT = 0 local BACK = 3 @@ -51,47 +37,15 @@ local function getSafeSpawn() return origin end -I.T_ActorMagic.addEffectStartHandler(function(spell, effect, track) - local creature = summons[effect.id] - if creature == nil then - return - end - local id = spell.activeSpellId - local index = effect.index - local key = toKey(id, index) - state.summons[key] = { id = id, index = index } - core.sendGlobalEvent('T_Summon', { key = key, creature = creature, caster = self.object, position = getSafeSpawn() }) - track.ignore = false -end) - -I.T_ActorMagic.addEffectEndHandler(function(id, index) - local key = toKey(id, index) - local summon = state.summons[key] - if summon == nil then - return - end - local creature = summon.creature - if creature and creature:isValid() then - core.sendGlobalEvent('T_Unsummon', { creature = creature }) - end - state.summons[key] = nil -end) +local state = {} return { eventHandlers = { - T_Summoned = function(data) - local summon = state.summons[data.key] - if summon == nil then - summon = {} - state.summons[data.key] = summon - end - summon.creature = data.creature - end, - T_SummonDied = function(data) - local summon = state.summons[data.key] - if summon ~= nil and summon.id ~= nil and summon.index ~= nil then - I.T_ActorMagic.removeEffect(summon.id, summon.index) - end + T_GetSummonPosition = function(data) + local position = getSafeSpawn() + data.position = position + data.caster = self.object + core.sendGlobalEvent('T_Summon', data) end, T_MarkSummon = function(data) state.caster = data.caster @@ -100,10 +54,7 @@ return { end, Died = function() if state.key ~= nil then - core.sendGlobalEvent('T_Unsummon', { creature = self.object }) - if state.caster:isValid() then - state.caster:sendEvent('T_SummonDied', { key = state.key }) - end + core.sendGlobalEvent('T_Unsummon', { creature = self.object, caster = state.caster, key = state.key }) end end }, @@ -112,7 +63,9 @@ return { return state end, onLoad = function(data) - state = data + if data then + state = data + end end } } diff --git a/Data Files/scripts/TamrielData/global_magic.lua b/Data Files/scripts/TamrielData/global_magic.lua new file mode 100644 index 0000000..121b998 --- /dev/null +++ b/Data Files/scripts/TamrielData/global_magic.lua @@ -0,0 +1,232 @@ +local core = require('openmw.core') + +if core.API_REVISION < 125 then + return +end + +local types = require('openmw.types') +local world = require('openmw.world') +local auxUtil = require('openmw_aux.util') + +local effectStartHandlers = {} +local effectUpdateHandlers = {} +local effectEndHandlers = {} + +local function onEffectStart(actor, spell, effect) + local track = { ignore = true } + auxUtil.callEventHandlers(effectStartHandlers, actor, spell, effect, track) + return track.ignore +end + +local function onEffectUpdate(actor, spell, effect) + local track = { ignore = false } + auxUtil.callEventHandlers(effectUpdateHandlers, actor, spell, effect, track) + return track.ignore +end + +local function onEffectEnd(actor, id, index) + auxUtil.callEventHandlers(effectEndHandlers, actor, id, index) +end + +local STATE_INIT = 0 +local STATE_ACTIVE = 1 +local STATE_ONCE = 2 +local STATE_IGNORE = 3 + +local appliedOnce = {} +for _, effect in pairs(core.magic.effects.records) do + if effect.isAppliedOnce then + appliedOnce[effect.id] = true + end +end + +local persistentState = { + actors = {} +} +local tempState = {} + +local function initActorState(actor, state) + local activeSpells = types.Actor.activeSpells(actor) + for _, spell in pairs(activeSpells) do + local effects = {} + for _, effect in pairs(spell.effects) do + effects[effect.index] = STATE_IGNORE + end + state.spells[spell.activeSpellId] = effects + end + return { + waited = math.random(), + activeSpells = activeSpells + } +end + +local function deleteActorState(actor) + local id = actor.id + persistentState.actors[id] = nil + tempState[id] = nil +end + +local function getActorState(actor, init) + local id = actor.id + local state = persistentState.actors[id] + if not state then + if not init then + return nil + end + state = { + delayUpdateChecks = true, + spells = {} + } + persistentState.actors[id] = state + tempState[id] = initActorState(actor, state) + elseif not tempState[id] then + tempState[id] = { + waited = math.random(), + activeSpells = types.Actor.activeSpells(actor) + } + end + return state, tempState[id] +end + +-- This should all be replaced with built in OpenMW stuff, but that doesn't exist yet. This code cannot track effect lifecycles properly +local function updateEffects(actor, state, tempState) + local canDiscard = true + state.delayUpdateChecks = true + local active = {} + for _, spell in pairs(tempState.activeSpells) do + local id = spell.activeSpellId + active[id] = true + local effects = state.spells[id] + if effects == nil then + effects = {} + state.spells[id] = effects + end + local activeIndices = {} + for _, effect in pairs(spell.effects) do + local index = effect.index + activeIndices[index] = true + local s = effects[index] + if s == nil then + effects[index] = STATE_INIT + if onEffectStart(actor, spell, effect) then + effects[index] = STATE_IGNORE + else + state.delayUpdateChecks = false + canDiscard = false + end + elseif s == STATE_INIT then + if appliedOnce[effect.id] then + effects[index] = STATE_ONCE + canDiscard = false + else + s = STATE_ACTIVE + effects[index] = s + end + end + if s == STATE_ACTIVE then + if onEffectUpdate(actor, spell, effect) then + effects[index] = STATE_IGNORE + else + state.delayUpdateChecks = false + canDiscard = false + end + end + end + for index, s in pairs(effects) do + if activeIndices[index] == nil then + if s ~= STATE_IGNORE then + onEffectEnd(actor, id, index) + end + effects[index] = nil + end + end + end + for id, effects in pairs(state.spells) do + if active[id] == nil then + for index, s in pairs(effects) do + if s ~= STATE_IGNORE then + onEffectEnd(actor, id, index) + end + end + state.spells[id] = nil + end + end + return canDiscard +end + +local MAX_WAIT = 0.25 + +local function waitOrUpdate(actor, dt) + local state, tempState = getActorState(actor, true) + if state.delayUpdateChecks then + tempState.waited = tempState.waited + dt + if tempState.waited < MAX_WAIT then + return + else + tempState.waited = tempState.waited - MAX_WAIT + end + end + updateEffects(actor, state, tempState) +end + +local activeActors = world.activeActors + +return { + engineHandlers = { + onSave = function() + return persistentState + end, + onLoad = function(data) + if data then + persistentState = data + end + end, + onUpdate = function(dt) + for _, actor in pairs(activeActors) do + waitOrUpdate(actor, dt) + end + end + }, + eventHandlers = { + T_ActorInactive = function(actor) + local state, tempState = getActorState(actor, false) + if not state then + return + end + local discard = updateEffects(actor, state, tempState) + if discard then + deleteActorState(actor) + end + end + }, + interfaceName = 'T_ActorMagic', + interface = { + version = 1, + addEffectStartHandler = function(handler) + effectStartHandlers[#effectStartHandlers + 1] = handler + end, + addEffectUpdateHandler = function(handler) + effectUpdateHandlers[#effectUpdateHandlers + 1] = handler + end, + addEffectEndHandler = function(handler) + effectEndHandlers[#effectEndHandlers + 1] = handler + end, + removeEffect = function(actor, id, index) + -- This isn't possible and this implementation is slightly wrong, but it's better than nothing + local state, tempState = getActorState(actor, false) + if not state then + return + end + local effects = state.spells[id] + if effects == nil then + return + end + for i, _ in pairs(effects) do + if i ~= index then + return + end + end + tempState.activeSpells:remove(id) + end + } +} diff --git a/Data Files/scripts/TamrielData/global_summons.lua b/Data Files/scripts/TamrielData/global_summons.lua index 12c2a3c..bbe39f5 100644 --- a/Data Files/scripts/TamrielData/global_summons.lua +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -1,23 +1,83 @@ +local core = require('openmw.core') + +if not core.magic.effects.records['T_summon_Devourer'] then + return +end + +local I = require('openmw.interfaces') local types = require('openmw.types') local world = require('openmw.world') +local magicData = require('MWSE.mods.TamrielData.magicdata') +local summons = {} +for _, values in pairs(magicData.td_summon_effects) do + summons[values[1]:lower()] = values[3] +end local startVfx = types.Static.records['VFX_Summon_Start'].model local endVfx = types.Static.records['VFX_Summon_End'].model +local state = { + summons = {} +} + +local function toKey(actor, id, index) + return actor.id .. ',' .. id .. ',' .. index +end + +I.T_ActorMagic.addEffectStartHandler(function(caster, spell, effect, track) + local creature = summons[effect.id] + if not creature then + return + end + local id = spell.activeSpellId + local index = effect.index + local key = toKey(caster, id, index) + state.summons[key] = { id = id, index = index, creatureId = creature } + caster:sendEvent('T_GetSummonPosition', { key = key }) + track.ignore = false +end) + +local function unsummon(creature) + creature.enabled = false + world.vfx.spawn(startVfx, creature.position) +end + +I.T_ActorMagic.addEffectEndHandler(function(actor, id, index) + local key = toKey(actor, id, index) + local summon = state.summons[key] + if not summon then + return + end + local creature = summon.creature + if creature and creature:isValid() then + unsummon(creature) + end + state.summons[key] = nil +end) + return { eventHandlers = { T_Summon = function(data) - local creature = world.createObject(data.creature) + local effect = state.summons[data.key] + if not effect then + return + end + local creature = world.createObject(effect.creatureId) local caster = data.caster creature:teleport(caster.cell.name, data.position, { onGround = true }) creature:sendEvent('StartAIPackage', { type = 'Follow', target = caster }) creature:sendEvent('T_MarkSummon', { key = data.key, caster = caster }) creature:sendEvent('AddVfx', { model = startVfx }) - caster:sendEvent('T_Summoned', { key = data.key, creature = creature }) + effect.creatureId = nil + effect.creature = creature end, T_Unsummon = function(data) - data.creature.enabled = false - world.vfx.spawn(startVfx, data.creature.position) + unsummon(data.creature) + local effect = state.summons[data.key] + if effect then + state.summons[data.key] = nil + I.T_ActorMagic.removeEffect(data.caster, effect.id, effect.index) + end end } } From e8cbe1e053a8ab260c9894e0cb0dc9af57e66cbb Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 11 Apr 2026 18:10:44 +0200 Subject: [PATCH 08/12] Implement enchantment, potion, ingredient, and item changing --- Data Files/l10n/TamrielData/en.yaml | 18 +++ Data Files/l10n/TamrielData/fr.yaml | 18 +++ Data Files/l10n/TamrielData/pl.yaml | 20 ++- Data Files/scripts/TamrielData/load_magic.lua | 138 ++++++++++++++++-- .../TamrielData/utils/feature_data.lua | 2 +- 5 files changed, 178 insertions(+), 18 deletions(-) diff --git a/Data Files/l10n/TamrielData/en.yaml b/Data Files/l10n/TamrielData/en.yaml index 814a3de..8dbd6de 100644 --- a/Data Files/l10n/TamrielData/en.yaml +++ b/Data Files/l10n/TamrielData/en.yaml @@ -81,3 +81,21 @@ Magic_summonFrostMonarch: "Summon Frost Monarch" Magic_summonFrostMonarchDesc: "This effect summons a frost monarch 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." Magic_summonSpiderDaedra: "Summon Spider Daedra" Magic_summonSpiderDaedraDesc: "This effect summons a spider daedra 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." + +Magic_itemPotionReflectDamageB: "Bargain Potion of Reflect Dmg" +Magic_itemPotionReflectDamageC: "Cheap Potion of Reflect Dmg" +Magic_itemPotionReflectDamageS: "Standard Potion of Reflect Dmg" +Magic_itemPotionReflectDamageQ: "Quality Potion of Reflect Dmg" +Magic_itemPotionReflectDamageE: "Exclusive Potion of Reflect Dmg" +Magic_itemPotionInsightB: "Bargain Potion of Insight" +Magic_itemPotionInsightC: "Cheap Potion of Insight" +Magic_itemPotionInsightS: "Standard Potion of Insight" +Magic_itemPotionInsightQ: "Quality Potion of Insight" +Magic_itemPotionInsightE: "Exclusive Potion of Insight" +Magic_itemPotionDetectHumanoid: "Potion of Detect Humanoid" +Magic_itemPotionDetectEnemy: "Potion of Detect Enemies" +Magic_itemPotionDetectInvisibility: "Potion of Detect Invisibility" + +Magic_itemScSummonDremoraArcher: "Scroll of Mehrunes' Quarry" +Magic_itemScSummonDremoraCaster: "Scroll of The Razor Compact" +Magic_itemScKynesIntervention: "Scroll of Kyne's Intervention" diff --git a/Data Files/l10n/TamrielData/fr.yaml b/Data Files/l10n/TamrielData/fr.yaml index 0f9fe77..d424da7 100644 --- a/Data Files/l10n/TamrielData/fr.yaml +++ b/Data Files/l10n/TamrielData/fr.yaml @@ -81,3 +81,21 @@ Magic_summonFrostMonarch: "Appel de monarque de givre" Magic_summonFrostMonarchDesc: "Cet effet permet d'invoquer un monarque de givre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." Magic_summonSpiderDaedra: "Appel d'araignée daedra" Magic_summonSpiderDaedraDesc: "Cet effet permet d'invoquer un monarque de givre des Royaumes extérieurs. Il apparaît à 2 mètres du lanceur et attaque toute entité hostile à son maître jusqu'à ce que le sort prenne fin ou qu'il soit tué. Quand il meurt ou que le sort prend fin, il disparaît et retourne dans les Royaumes extérieurs. En cas d'invocation en ville, les gardes vous attaqueront, vous et votre invocation." + +Magic_itemPotionReflectDamageB: "Potion Réflexion dégâts bradée" +Magic_itemPotionReflectDamageC: "Potion Réflexion dégâts bas prix" +Magic_itemPotionReflectDamageS: "Potion Réflexion dégâts std" +Magic_itemPotionReflectDamageQ: "Potion Réflexion dégâts qualité" +Magic_itemPotionReflectDamageE: "Potion Réflexion dégâts choix" +Magic_itemPotionInsightB: "Pot. Perspicacité bradée" +Magic_itemPotionInsightC: "Pot. Perspicacité à bas prix" +Magic_itemPotionInsightS: "Pot. Perspicacité standard" +Magic_itemPotionInsightQ: "Pot. Perspicacité de qualité" +Magic_itemPotionInsightE: "Pot. Perspicacité de choix" +Magic_itemPotionDetectHumanoid: "Potion Détecte-humanoïdes" +Magic_itemPotionDetectEnemy: "Potion Détecte-ennemis" +Magic_itemPotionDetectInvisibility: "Potion Détecte-invisibilité" + +Magic_itemScSummonDremoraArcher: "Parch. de proie de Mérunès" +Magic_itemScSummonDremoraCaster: "Parch. de convention du Rasoir" +Magic_itemScKynesIntervention: "Parch. d'Intervention de Kyne" diff --git a/Data Files/l10n/TamrielData/pl.yaml b/Data Files/l10n/TamrielData/pl.yaml index 010359a..a4f06c8 100644 --- a/Data Files/l10n/TamrielData/pl.yaml +++ b/Data Files/l10n/TamrielData/pl.yaml @@ -58,4 +58,22 @@ Magic_summonSkeletonChampionDesc: "Przywołuje szkielet-bohatera. Stworzenie poj Magic_summonFrostMonarch: "Przywołanie Monarchy Mrozu" Magic_summonFrostMonarchDesc: "Przywołuje z Otchłani monarchę mrozu. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" Magic_summonSpiderDaedra: "Przywołanie Pajęczej Daedry" -Magic_summonSpiderDaedraDesc: "Przywołuje z Otchłani pajęczą daedrę. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" \ No newline at end of file +Magic_summonSpiderDaedraDesc: "Przywołuje z Otchłani pajęczą daedrę. Stworzenie pojawi się sześć stóp przed magiem i będzie atakowało każdą zagrażającą mu istotę, póki nie minie czas trwania efektu lub póki samo nie zostanie zabite. W obydwu przypadkach przywołana istota znika, powracając do Otchłani. Pamiętaj, że jeśli przywołasz istotę z innego wymiaru wewnątrz miasta, miejska straż rzuci się na ciebie bez ostrzeżenia!" + +Magic_itemPotionReflectDamageB: "Słaba mikstura odbicia obrażeń" +Magic_itemPotionReflectDamageC: "Mała mikstura odbicia obrażeń" +Magic_itemPotionReflectDamageS: "Klasyczne odbicie obrażeń" +Magic_itemPotionReflectDamageQ: "Duża mikstura odbicia obrażeń" +Magic_itemPotionReflectDamageE: "Dosk. mikstura odbicia obrażeń" +Magic_itemPotionInsightB: "Słaba mikstura intuicji" +Magic_itemPotionInsightC: "Mała mikstura intuicji" +Magic_itemPotionInsightS: "Klasyczna mikstura intuicji" +Magic_itemPotionInsightQ: "Duża mikstura intuicji" +Magic_itemPotionInsightE: "Dosk. mikstura intuicji" +Magic_itemPotionDetectHumanoid: "Mikstura wykrycia humanoidów" +Magic_itemPotionDetectEnemy: "Mikstura wykrycia przeciwników" +Magic_itemPotionDetectInvisibility: "Miks. wykrycia niewidzialności" + +Magic_itemScSummonDremoraArcher: "Zwój Pastwy Mehrunesa" +Magic_itemScSummonDremoraCaster: "Zwój Paktu Brzytwy" +Magic_itemScKynesIntervention: "Zwój Interwencji Kyne" diff --git a/Data Files/scripts/TamrielData/load_magic.lua b/Data Files/scripts/TamrielData/load_magic.lua index 521a27c..0eeb72f 100644 --- a/Data Files/scripts/TamrielData/load_magic.lua +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -12,6 +12,31 @@ local function t(key) return l10n('Magic_' .. key) end +local implementedEffects = {} +local RANGE = { + self = content.RANGE.Self, + touch = content.RANGE.Touch, + target = content.RANGE.Target +} + +local function parseEffects(values, offset) + local effects = {} + local implemented = true + for i = 1,8 do + local row = values[offset + i] + if not row then + break + end + if not implementedEffects[row.id] then + implemented = false + break + end + effects[i] = row + row.range = RANGE[row.range] + end + return implemented, effects +end + local function replaceSpells(table) local types = { spell = content.spells.TYPE.Spell, @@ -21,28 +46,15 @@ local function replaceSpells(table) curse = content.spells.TYPE.Curse, power = content.spells.TYPE.Power, } - local range = { - self = content.RANGE.Self, - touch = content.RANGE.Touch, - target = content.RANGE.Target - } local spells = content.spells.records for _, values in pairs(table) do local id = values[1] local type = values[2] local name = values[3] local cost = values[4] - local effects = {} - for i = 1,8 do - local row = values[4 + i] - if not row then - break - end - effects[i] = row - row.range = range[row.range] - end + local implemented, effects = parseEffects(values, 4) local spell = spells[id] - if spell then + if spell and implemented then if cost then spell.cost = cost end @@ -55,6 +67,95 @@ local function replaceSpells(table) end end +local modifiedEnchantments = {} + +local function replaceEnchantments(table) + local types = { + castOnce = content.enchantments.TYPE.CastOnce, + onStrike = content.enchantments.TYPE.CastOnStrike, + onUse = content.enchantments.TYPE.CastOnUse, + constant = content.enchantments.TYPE.ConstantEffect, + } + local enchantments = content.enchantments.records + for _, values in pairs(table) do + local id = values[1] + local type = values[2] + local implemented, effects = parseEffects(values, 2) + local enchantment = enchantments[id] + if enchantment and implemented then + modifiedEnchantments[enchantment.id] = true + enchantment.type = types[type] + enchantment.effects = effects + end + end +end + +local function replacePotions(table) + local potions = content.potions.records + for _, values in pairs(table) do + local id = values[1] + local name = values[2] + local implemented, effects = parseEffects(values, 2) + local potion = potions[id] + if potion and implemented then + if name then + potion.name = t(name) + end + potion.effects = effects + end + end +end + +local enchantableTypes = { 'armor', 'books', 'clothes', 'weapons' } + +local function getItem(id) + for _, type in pairs(enchantableTypes) do + local c = content[type] + if c then + local item = c.records[id] + if item then + return item + end + end + end +end + +local function editItems(table) + for _, values in pairs(table) do + local id = values[1] + local name = values[2] + local value = values[3] + local item = getItem(id) + if item and modifiedEnchantments[item.enchant] then + if name then + item.name = t(name) + end + if value then + item.value = value + end + end + end +end + +local function replaceIngredients(table) + local ingredients = content.ingredients.records + for _, values in pairs(table) do + local id = values[1] + local ingredient = ingredients[id] + if ingredient then + for i = 1,4 do + local row = values[i + 1] + if row and implementedEffects[row.id] then + local effect = ingredient.effects[i] + effect.id = row.id + effect.affectedAttribute = row.attribute or '' + effect.affectedSkill = row.skill or '' + end + end + end + end +end + local function addSummons() local effects = content.magicEffects.records for _, values in pairs(magicData.td_summon_effects) do @@ -63,6 +164,7 @@ local function addSummons() template = 'summonbear' end effects[id] = { template = effects[template], cost = cost, icon = icon, name = t(name), description = t(desc), allowsSpellmaking = true, allowsEnchanting = true } + implementedEffects[id] = true end end @@ -71,8 +173,12 @@ return { onContentFilesLoaded = function() if version_check.isFeatureEnabled('summoningSpells') then addSummons() - replaceSpells(magicData.td_summon_spells) end + replaceSpells(magicData.td_summon_spells) + replaceEnchantments(magicData.td_enchantments) + editItems(magicData.td_enchanted_items) + replacePotions(magicData.td_potions) + replaceIngredients(magicData.td_ingredients) end } } diff --git a/Data Files/scripts/TamrielData/utils/feature_data.lua b/Data Files/scripts/TamrielData/utils/feature_data.lua index 7ee5801..0a0636d 100644 --- a/Data Files/scripts/TamrielData/utils/feature_data.lua +++ b/Data Files/scripts/TamrielData/utils/feature_data.lua @@ -19,7 +19,7 @@ features["miscSpells"] = { settingsKey = "Settings_TamrielData_page01Main_group02Magic_miscSpells" } features["summoningSpells"] = { - requiredLuaApi = 126, + requiredLuaApi = 128, settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic", settingsEnabledByDefault = true, settingsKey = "Settings_TamrielData_page01Main_group02Magic_summoningSpells" From 5a56df1c13d824d4ca01ac8e65b8d56de1b20de7 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 11 Apr 2026 19:49:57 +0200 Subject: [PATCH 09/12] Account for load order changes --- .../scripts/TamrielData/actor_magic.lua | 1 + .../scripts/TamrielData/actor_summons.lua | 8 +++--- .../scripts/TamrielData/global_magic.lua | 20 ++++++++++---- .../scripts/TamrielData/global_summons.lua | 27 +++++++++++++++---- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Data Files/scripts/TamrielData/actor_magic.lua b/Data Files/scripts/TamrielData/actor_magic.lua index bd69ee9..b405ce6 100644 --- a/Data Files/scripts/TamrielData/actor_magic.lua +++ b/Data Files/scripts/TamrielData/actor_magic.lua @@ -1,4 +1,5 @@ local core = require('openmw.core') +local self = require('openmw.self') return { engineHandlers = { diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua index acfd683..9bb6a35 100644 --- a/Data Files/scripts/TamrielData/actor_summons.lua +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -44,17 +44,17 @@ return { T_GetSummonPosition = function(data) local position = getSafeSpawn() data.position = position - data.caster = self.object core.sendGlobalEvent('T_Summon', data) end, T_MarkSummon = function(data) state.caster = data.caster - state.key = data.key + state.id = data.id + state.index = data.index self.type.stats.ai.fight(self).base = 30 -- we should probably be using dedicated creature variants end, Died = function() - if state.key ~= nil then - core.sendGlobalEvent('T_Unsummon', { creature = self.object, caster = state.caster, key = state.key }) + if state.caster ~= nil then + core.sendGlobalEvent('T_Unsummon', { creature = self.object, caster = state.caster, id = state.id, index = state.index }) end end }, diff --git a/Data Files/scripts/TamrielData/global_magic.lua b/Data Files/scripts/TamrielData/global_magic.lua index 121b998..f1640c8 100644 --- a/Data Files/scripts/TamrielData/global_magic.lua +++ b/Data Files/scripts/TamrielData/global_magic.lua @@ -33,6 +33,8 @@ local STATE_ACTIVE = 1 local STATE_ONCE = 2 local STATE_IGNORE = 3 +local MAX_WAIT = 0.25 + local appliedOnce = {} for _, effect in pairs(core.magic.effects.records) do if effect.isAppliedOnce then @@ -55,7 +57,7 @@ local function initActorState(actor, state) state.spells[spell.activeSpellId] = effects end return { - waited = math.random(), + waited = math.random() * MAX_WAIT, activeSpells = activeSpells } end @@ -75,13 +77,14 @@ local function getActorState(actor, init) end state = { delayUpdateChecks = true, - spells = {} + spells = {}, + actor = actor } persistentState.actors[id] = state tempState[id] = initActorState(actor, state) elseif not tempState[id] then tempState[id] = { - waited = math.random(), + waited = math.random() * MAX_WAIT, activeSpells = types.Actor.activeSpells(actor) } end @@ -122,6 +125,8 @@ local function updateEffects(actor, state, tempState) s = STATE_ACTIVE effects[index] = s end + elseif s == STATE_ONCE then + canDiscard = false end if s == STATE_ACTIVE then if onEffectUpdate(actor, spell, effect) then @@ -154,8 +159,6 @@ local function updateEffects(actor, state, tempState) return canDiscard end -local MAX_WAIT = 0.25 - local function waitOrUpdate(actor, dt) local state, tempState = getActorState(actor, true) if state.delayUpdateChecks then @@ -179,6 +182,13 @@ return { onLoad = function(data) if data then persistentState = data + local actors = {} + for id, actorData in pairs(data.actors) do + if actorData.actor:isValid() then + actors[actorData.actor.id] = actorData + end + end + persistentState.actors = actors end end, onUpdate = function(dt) diff --git a/Data Files/scripts/TamrielData/global_summons.lua b/Data Files/scripts/TamrielData/global_summons.lua index bbe39f5..78719c4 100644 --- a/Data Files/scripts/TamrielData/global_summons.lua +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -32,7 +32,7 @@ I.T_ActorMagic.addEffectStartHandler(function(caster, spell, effect, track) local id = spell.activeSpellId local index = effect.index local key = toKey(caster, id, index) - state.summons[key] = { id = id, index = index, creatureId = creature } + state.summons[key] = { id = id, index = index, creatureId = creature, actor = caster } caster:sendEvent('T_GetSummonPosition', { key = key }) track.ignore = false end) @@ -56,6 +56,22 @@ I.T_ActorMagic.addEffectEndHandler(function(actor, id, index) end) return { + engineHandlers = { + onSave = function() + return state + end, + onLoad = function(data) + if data then + state = data + local summons = {} + for _, actorData in pairs(data.summons) do + local key = toKey(actorData.actor, actorData.id, actorData.index) + summons[key] = actorData + end + state.summons = summons + end + end + }, eventHandlers = { T_Summon = function(data) local effect = state.summons[data.key] @@ -63,19 +79,20 @@ return { return end local creature = world.createObject(effect.creatureId) - local caster = data.caster + local caster = effect.actor creature:teleport(caster.cell.name, data.position, { onGround = true }) creature:sendEvent('StartAIPackage', { type = 'Follow', target = caster }) - creature:sendEvent('T_MarkSummon', { key = data.key, caster = caster }) + creature:sendEvent('T_MarkSummon', { index = effect.index, id = effect.id, caster = caster }) creature:sendEvent('AddVfx', { model = startVfx }) effect.creatureId = nil effect.creature = creature end, T_Unsummon = function(data) unsummon(data.creature) - local effect = state.summons[data.key] + local key = toKey(data.caster, data.id, data.index) + local effect = state.summons[key] if effect then - state.summons[data.key] = nil + state.summons[key] = nil I.T_ActorMagic.removeEffect(data.caster, effect.id, effect.index) end end From 1fc3ed00bd59519d9b52d1ac6bb90841b6b35985 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 12 Apr 2026 10:22:26 +0200 Subject: [PATCH 10/12] Delete summons instead of disabling them --- .../scripts/TamrielData/global_summons.lua | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Data Files/scripts/TamrielData/global_summons.lua b/Data Files/scripts/TamrielData/global_summons.lua index 78719c4..3f01b65 100644 --- a/Data Files/scripts/TamrielData/global_summons.lua +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -38,8 +38,10 @@ I.T_ActorMagic.addEffectStartHandler(function(caster, spell, effect, track) end) local function unsummon(creature) - creature.enabled = false - world.vfx.spawn(startVfx, creature.position) + if creature:isValid() then + world.vfx.spawn(startVfx, creature.position) + creature:remove() + end end I.T_ActorMagic.addEffectEndHandler(function(actor, id, index) @@ -49,7 +51,7 @@ I.T_ActorMagic.addEffectEndHandler(function(actor, id, index) return end local creature = summon.creature - if creature and creature:isValid() then + if creature then unsummon(creature) end state.summons[key] = nil @@ -65,8 +67,12 @@ return { state = data local summons = {} for _, actorData in pairs(data.summons) do - local key = toKey(actorData.actor, actorData.id, actorData.index) - summons[key] = actorData + if actorData.actor:isValid() then + local key = toKey(actorData.actor, actorData.id, actorData.index) + summons[key] = actorData + elseif actorData.creature then + unsummon(actorData.creature) + end end state.summons = summons end From 658504a52d7999151487117f2351d34a192261bd Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 14 Apr 2026 17:29:04 +0200 Subject: [PATCH 11/12] Switch to nicer syntax --- Data Files/scripts/TamrielData/load_magic.lua | 4 ++-- Data Files/scripts/TamrielData/utils/feature_data.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Data Files/scripts/TamrielData/load_magic.lua b/Data Files/scripts/TamrielData/load_magic.lua index 0eeb72f..118206d 100644 --- a/Data Files/scripts/TamrielData/load_magic.lua +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -148,8 +148,8 @@ local function replaceIngredients(table) if row and implementedEffects[row.id] then local effect = ingredient.effects[i] effect.id = row.id - effect.affectedAttribute = row.attribute or '' - effect.affectedSkill = row.skill or '' + effect.affectedAttribute = row.attribute + effect.affectedSkill = row.skill end end end diff --git a/Data Files/scripts/TamrielData/utils/feature_data.lua b/Data Files/scripts/TamrielData/utils/feature_data.lua index 0a0636d..5331ef0 100644 --- a/Data Files/scripts/TamrielData/utils/feature_data.lua +++ b/Data Files/scripts/TamrielData/utils/feature_data.lua @@ -19,7 +19,7 @@ features["miscSpells"] = { settingsKey = "Settings_TamrielData_page01Main_group02Magic_miscSpells" } features["summoningSpells"] = { - requiredLuaApi = 128, + requiredLuaApi = 129, settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic", settingsEnabledByDefault = true, settingsKey = "Settings_TamrielData_page01Main_group02Magic_summoningSpells" From f63aa311ef4842e42ff397291e51d0404fce5c45 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 15 Apr 2026 19:28:19 +0200 Subject: [PATCH 12/12] Fix typo --- Data Files/scripts/TamrielData/load_magic.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data Files/scripts/TamrielData/load_magic.lua b/Data Files/scripts/TamrielData/load_magic.lua index 118206d..66872d9 100644 --- a/Data Files/scripts/TamrielData/load_magic.lua +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -159,7 +159,7 @@ end local function addSummons() local effects = content.magicEffects.records for _, values in pairs(magicData.td_summon_effects) do - local id, name, creature, cost, icon, description, template = unpack(values) + local id, name, creature, cost, icon, desc, template = unpack(values) if template == 'callBear' then template = 'summonbear' end