diff --git a/Data Files/MWSE/mods/TamrielData/magic.lua b/Data Files/MWSE/mods/TamrielData/magic.lua index f986f2f..ec7cee5 100644 --- a/Data Files/MWSE/mods/TamrielData/magic.lua +++ b/Data Files/MWSE/mods/TamrielData/magic.lua @@ -110,44 +110,6 @@ end local magicData = require("TamrielData.magicdata") --- race id, isFemale, distraction voice files, distraction end voice lines -local distractedVoiceLines = { - { "Argonian", false, { "vo\\a\\m\\Idl_AM001.mp3", "vo\\a\\m\\Hlo_AM056.mp3" }, { "vo\\a\\m\\Idl_AM008.mp3" } }, - { "Argonian", true, { "vo\\a\\f\\Idl_AF007.mp3", "vo\\a\\f\\Idl_AF004.mp3" }, { "vo\\a\\f\\Idl_AF002.mp3" } }, - { "Breton", false, { }, { } }, - { "Breton", true, { "vo\\b\\f\\Idl_BF001.mp3", "vo\\b\\f\\Idl_BF005.mp3" }, { "vo\\b\\f\\Idl_BF003.mp3" } }, - { "Dark Elf", false, { "vo\\d\\m\\Idl_DM006.mp3", "vo\\d\\m\\Idl_DM007.mp3" }, { "vo\\d\\m\\Idl_DM008.mp3" } }, - { "Dark Elf", true, { "vo\\d\\f\\Idl_DF006.mp3" }, { "vo\\d\\f\\Idl_DF003.mp3" } }, - { "High Elf", false, { "vo\\h\\m\\Hlo_HM056.mp3" }, { "vo\\i\\m\\Idl_HF007.mp3" } }, - { "High Elf", true, { "vo\\h\\f\\Hlo_HF056.mp3" }, { "vo\\i\\f\\Idl_HF007.mp3" } }, - { "Imperial", false, { "vo\\i\\m\\Idl_IM008.mp3" }, { "vo\\i\\m\\Idl_IM005.mp3" } }, - { "Imperial", true, { "vo\\i\\f\\Idl_IF001.mp3" }, { "vo\\i\\f\\Idl_IF009.mp3" } }, - { "Khajiit", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "Khajiit", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Cathay", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Cathay-raht", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Dagi-raht", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Ohmes", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Ohmes-raht", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Suthay", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Tojay", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, - { "T_Els_Cathay", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Cathay-raht", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Dagi-raht", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Ohmes", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Ohmes-raht", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Suthay", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "T_Els_Tojay", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, - { "Nord", false, { "vo\\n\\m\\Idl_NM001.mp3" }, { "vo\\n\\m\\Idl_NM009.mp3" } }, - { "Nord", true, { "vo\\n\\f\\Idl_NF002.mp3", "vo\\n\\f\\Idl_NF004.mp3" }, { "vo\\n\\f\\Idl_NM008.mp3" } }, - { "Orc", false, { "vo\\o\\m\\Idl_OM001.mp3", "vo\\o\\m\\Idl_OM002.mp3" }, { "vo\\o\\m\\Idl_OM004.mp3", "vo\\o\\m\\Idl_OM009.mp3" } }, - { "Orc", true, { "vo\\o\\f\\Idl_OF009.mp3" }, { } }, - { "Redguard", false, { }, { } }, - { "Redguard", true, { "vo\\r\\f\\Idl_RF002.mp3", "vo\\r\\f\\Idl_RF008.mp3" }, { "vo\\r\\f\\Idl_RF003.mp3", "vo\\r\\f\\Idl_RF007.mp3" } }, - { "Wood Elf", false, { "vo\\w\\m\\Idl_WM009.mp3" }, { "vo\\w\\m\\Idl_WM006.mp3", "vo\\w\\m\\Idl_WM007.mp3" } }, - { "Wood Elf", true, { "vo\\w\\f\\Idl_WF006.mp3", "vo\\w\\f\\Idl_WF009.mp3" }, { "vo\\w\\f\\Idl_WF003.mp3", "vo\\w\\f\\Idl_WF007.mp3" } }, -} - local prismaticReferences = {} local distractedReferences = {} -- Should probably decide on a consistent naming scheme for tables @@ -252,35 +214,6 @@ local raceSkeletonBodyParts = { { "T_Yne_Ynesai", "T_B_GazeVeloth_Skeleton_01", "T_C_GazeVeloth_Skeleton_01" }, -- Imga and Tsaesci skeletons will take more effort } -local wabbajackCreatures = { - "T_Mw_UNI_GrahlWabbajack", -- This version of the Grahl does not have fireregenScript attached to it; I saw a crash occur while it was being executed, but I am not sure why. - "scamp", - "T_Glb_Cre_LandDreu_01", - "T_Glb_Cre_TrollCave_03", - "mudcrab", - "T_Ham_Fau_Goat_01", - "Rat", - "golden saint" -} - -local sanguineRoseDaedra = { - "dremora_summon", - "T_Dae_Cre_Seduc_01", - "atronach_flame", - "atronach_frost", - "atronach_storm", - "scamp_summon", - "T_Dae_Cre_Verm_01", - "clannfear_summon", - "T_Dae_Cre_Herne_01", - "T_Dae_Cre_Morphoid_01", - "T_Dae_Cre_SpiderDae_01", - "hunger_summon", - "winged twilight_summon", - "golden saint_summon", - "daedroth_summon", -} - -- actor id local gazeOfVelothImmuneActors = { ["vivec_god"] = true, @@ -291,48 +224,6 @@ local gazeOfVelothImmuneActors = { ["Sky_qRe_KWMG6_Azra"] = true, } --- script id -local safeScripts = { - ["nolore"] = true, - ["slaveScript"] = true, - ["fortloreboozeScript"] = true, - ["TR_m3_Kha_Methats_sc"] = true, - ["TR_m3_NPC_OE_commonNoLore"] = true, - ["TR_m3_NPC_OE_poorNoLore"] = true, - ["TR_m3_NPC_OE_richNoLore"] = true, - ["TR_m3_NPC_OE_towerNoLore"] = true, - ["TR_m4_AA_Vf_NPC_NoLoresc"] = true, - ["TR_m7_NPC_RuddyEggsNoLore"] = true, - ["TR_m7_Ns_KhanVolnyr_sc"] = true, - ["TR_m3_q_kharg"] = true, - ["TR_m3_Kha_AtroLordDis_sc"] = true, - ["TR_m3_Kha_Black_Heart_Script"] = true, - ["TR_m3_Kha_ClannLordDis_sc"] = true, - ["TR_m3_Kha_FireScamp_sc"] = true, - ["TR_m1_Lornie_Slave_scpt"] = true, - ["TR_m4_OranSlave_Sc"] = true, - ["TR_m1_T_CouncilorSc"] = true, - ["TR_m2_T_CouncilorSc"] = true, - ["TR_NecMQ_MovingNPCScript"] = true, - ["TR_m1_FW_TG3_HrongalDrink"] = true, - ["TR_m1_MinTalScript"] = true, - ["TR_m1_NPC_DiceGambler"] = true, - ["TR_m2_NPC_DiceGambler"] = true, - ["TR_m3_NPC_DiceGambler"] = true, - ["TR_m3_NPC_DiceGamblerNoLore"] = true, - ["TR_m3_NPC_DiceGamblerOECom"] = true, - ["TR_m3_NPC_DiceGamblerOEPoor"] = true, - ["TR_m4_NPC_DiceGambler"] = true, - ["TR_m5_NPC_DiceGambler"] = true, - ["TR_m6_NPC_DiceGambler"] = true, - ["TR_m7_NPC_DiceGambler"] = true, - ["TR_m1_NPC_Fervas_Shulisa"] = true, - ["TR_m1_NPC_Gilen_Indothan"] = true, - ["TR_m1_NPC_Malvas_Relvani"] = true, - ["TR_m1_T_Seducer"] = true, - ["TR_m3_q_vampambush"] = true, -} - ---@param table table function this.replaceSpells(table) for _,v in pairs(table) do @@ -1474,7 +1365,7 @@ end ---@param isEnd boolean local function playDistractedVoiceLine(ref, isEnd) if ref.mobile.actorType == tes3.actorType.npc and not ref.mobile.hasVampirism then - for _,v in pairs(distractedVoiceLines) do + for _,v in pairs(magicData.distractedVoiceLines) do local raceID, isFemale, voicesStart, voicesEnd = unpack(v) if ref.baseObject.race.id == raceID and ref.baseObject.female == isFemale then local voices @@ -1763,7 +1654,7 @@ local function corruptionEffect(e) local target = e.effectInstance.target if target.id ~= tes3.player.data.tamrielData.corruptionReferenceID then -- Memory errors can be reported if the effect is applied to the summon and doing so is weird anyways - if target.baseObject.script and (not ((target.baseObject.script.id:find("T_ScNpc") and not target.baseObject.script.id:find("_Were")) or safeScripts[target.baseObject.script.id]) or hasScriptedItem(target.mobile.inventory)) then -- Checks whether the target has a scripted item or a script that is not known to be safely cloneable + if target.baseObject.script and (not ((target.baseObject.script.id:find("T_ScNpc") and not target.baseObject.script.id:find("_Were")) or magicData.safeScripts[target.baseObject.script.id]) or hasScriptedItem(target.mobile.inventory)) then -- Checks whether the target has a scripted item or a script that is not known to be safely cloneable tes3ui.showNotifyMenu(common.i18n("magic.corruptionScript", { target.object.name })) e.effectInstance.state = tes3.spellState.retired restoreCharge(e.sourceInstance) @@ -2514,7 +2405,7 @@ local function wabbajackEffect(e) local targetFatigue = target.mobile.fatigue.normalized local targetMagicka = target.mobile.magicka.normalized - local transformCreature = tes3.getObject(wabbajackCreatures[math.random(#wabbajackCreatures)]) + local transformCreature = tes3.getObject(magicData.wabbajackCreatures[math.random(#magicData.wabbajackCreatures)]) local transformedTarget = tes3.createReference({ object = transformCreature, position = target.position, orientation = target.orientation, cell = target.cell }) -- Could this setup and the WabbajackTrans effect actually be done through a summon like the Corruption effect does? transformedTarget.data.tamrielData = transformedTarget.data.tamrielData or {} @@ -3238,42 +3129,55 @@ event.register(tes3.event.magicEffectsResolved, function() if config.miscSpells then local passwallBaseEffect = tes3.getMagicEffect(tes3.effect.detectAnimal) - local passwallSchool = tes3.magicSchool.mysticism if passwallAlteration then passwallBaseEffect = tes3.getMagicEffect(tes3.effect.levitate) - passwallSchool = tes3.magicSchool.alteration end - local soultrapEffect = tes3.getMagicEffect(tes3.effect.soultrap) - local reflectEffect = tes3.getMagicEffect(tes3.effect.reflect) - local detectEffect = tes3.getMagicEffect(tes3.effect.detectAnimal) local shieldEffect = tes3.getMagicEffect(tes3.effect.shield) - local burdenEffect = tes3.getMagicEffect(tes3.effect.burden) - local restoreEffect = tes3.getMagicEffect(tes3.effect.fortifyHealth) -- The fortify VFX feels more appropriate for the resartus effects, but perhaps it should still be restoration? - local summonDremoraEffect = tes3.getMagicEffect(tes3.effect.summonDremora) - local blindEffect = tes3.getMagicEffect(tes3.effect.blind) - local damageHealthEffect = tes3.getMagicEffect(tes3.effect.damageHealth) - local fortifyAttackEffect = tes3.getMagicEffect(tes3.effect.fortifyAttack) - local lightEffect = tes3.getMagicEffect(tes3.effect.light) - - local effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[1]) -- Passwall - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + + local function addMiscEffect(effectID, params, templateOverride) + local effectName, effectCost, iconPath, effectDescription, templateId = unpack(magicData.td_misc_effects[effectID]) + params.id = tes3.effect[effectID] + params.name = common.i18n("magic." .. effectName) + params.description = common.i18n("magic." .. effectDescription) + params.baseCost = effectCost + if not params.icon then + params.icon = iconPath + end + local template = templateOverride or tes3.getMagicEffect(tes3.effect[templateId]) + if template then + for _, key in pairs({ "school", "speed", "casterLinked", "usesNegativeLighting", "particleTexture", + "size", "sizeCap", "hasContinuousVFX", "illegalDaedra", "targetsAttributes", "targetsSkills", + "allowEnchanting", "allowSpellmaking", "appliesOnce", "canCastSelf", "canCastTarget", "canCastTouch", + "hasNoDuration", "hasNoMagnitude", "isHarmful", "nonRecastable", "unreflectable" }) do + if params[key] == nil then + params[key] = template[key] + end + end + if not params.lighting then + params.lighting = {x = template.lightingRed / 255, y = template.lightingGreen / 255, z = template.lightingBlue / 255} + end + for key1, key2 in pairs({ boltSound = "boltSoundEffect", boltVFX = "boltVisualEffect", hitSound = "hitSoundEffect", + hitVFX = "hitVisualEffect", areaSound = "areaSoundEffect", areaVFX = "areaVisualEffect", castSound = "castSoundEffect", + castVFX = "castVisualEffect" }) do + if params[key1] == nil then + params[key1] = template[key2].id + end + end + end + tes3.addMagicEffect(params) + end + + addMiscEffect("T_mysticism_Passwall", { --magnitudeType = " " .. tes3.findGMST(tes3.gmst.sfeet).value, -- Passwall is currently set up to not have a magnitude and works off of the effect's area instead --magnitudeTypePlural = " " .. tes3.findGMST(tes3.gmst.sfeet).value, - school = passwallSchool, - baseCost = effectCost, - speed = passwallBaseEffect.speed, allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = false, canCastTarget = false, canCastTouch = true, - casterLinked = passwallBaseEffect.casterLinked, hasContinuousVFX = false, hasNoDuration = true, hasNoMagnitude = true, @@ -3283,265 +3187,107 @@ event.register(tes3.event.magicEffectsResolved, function() targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = passwallBaseEffect.usesNegativeLighting, icon = passwallIcon, - particleTexture = passwallBaseEffect.particleTexture, - castSound = passwallBaseEffect.castSoundEffect.id, - castVFX = passwallBaseEffect.castVisualEffect.id, boltSound = "T_SndObj_Silence", boltVFX = "T_VFX_Empty", hitSound = "T_SndObj_Silence", hitVFX = "T_VFX_Empty", -- Currently has to use VFX because otherwise Morrowind crashes when casting the effect on some actors despite this parameter being "optional" areaSound = "T_SndObj_Silence", areaVFX = "T_VFX_Empty", -- Problems can apparently still arise from missing boltVFX and areaVFX for some people - lighting = {x = passwallBaseEffect.lightingRed / 255, y = passwallBaseEffect.lightingGreen / 255, z = passwallBaseEffect.lightingBlue / 255}, - size = passwallBaseEffect.size, - sizeCap = passwallBaseEffect.sizeCap, onTick = function(eventData) eventData:trigger() end, onCollision = nil - } + }, passwallBaseEffect) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[2]) -- Banish Daedra - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = soultrapEffect.speed, + addMiscEffect("T_mysticism_BanishDae", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = false, canCastTarget = true, canCastTouch = true, - casterLinked = soultrapEffect.casterLinked, - hasContinuousVFX = soultrapEffect.hasContinuousVFX, hasNoDuration = true, hasNoMagnitude = false, - illegalDaedra = soultrapEffect.illegalDaedra, isHarmful = false, nonRecastable = true, - targetsAttributes = soultrapEffect.targetsAttributes, - targetsSkills = soultrapEffect.targetsSkills, unreflectable = true, - usesNegativeLighting = soultrapEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = soultrapEffect.particleTexture, - castSound = soultrapEffect.castSoundEffect.id, - castVFX = soultrapEffect.castVisualEffect.id, - boltSound = soultrapEffect.boltSoundEffect.id, - boltVFX = soultrapEffect.boltVisualEffect.id, hitSound = "T_SndObj_Silence", hitVFX = "T_VFX_Empty", areaSound = "T_SndObj_Silence", areaVFX = "T_VFX_Empty", - lighting = {x = soultrapEffect.lightingRed / 255, y = soultrapEffect.lightingGreen / 255, z = soultrapEffect.lightingBlue / 255}, - size = soultrapEffect.size, - sizeCap = soultrapEffect.sizeCap, onTick = banishDaedraEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[3]) -- Reflect Damage - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + addMiscEffect("T_mysticism_ReflectDmg", { magnitudeType = tes3.findGMST(tes3.gmst.spercent).value, magnitudeTypePlural = tes3.findGMST(tes3.gmst.spercent).value, - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = reflectEffect.speed, - allowEnchanting = reflectEffect.allowEnchanting, - allowSpellmaking = reflectEffect.allowSpellmaking, - appliesOnce = reflectEffect.appliesOnce, - canCastSelf = reflectEffect.canCastSelf, - canCastTarget = reflectEffect.canCastTarget, - canCastTouch = reflectEffect.canCastTouch, - casterLinked = reflectEffect.casterLinked, - hasContinuousVFX = reflectEffect.hasContinuousVFX, - hasNoDuration = reflectEffect.hasNoDuration, - hasNoMagnitude = reflectEffect.hasNoMagnitude, - illegalDaedra = reflectEffect.illegalDaedra, - isHarmful = reflectEffect.isHarmful, - nonRecastable = reflectEffect.nonRecastable, - targetsAttributes = reflectEffect.targetsAttributes, - targetsSkills = reflectEffect.targetsSkills, - unreflectable = reflectEffect.unreflectable, - usesNegativeLighting = reflectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = reflectEffect.particleTexture, - castSound = reflectEffect.castSoundEffect.id, - castVFX = reflectEffect.castVisualEffect.id, - boltSound = reflectEffect.boltSoundEffect.id, - boltVFX = reflectEffect.boltVisualEffect.id, - hitSound = reflectEffect.hitSoundEffect.id, - hitVFX = reflectEffect.hitVisualEffect.id, - areaSound = reflectEffect.areaSoundEffect.id, - areaVFX = reflectEffect.areaVisualEffect.id, - lighting = {x = reflectEffect.lightingRed / 255, y = reflectEffect.lightingGreen / 255, z = reflectEffect.lightingBlue / 255}, - size = reflectEffect.size, - sizeCap = reflectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[4]) -- Detect Humanoid - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + addMiscEffect("T_mysticism_DetHuman", { magnitudeType = " " .. tes3.findGMST(tes3.gmst.sfeet).value, magnitudeTypePlural = " " .. tes3.findGMST(tes3.gmst.sfeet).value, - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, - hasContinuousVFX = detectEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, - hitSound = detectEffect.hitSoundEffect.id, - hitVFX = detectEffect.hitVisualEffect.id, - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, - lighting = {x = detectEffect.lightingRed / 255, y = detectEffect.lightingGreen / 255, z = detectEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[5]) -- Radiant Shield - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.alteration, - baseCost = effectCost, - speed = shieldEffect.speed, - allowEnchanting = shieldEffect.allowEnchanting, - allowSpellmaking = shieldEffect.allowSpellmaking, - appliesOnce = shieldEffect.appliesOnce, - canCastSelf = shieldEffect.canCastSelf, - canCastTarget = shieldEffect.canCastTarget, - canCastTouch = shieldEffect.canCastTouch, - casterLinked = shieldEffect.casterLinked, - hasContinuousVFX = shieldEffect.hasContinuousVFX, - hasNoDuration = shieldEffect.hasNoDuration, - hasNoMagnitude = shieldEffect.hasNoMagnitude, - illegalDaedra = shieldEffect.illegalDaedra, - isHarmful = shieldEffect.isHarmful, - nonRecastable = shieldEffect.nonRecastable, - targetsAttributes = shieldEffect.targetsAttributes, - targetsSkills = shieldEffect.targetsSkills, - unreflectable = shieldEffect.unreflectable, - usesNegativeLighting = shieldEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = shieldEffect.particleTexture, - castSound = shieldEffect.castSoundEffect.id, - castVFX = shieldEffect.castVisualEffect.id, - boltSound = shieldEffect.boltSoundEffect.id, - boltVFX = shieldEffect.boltVisualEffect.id, - hitSound = shieldEffect.hitSoundEffect.id, + addMiscEffect("T_alteration_RadShield", { hitVFX = "T_VFX_RadiantShieldHit", - areaSound = shieldEffect.areaSoundEffect.id, - areaVFX = shieldEffect.areaVisualEffect.id, lighting = {x = 128, y = 128, z = 128}, - size = shieldEffect.size, - sizeCap = shieldEffect.sizeCap, onTick = radiantShieldEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[6]) -- Wabbajack - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.alteration, - baseCost = effectCost, - speed = burdenEffect.speed, + addMiscEffect("T_alteration_Wabbajack", { allowEnchanting = false, allowSpellmaking = false, appliesOnce = true, canCastSelf = false, canCastTarget = true, canCastTouch = false, - casterLinked = burdenEffect.casterLinked, - hasContinuousVFX = burdenEffect.hasContinuousVFX, hasNoDuration = true, hasNoMagnitude = true, - illegalDaedra = burdenEffect.illegalDaedra, isHarmful = true, nonRecastable = true, targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = burdenEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = burdenEffect.particleTexture, - castSound = burdenEffect.castSoundEffect.id, - castVFX = burdenEffect.castVisualEffect.id, - boltSound = burdenEffect.boltSoundEffect.id, - boltVFX = burdenEffect.boltVisualEffect.id, hitSound = "T_SndObj_Silence", hitVFX = "T_VFX_Empty", areaSound = "T_SndObj_Silence", areaVFX = "T_VFX_Empty", - lighting = {x = burdenEffect.lightingRed / 255, y = burdenEffect.lightingGreen / 255, z = burdenEffect.lightingBlue / 255}, - size = burdenEffect.size, - sizeCap = burdenEffect.sizeCap, onTick = wabbajackEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[7]) -- Wabbajack Helper - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.alteration, - baseCost = effectCost, - speed = burdenEffect.speed, + addMiscEffect("T_alteration_WabbajackHelper", { allowEnchanting = false, allowSpellmaking = false, appliesOnce = true, canCastSelf = false, canCastTarget = true, canCastTouch = true, - casterLinked = burdenEffect.casterLinked, - hasContinuousVFX = burdenEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = burdenEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = burdenEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = burdenEffect.particleTexture, castSound = "T_SndObj_Silence", castVFX = "T_VFX_Empty", boltSound = "T_SndObj_Silence", @@ -3550,780 +3296,335 @@ event.register(tes3.event.magicEffectsResolved, function() hitVFX = "T_VFX_Empty", areaSound = "T_SndObj_Silence", areaVFX = "T_VFX_Empty", - lighting = {x = burdenEffect.lightingRed / 255, y = burdenEffect.lightingGreen / 255, z = burdenEffect.lightingBlue / 255}, - size = burdenEffect.size, - sizeCap = burdenEffect.sizeCap, onTick = wabbajackHelperEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[8]) -- Insight - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = reflectEffect.speed, + addMiscEffect("T_mysticism_Insight", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = reflectEffect.casterLinked, - hasContinuousVFX = reflectEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = reflectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = reflectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = reflectEffect.particleTexture, - castSound = reflectEffect.castSoundEffect.id, - castVFX = reflectEffect.castVisualEffect.id, - boltSound = reflectEffect.boltSoundEffect.id, - boltVFX = reflectEffect.boltVisualEffect.id, - hitSound = reflectEffect.hitSoundEffect.id, - hitVFX = reflectEffect.hitVisualEffect.id, - areaSound = reflectEffect.areaSoundEffect.id, - areaVFX = reflectEffect.areaVisualEffect.id, - lighting = {x = reflectEffect.lightingRed / 255, y = reflectEffect.lightingGreen / 255, z = reflectEffect.lightingBlue / 255}, - size = reflectEffect.size, - sizeCap = reflectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[9]) -- Armor Resartus - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.restoration, - baseCost = effectCost, - speed = restoreEffect.speed, + addMiscEffect("T_restoration_ArmorResartus", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = restoreEffect.casterLinked, - hasContinuousVFX = restoreEffect.hasContinuousVFX, hasNoDuration = true, hasNoMagnitude = false, - illegalDaedra = restoreEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = restoreEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = restoreEffect.particleTexture, - castSound = restoreEffect.castSoundEffect.id, - castVFX = restoreEffect.castVisualEffect.id, - boltSound = restoreEffect.boltSoundEffect.id, - boltVFX = restoreEffect.boltVisualEffect.id, - hitSound = restoreEffect.hitSoundEffect.id, - hitVFX = restoreEffect.hitVisualEffect.id, - areaSound = restoreEffect.areaSoundEffect.id, - areaVFX = restoreEffect.areaVisualEffect.id, - lighting = {x = restoreEffect.lightingRed / 255, y = restoreEffect.lightingGreen / 255, z = restoreEffect.lightingBlue / 255}, - size = restoreEffect.size, - sizeCap = restoreEffect.sizeCap, onTick = armorResartusEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[10]) -- Weapon Resartus - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.restoration, - baseCost = effectCost, - speed = restoreEffect.speed, + addMiscEffect("T_restoration_WeaponResartus", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = restoreEffect.casterLinked, - hasContinuousVFX = restoreEffect.hasContinuousVFX, hasNoDuration = true, hasNoMagnitude = false, - illegalDaedra = restoreEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = restoreEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = restoreEffect.particleTexture, - castSound = restoreEffect.castSoundEffect.id, - castVFX = restoreEffect.castVisualEffect.id, - boltSound = restoreEffect.boltSoundEffect.id, - boltVFX = restoreEffect.boltVisualEffect.id, - hitSound = restoreEffect.hitSoundEffect.id, - hitVFX = restoreEffect.hitVisualEffect.id, - areaSound = restoreEffect.areaSoundEffect.id, - areaVFX = restoreEffect.areaVisualEffect.id, - lighting = {x = restoreEffect.lightingRed / 255, y = restoreEffect.lightingGreen / 255, z = restoreEffect.lightingBlue / 255}, - size = restoreEffect.size, - sizeCap = restoreEffect.sizeCap, onTick = weaponResartusEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[11]) -- Corruption - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.conjuration, - baseCost = effectCost, - speed = summonDremoraEffect.speed, + addMiscEffect("T_conjuration_Corruption", { allowEnchanting = false, allowSpellmaking = false, appliesOnce = true, canCastSelf = false, canCastTarget = true, canCastTouch = false, - casterLinked = summonDremoraEffect.casterLinked, - hasContinuousVFX = summonDremoraEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = summonDremoraEffect.illegalDaedra, isHarmful = true, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = summonDremoraEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = summonDremoraEffect.particleTexture, - castSound = summonDremoraEffect.castSoundEffect.id, - castVFX = summonDremoraEffect.castVisualEffect.id, - boltSound = summonDremoraEffect.boltSoundEffect.id, - boltVFX = summonDremoraEffect.boltVisualEffect.id, - hitSound = summonDremoraEffect.hitSoundEffect.id, - hitVFX = summonDremoraEffect.hitVisualEffect.id, - areaSound = summonDremoraEffect.areaSoundEffect.id, - areaVFX = summonDremoraEffect.areaVisualEffect.id, - lighting = {x = summonDremoraEffect.lightingRed / 255, y = summonDremoraEffect.lightingGreen / 255, z = summonDremoraEffect.lightingBlue / 255}, - size = summonDremoraEffect.size, - sizeCap = summonDremoraEffect.sizeCap, onTick = corruptionEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[12]) -- Corruption Summon - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.conjuration, - baseCost = effectCost, - speed = summonDremoraEffect.speed, + addMiscEffect("T_conjuration_CorruptionSummon", { allowEnchanting = false, allowSpellmaking = false, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = summonDremoraEffect.casterLinked, - hasContinuousVFX = summonDremoraEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = summonDremoraEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, - unreflectable = summonDremoraEffect.unreflectable, - usesNegativeLighting = summonDremoraEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = summonDremoraEffect.particleTexture, - castSound = summonDremoraEffect.castSoundEffect.id, - castVFX = summonDremoraEffect.castVisualEffect.id, - boltSound = summonDremoraEffect.boltSoundEffect.id, - boltVFX = summonDremoraEffect.boltVisualEffect.id, - hitSound = summonDremoraEffect.hitSoundEffect.id, - hitVFX = summonDremoraEffect.hitVisualEffect.id, - areaSound = summonDremoraEffect.areaSoundEffect.id, - areaVFX = summonDremoraEffect.areaVisualEffect.id, - lighting = {x = summonDremoraEffect.lightingRed / 255, y = summonDremoraEffect.lightingGreen / 255, z = summonDremoraEffect.lightingBlue / 255}, - size = summonDremoraEffect.size, - sizeCap = summonDremoraEffect.sizeCap, onTick = function(eventData) eventData:triggerSummon(corruptionActorID) end, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[13]) -- Distract Creature - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.illusion, - baseCost = effectCost, - speed = blindEffect.speed, + addMiscEffect("T_illusion_DistractCreature", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = false, canCastTarget = true, -- The GUI for making custom magic effects doesn't like just having an effect only work at target range, so the distract spells also work at touch range for now canCastTouch = true, - casterLinked = blindEffect.casterLinked, - hasContinuousVFX = blindEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = blindEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = blindEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = blindEffect.particleTexture, - castSound = blindEffect.castSoundEffect.id, - castVFX = blindEffect.castVisualEffect.id, - boltSound = blindEffect.boltSoundEffect.id, - boltVFX = blindEffect.boltVisualEffect.id, - hitSound = blindEffect.hitSoundEffect.id, - hitVFX = blindEffect.hitVisualEffect.id, - areaSound = blindEffect.areaSoundEffect.id, - areaVFX = blindEffect.areaVisualEffect.id, - lighting = {x = blindEffect.lightingRed / 255, y = blindEffect.lightingGreen / 255, z = blindEffect.lightingBlue / 255}, - size = blindEffect.size, - sizeCap = blindEffect.sizeCap, onTick = distractCreatureEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[14]) -- Distract Humanoid - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.illusion, - baseCost = effectCost, - speed = blindEffect.speed, + addMiscEffect("T_illusion_DistractHumanoid", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = false, canCastTarget = true, canCastTouch = true, - casterLinked = blindEffect.casterLinked, - hasContinuousVFX = blindEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = blindEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = blindEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = blindEffect.particleTexture, - castSound = blindEffect.castSoundEffect.id, - castVFX = blindEffect.castVisualEffect.id, - boltSound = blindEffect.boltSoundEffect.id, - boltVFX = blindEffect.boltVisualEffect.id, - hitSound = blindEffect.hitSoundEffect.id, - hitVFX = blindEffect.hitVisualEffect.id, - areaSound = blindEffect.areaSoundEffect.id, - areaVFX = blindEffect.areaVisualEffect.id, - lighting = {x = blindEffect.lightingRed / 255, y = blindEffect.lightingGreen / 255, z = blindEffect.lightingBlue / 255}, - size = blindEffect.size, - sizeCap = blindEffect.sizeCap, onTick = distractHumanoidEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[15]) -- Gaze of Veloth - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.destruction, - baseCost = effectCost, - speed = damageHealthEffect.speed, + addMiscEffect("T_destruction_GazeOfVeloth", { allowEnchanting = false, allowSpellmaking = false, appliesOnce = true, canCastSelf = false, canCastTarget = true, canCastTouch = true, - casterLinked = damageHealthEffect.casterLinked, - hasContinuousVFX = damageHealthEffect.hasContinuousVFX, hasNoDuration = true, hasNoMagnitude = true, - illegalDaedra = damageHealthEffect.illegalDaedra, isHarmful = true, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = true, - usesNegativeLighting = damageHealthEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = damageHealthEffect.particleTexture, - castSound = damageHealthEffect.castSoundEffect.id, - castVFX = damageHealthEffect.castVisualEffect.id, - boltSound = damageHealthEffect.boltSoundEffect.id, - boltVFX = damageHealthEffect.boltVisualEffect.id, - hitSound = damageHealthEffect.hitSoundEffect.id, - hitVFX = damageHealthEffect.hitVisualEffect.id, - areaSound = damageHealthEffect.areaSoundEffect.id, - areaVFX = damageHealthEffect.areaVisualEffect.id, - lighting = {x = damageHealthEffect.lightingRed / 255, y = damageHealthEffect.lightingGreen / 255, z = damageHealthEffect.lightingBlue / 255}, - size = damageHealthEffect.size, - sizeCap = damageHealthEffect.sizeCap, onTick = gazeOfVelothEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[16]) -- Detect Enemy - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + addMiscEffect("T_mysticism_DetEnemy", { magnitudeType = " " .. tes3.findGMST(tes3.gmst.sfeet).value, magnitudeTypePlural = " " .. tes3.findGMST(tes3.gmst.sfeet).value, - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, - hasContinuousVFX = detectEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, - hitSound = detectEffect.hitSoundEffect.id, - hitVFX = detectEffect.hitVisualEffect.id, - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, - lighting = {x = detectEffect.lightingRed / 255, y = detectEffect.lightingGreen / 255, z = detectEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[17]) -- Detect Invisibility - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + addMiscEffect("T_mysticism_DetInvisibility", { magnitudeType = " " .. tes3.findGMST(tes3.gmst.sfeet).value, magnitudeTypePlural = " " .. tes3.findGMST(tes3.gmst.sfeet).value, - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, - hasContinuousVFX = detectEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, - hitSound = detectEffect.hitSoundEffect.id, - hitVFX = detectEffect.hitVisualEffect.id, - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, - lighting = {x = detectEffect.lightingRed / 255, y = detectEffect.lightingGreen / 255, z = detectEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[18]) -- Blink - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + addMiscEffect("T_mysticism_Blink", { magnitudeType = " " .. tes3.findGMST(tes3.gmst.sfeet).value, magnitudeTypePlural = " " .. tes3.findGMST(tes3.gmst.sfeet).value, - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, - hasContinuousVFX = detectEffect.hasContinuousVFX, hasNoDuration = true, hasNoMagnitude = false, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, hitSound = "T_SndObj_BlinkHit", hitVFX = "T_VFX_Empty", - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, - lighting = {x = detectEffect.lightingRed / 255, y = detectEffect.lightingGreen / 255, z = detectEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = blinkEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[19]) -- Fortify Casting - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.restoration, - baseCost = effectCost, - speed = fortifyAttackEffect.speed, + addMiscEffect("T_restoration_FortifyCasting", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = fortifyAttackEffect.casterLinked, - hasContinuousVFX = fortifyAttackEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = fortifyAttackEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = fortifyAttackEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = fortifyAttackEffect.particleTexture, - castSound = fortifyAttackEffect.castSoundEffect.id, - castVFX = fortifyAttackEffect.castVisualEffect.id, - boltSound = fortifyAttackEffect.boltSoundEffect.id, - boltVFX = fortifyAttackEffect.boltVisualEffect.id, - hitSound = fortifyAttackEffect.hitSoundEffect.id, - hitVFX = fortifyAttackEffect.hitVisualEffect.id, - areaSound = fortifyAttackEffect.areaSoundEffect.id, - areaVFX = fortifyAttackEffect.areaVisualEffect.id, - lighting = {x = fortifyAttackEffect.lightingRed / 255, y = fortifyAttackEffect.lightingGreen / 255, z = fortifyAttackEffect.lightingBlue / 255}, - size = fortifyAttackEffect.size, - sizeCap = fortifyAttackEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[20]) -- Prismatic Light - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.illusion, - baseCost = effectCost, - speed = lightEffect.speed, - allowEnchanting = lightEffect.allowEnchanting, - allowSpellmaking = lightEffect.allowSpellmaking, - appliesOnce = lightEffect.appliesOnce, - canCastSelf = lightEffect.canCastSelf, - canCastTarget = lightEffect.canCastTarget, - canCastTouch = lightEffect.canCastTouch, - casterLinked = lightEffect.casterLinked, - hasContinuousVFX = lightEffect.hasContinuousVFX, - hasNoDuration = lightEffect.hasNoDuration, - hasNoMagnitude = lightEffect.hasNoMagnitude, - illegalDaedra = lightEffect.illegalDaedra, - isHarmful = lightEffect.isHarmful, - nonRecastable = lightEffect.nonRecastable, - targetsAttributes = lightEffect.targetsAttributes, - targetsSkills = lightEffect.targetsSkills, - unreflectable = lightEffect.unreflectable, - usesNegativeLighting = lightEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = lightEffect.particleTexture, - castSound = lightEffect.castSoundEffect.id, - castVFX = lightEffect.castVisualEffect.id, - boltSound = lightEffect.boltSoundEffect.id, - boltVFX = lightEffect.boltVisualEffect.id, - hitSound = lightEffect.hitSoundEffect.id, - hitVFX = lightEffect.hitVisualEffect.id, - areaSound = lightEffect.areaSoundEffect.id, - areaVFX = lightEffect.areaVisualEffect.id, - lighting = {x = lightEffect.lightingRed / 255, y = lightEffect.lightingGreen / 255, z = lightEffect.lightingBlue / 255}, - size = lightEffect.size, - sizeCap = lightEffect.sizeCap, + addMiscEffect("T_illusion_PrismaticLight", { onTick = prismaticLightEffect, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[21]) -- Blood Magic - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, + addMiscEffect("T_mysticism_BloodMagic", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = false, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, - hasContinuousVFX = detectEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, - hitSound = detectEffect.hitSoundEffect.id, - hitVFX = detectEffect.hitVisualEffect.id, - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, - lighting = {x = detectEffect.lightingRed / 255, y = detectEffect.lightingGreen / 255, z = detectEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[22]) -- Sanguine Rose - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.conjuration, - baseCost = effectCost, - speed = summonDremoraEffect.speed, + addMiscEffect("T_conjuration_SanguineRose", { allowEnchanting = false, allowSpellmaking = false, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = summonDremoraEffect.casterLinked, - hasContinuousVFX = summonDremoraEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = summonDremoraEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, - unreflectable = summonDremoraEffect.unreflectable, - usesNegativeLighting = summonDremoraEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = summonDremoraEffect.particleTexture, - castSound = summonDremoraEffect.castSoundEffect.id, - castVFX = summonDremoraEffect.castVisualEffect.id, - boltSound = summonDremoraEffect.boltSoundEffect.id, - boltVFX = summonDremoraEffect.boltVisualEffect.id, - hitSound = summonDremoraEffect.hitSoundEffect.id, - hitVFX = summonDremoraEffect.hitVisualEffect.id, - areaSound = summonDremoraEffect.areaSoundEffect.id, - areaVFX = summonDremoraEffect.areaVisualEffect.id, - lighting = {x = summonDremoraEffect.lightingRed / 255, y = summonDremoraEffect.lightingGreen / 255, z = summonDremoraEffect.lightingBlue / 255}, - size = summonDremoraEffect.size, - sizeCap = summonDremoraEffect.sizeCap, onTick = function(eventData) - eventData:triggerSummon(sanguineRoseDaedra[math.random(#sanguineRoseDaedra)]) + eventData:triggerSummon(magicData.sanguineRoseDaedra[math.random(#magicData.sanguineRoseDaedra)]) end, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[23]) -- Detect Valuable - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), + addMiscEffect("T_mysticism_DetValuables", { magnitudeType = " " .. tes3.findGMST(tes3.gmst.sfeet).value, magnitudeTypePlural = " " .. tes3.findGMST(tes3.gmst.sfeet).value, - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, - hasContinuousVFX = detectEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = false, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, - hitSound = detectEffect.hitSoundEffect.id, - hitVFX = detectEffect.hitVisualEffect.id, - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, - lighting = {x = detectEffect.lightingRed / 255, y = detectEffect.lightingGreen / 255, z = detectEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[24]) -- Magicka Ward - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.mysticism, - baseCost = effectCost, - speed = detectEffect.speed, + addMiscEffect("T_mysticism_MagickaWard", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = false, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = detectEffect.casterLinked, hasContinuousVFX = shieldEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = detectEffect.illegalDaedra, isHarmful = false, nonRecastable = false, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = detectEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = detectEffect.particleTexture, - castSound = detectEffect.castSoundEffect.id, - castVFX = detectEffect.castVisualEffect.id, - boltSound = detectEffect.boltSoundEffect.id, - boltVFX = detectEffect.boltVisualEffect.id, - hitSound = detectEffect.hitSoundEffect.id, hitVFX = shieldEffect.hitVisualEffect.id, - areaSound = detectEffect.areaSoundEffect.id, - areaVFX = detectEffect.areaVisualEffect.id, lighting = {x = shieldEffect.lightingRed / 255, y = shieldEffect.lightingGreen / 255, z = shieldEffect.lightingBlue / 255}, - size = detectEffect.size, - sizeCap = detectEffect.sizeCap, onTick = nil, onCollision = nil - } + }) - effectID, effectName, effectCost, iconPath, effectDescription = unpack(magicData.td_misc_effects[25]) -- Ethereal - tes3.addMagicEffect{ - id = tes3.effect[effectID], - name = common.i18n("magic." .. effectName), - description = common.i18n("magic." .. effectDescription), - school = tes3.magicSchool.illusion, - baseCost = effectCost, - speed = blindEffect.speed, + addMiscEffect("T_illusion_Ethereal", { allowEnchanting = true, allowSpellmaking = true, appliesOnce = true, canCastSelf = true, canCastTarget = false, canCastTouch = false, - casterLinked = blindEffect.casterLinked, - hasContinuousVFX = blindEffect.hasContinuousVFX, hasNoDuration = false, hasNoMagnitude = true, - illegalDaedra = blindEffect.illegalDaedra, isHarmful = false, nonRecastable = true, targetsAttributes = false, targetsSkills = false, unreflectable = false, - usesNegativeLighting = blindEffect.usesNegativeLighting, - icon = iconPath, - particleTexture = blindEffect.particleTexture, - castSound = blindEffect.castSoundEffect.id, - castVFX = blindEffect.castVisualEffect.id, - boltSound = blindEffect.boltSoundEffect.id, - boltVFX = blindEffect.boltVisualEffect.id, - hitSound = blindEffect.hitSoundEffect.id, - hitVFX = blindEffect.hitVisualEffect.id, - areaSound = blindEffect.areaSoundEffect.id, - areaVFX = blindEffect.areaVisualEffect.id, - lighting = {x = blindEffect.lightingRed / 255, y = blindEffect.lightingGreen / 255, z = blindEffect.lightingBlue / 255}, - size = blindEffect.size, - sizeCap = blindEffect.sizeCap, onTick = etherealEffect, onCollision = nil - } + }) end end) diff --git a/Data Files/MWSE/mods/TamrielData/magicdata.lua b/Data Files/MWSE/mods/TamrielData/magicdata.lua index 618bf18..35bfa31 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 @@ -49,33 +52,33 @@ local td_intervention_effects = { { "T_intervention_Kyne", "interventionKyne", 150, "td\\s\\td_s_int_kyne.tga", "interventionKyneDesc"}, } --- effect id, effect name, effect mana cost, icon, effect description +-- effect id => effect name, effect mana cost, icon, effect description, template local td_misc_effects = { - { "T_mysticism_Passwall", "miscPasswall", 750, "td\\s\\td_s_passwall.tga", "miscPasswallDesc"}, - { "T_mysticism_BanishDae", "miscBanish", 128, "td\\s\\td_s_ban_daedra.tga", "miscBanishDesc"}, - { "T_mysticism_ReflectDmg", "miscReflectDamage", 20, "td\\s\\td_s_ref_dam.tga", "miscReflectDamageDesc"}, - { "T_mysticism_DetHuman", "miscDetectHumanoid", .75, "td\\s\\td_s_det_hum.tga", "miscDetectHumanoidDesc"}, - { "T_alteration_RadShield", "miscRadiantShield", 5, "td\\s\\td_s_radiant_shield.tga", "miscRadiantShieldDesc"}, - { "T_alteration_Wabbajack", "miscWabbajack", 22, "td\\s\\td_s_wabbajack.tga", "miscWabbajackDesc"}, - { "T_alteration_WabbajackHelper", "miscWabbajack", 0, "td\\s\\td_s_wabbajack.tga", "miscWabbajackDesc"}, - { "T_mysticism_Insight", "miscInsight", 10, "td\\s\\td_s_insight.tga", "miscInsightDesc"}, - { "T_restoration_ArmorResartus", "miscArmorResartus", 60, "td\\s\\td_s_restore_ar.tga", "miscArmorResartusDesc"}, - { "T_restoration_WeaponResartus", "miscWeaponResartus", 120, "td\\s\\td_s_restore_wpn.tga", "miscWeaponResartusDesc"}, - { "T_conjuration_Corruption", "miscCorruption", 40, "td\\s\\td_s_skull_corr.tga", "miscCorruptionDesc"}, - { "T_conjuration_CorruptionSummon", "miscCorruption", 0, "td\\s\\td_s_skull_corr.tga", "miscCorruptionDesc"}, - { "T_illusion_DistractCreature", "miscDistractCreature", 0.5, "td\\s\\td_s_dist_cre.tga", "miscDistractCreatureDesc"}, - { "T_illusion_DistractHumanoid", "miscDistractHumanoid", 1, "td\\s\\td_s_dist_hum.tga", "miscDistractHumanoidDesc"}, - { "T_destruction_GazeOfVeloth", "miscGazeOfVeloth", 80, "td\\s\\td_s_gaze_veloth.tga", "miscGazeOfVelothDesc"}, - { "T_mysticism_DetEnemy", "miscDetectEnemy", 1, "td\\s\\td_s_det_enemy.tga", "miscDetectEnemyDesc"}, - { "T_mysticism_DetInvisibility", "miscDetectInvisibility", 1.5, "td\\s\\td_s_det_invisibility.tga", "miscDetectInvisibilityDesc"}, - { "T_mysticism_Blink", "miscBlink", 10, "td\\s\\td_s_blink.tga", "miscBlinkDesc"}, - { "T_restoration_FortifyCasting", "miscFortifyCasting", 1, "td\\s\\td_s_ftfy_cast.tga", "miscFortifyCastingDesc"}, - { "T_illusion_PrismaticLight", "miscPrismaticLight", 0.4, "td\\s\\td_s_p_light.tga", "miscPrismaticLightDesc"}, - { "T_mysticism_BloodMagic", "miscBloodMagic", 2, "td\\s\\td_s_blood_magic.tga", "miscBloodMagicDesc"}, - { "T_conjuration_SanguineRose", "miscSanguineRose", 40, "td\\s\\td_s_sanguine.dds.tga", "miscSanguineRoseDesc"}, - { "T_mysticism_DetValuables", "miscDetectValuables", 1.5, "td\\s\\td_s_det_value.tga", "miscDetectValuablesDesc"}, - { "T_mysticism_MagickaWard", "miscMagickaWard", 20, "td\\s\\td_s_magickaward.tga", "miscMagickaWardDesc"}, - { "T_illusion_Ethereal", "miscEthereal", 40, "td\\s\\td_s_ethereal.tga", "miscEtherealtDesc"}, + T_mysticism_Passwall = { "miscPasswall", 750, "td\\s\\td_s_passwall.tga", "miscPasswallDesc", "detectAnimal" }, + T_mysticism_BanishDae = { "miscBanish", 128, "td\\s\\td_s_ban_daedra.tga", "miscBanishDesc", "soultrap" }, + T_mysticism_ReflectDmg = { "miscReflectDamage", 20, "td\\s\\td_s_ref_dam.tga", "miscReflectDamageDesc", "reflect" }, + T_mysticism_DetHuman = { "miscDetectHumanoid", .75, "td\\s\\td_s_det_hum.tga", "miscDetectHumanoidDesc", "detectAnimal" }, + T_alteration_RadShield = { "miscRadiantShield", 5, "td\\s\\td_s_radiant_shield.tga", "miscRadiantShieldDesc", "shield" }, + T_alteration_Wabbajack = { "miscWabbajack", 22, "td\\s\\td_s_wabbajack.tga", "miscWabbajackDesc", "burden" }, + T_alteration_WabbajackHelper = { "miscWabbajack", 0, "td\\s\\td_s_wabbajack.tga", "miscWabbajackDesc", "burden" }, + T_mysticism_Insight = { "miscInsight", 10, "td\\s\\td_s_insight.tga", "miscInsightDesc", "reflect" }, + T_restoration_ArmorResartus = { "miscArmorResartus", 60, "td\\s\\td_s_restore_ar.tga", "miscArmorResartusDesc", "fortifyHealth" }, + T_restoration_WeaponResartus = { "miscWeaponResartus", 120, "td\\s\\td_s_restore_wpn.tga", "miscWeaponResartusDesc", "fortifyHealth" }, + T_conjuration_Corruption = { "miscCorruption", 40, "td\\s\\td_s_skull_corr.tga", "miscCorruptionDesc", "summonDremora" }, + T_conjuration_CorruptionSummon = { "miscCorruption", 0, "td\\s\\td_s_skull_corr.tga", "miscCorruptionDesc", "summonDremora" }, + T_illusion_DistractCreature = { "miscDistractCreature", 0.5, "td\\s\\td_s_dist_cre.tga", "miscDistractCreatureDesc", "blind" }, + T_illusion_DistractHumanoid = { "miscDistractHumanoid", 1, "td\\s\\td_s_dist_hum.tga", "miscDistractHumanoidDesc", "blind" }, + T_destruction_GazeOfVeloth = { "miscGazeOfVeloth", 80, "td\\s\\td_s_gaze_veloth.tga", "miscGazeOfVelothDesc", "damageHealth" }, + T_mysticism_DetEnemy = { "miscDetectEnemy", 1, "td\\s\\td_s_det_enemy.tga", "miscDetectEnemyDesc", "detectAnimal" }, + T_mysticism_DetInvisibility = { "miscDetectInvisibility", 1.5, "td\\s\\td_s_det_invisibility.tga", "miscDetectInvisibilityDesc", "detectAnimal" }, + T_mysticism_Blink = { "miscBlink", 10, "td\\s\\td_s_blink.tga", "miscBlinkDesc", "detectAnimal" }, + T_restoration_FortifyCasting = { "miscFortifyCasting", 1, "td\\s\\td_s_ftfy_cast.tga", "miscFortifyCastingDesc", "fortifyAttack" }, + T_illusion_PrismaticLight = { "miscPrismaticLight", 0.4, "td\\s\\td_s_p_light.tga", "miscPrismaticLightDesc", "light" }, + T_mysticism_BloodMagic = { "miscBloodMagic", 2, "td\\s\\td_s_blood_magic.tga", "miscBloodMagicDesc", "detectAnimal" }, + T_conjuration_SanguineRose = { "miscSanguineRose", 40, "td\\s\\td_s_sanguine.tga", "miscSanguineRoseDesc", "summonDremora" }, + T_mysticism_DetValuables = { "miscDetectValuables", 1.5, "td\\s\\td_s_det_value.tga", "miscDetectValuablesDesc", "detectAnimal" }, + T_mysticism_MagickaWard = { "miscMagickaWard", 20, "td\\s\\td_s_magickaward.tga", "miscMagickaWardDesc", "detectAnimal" }, + T_illusion_Ethereal = { "miscEthereal", 40, "td\\s\\td_s_ethereal.tga", "miscEtherealtDesc", "blind" }, } -- spell id, cast type, spell name, spell mana cost, effect1, ... @@ -607,6 +610,115 @@ local td_ingredients = { { id = "T_mysticism_Insight" } }, } +-- race id, isFemale, distraction voice files, distraction end voice lines +local distractedVoiceLines = { + { "Argonian", false, { "vo\\a\\m\\Idl_AM001.mp3", "vo\\a\\m\\Hlo_AM056.mp3" }, { "vo\\a\\m\\Idl_AM008.mp3" } }, + { "Argonian", true, { "vo\\a\\f\\Idl_AF007.mp3", "vo\\a\\f\\Idl_AF004.mp3" }, { "vo\\a\\f\\Idl_AF002.mp3" } }, + { "Breton", false, { }, { } }, + { "Breton", true, { "vo\\b\\f\\Idl_BF001.mp3", "vo\\b\\f\\Idl_BF005.mp3" }, { "vo\\b\\f\\Idl_BF003.mp3" } }, + { "Dark Elf", false, { "vo\\d\\m\\Idl_DM006.mp3", "vo\\d\\m\\Idl_DM007.mp3" }, { "vo\\d\\m\\Idl_DM008.mp3" } }, + { "Dark Elf", true, { "vo\\d\\f\\Idl_DF006.mp3" }, { "vo\\d\\f\\Idl_DF003.mp3" } }, + { "High Elf", false, { "vo\\h\\m\\Hlo_HM056.mp3" }, { "vo\\i\\m\\Idl_HF007.mp3" } }, + { "High Elf", true, { "vo\\h\\f\\Hlo_HF056.mp3" }, { "vo\\i\\f\\Idl_HF007.mp3" } }, + { "Imperial", false, { "vo\\i\\m\\Idl_IM008.mp3" }, { "vo\\i\\m\\Idl_IM005.mp3" } }, + { "Imperial", true, { "vo\\i\\f\\Idl_IF001.mp3" }, { "vo\\i\\f\\Idl_IF009.mp3" } }, + { "Khajiit", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "Khajiit", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Cathay", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Cathay-raht", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Dagi-raht", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Ohmes", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Ohmes-raht", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Suthay", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Tojay", false, { "vo\\k\\m\\Idl_KM005.mp3", "vo\\k\\m\\Idl_KM006.mp3", "vo\\k\\m\\Idl_KM007.mp3" }, { "vo\\k\\m\\Idl_KM002.mp3", "vo\\k\\m\\Idl_KM003.mp3" } }, + { "T_Els_Cathay", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Cathay-raht", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Dagi-raht", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Ohmes", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Ohmes-raht", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Suthay", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "T_Els_Tojay", true, { "vo\\k\\f\\Idl_KF005.mp3", "vo\\k\\f\\Idl_KF006.mp3", "vo\\k\\f\\Idl_KF007.mp3" }, { "vo\\k\\f\\Idl_KF002.mp3", "vo\\k\\f\\Idl_KF003.mp3" } }, + { "Nord", false, { "vo\\n\\m\\Idl_NM001.mp3" }, { "vo\\n\\m\\Idl_NM009.mp3" } }, + { "Nord", true, { "vo\\n\\f\\Idl_NF002.mp3", "vo\\n\\f\\Idl_NF004.mp3" }, { "vo\\n\\f\\Idl_NM008.mp3" } }, + { "Orc", false, { "vo\\o\\m\\Idl_OM001.mp3", "vo\\o\\m\\Idl_OM002.mp3" }, { "vo\\o\\m\\Idl_OM004.mp3", "vo\\o\\m\\Idl_OM009.mp3" } }, + { "Orc", true, { "vo\\o\\f\\Idl_OF009.mp3" }, { } }, + { "Redguard", false, { }, { } }, + { "Redguard", true, { "vo\\r\\f\\Idl_RF002.mp3", "vo\\r\\f\\Idl_RF008.mp3" }, { "vo\\r\\f\\Idl_RF003.mp3", "vo\\r\\f\\Idl_RF007.mp3" } }, + { "Wood Elf", false, { "vo\\w\\m\\Idl_WM009.mp3" }, { "vo\\w\\m\\Idl_WM006.mp3", "vo\\w\\m\\Idl_WM007.mp3" } }, + { "Wood Elf", true, { "vo\\w\\f\\Idl_WF006.mp3", "vo\\w\\f\\Idl_WF009.mp3" }, { "vo\\w\\f\\Idl_WF003.mp3", "vo\\w\\f\\Idl_WF007.mp3" } }, +} + +local sanguineRoseDaedra = { + "dremora_summon", + "T_Dae_Cre_Seduc_01", + "atronach_flame", + "atronach_frost", + "atronach_storm", + "scamp_summon", + "T_Dae_Cre_Verm_01", + "clannfear_summon", + "T_Dae_Cre_Herne_01", + "T_Dae_Cre_Morphoid_01", + "T_Dae_Cre_SpiderDae_01", + "hunger_summon", + "winged twilight_summon", + "golden saint_summon", + "daedroth_summon", +} + +-- script id +local safeScripts = { + ["nolore"] = true, + ["slaveScript"] = true, + ["fortloreboozeScript"] = true, + ["TR_m3_Kha_Methats_sc"] = true, + ["TR_m3_NPC_OE_commonNoLore"] = true, + ["TR_m3_NPC_OE_poorNoLore"] = true, + ["TR_m3_NPC_OE_richNoLore"] = true, + ["TR_m3_NPC_OE_towerNoLore"] = true, + ["TR_m4_AA_Vf_NPC_NoLoresc"] = true, + ["TR_m7_NPC_RuddyEggsNoLore"] = true, + ["TR_m7_Ns_KhanVolnyr_sc"] = true, + ["TR_m3_q_kharg"] = true, + ["TR_m3_Kha_AtroLordDis_sc"] = true, + ["TR_m3_Kha_Black_Heart_Script"] = true, + ["TR_m3_Kha_ClannLordDis_sc"] = true, + ["TR_m3_Kha_FireScamp_sc"] = true, + ["TR_m1_Lornie_Slave_scpt"] = true, + ["TR_m4_OranSlave_Sc"] = true, + ["TR_m1_T_CouncilorSc"] = true, + ["TR_m2_T_CouncilorSc"] = true, + ["TR_NecMQ_MovingNPCScript"] = true, + ["TR_m1_FW_TG3_HrongalDrink"] = true, + ["TR_m1_MinTalScript"] = true, + ["TR_m1_NPC_DiceGambler"] = true, + ["TR_m2_NPC_DiceGambler"] = true, + ["TR_m3_NPC_DiceGambler"] = true, + ["TR_m3_NPC_DiceGamblerNoLore"] = true, + ["TR_m3_NPC_DiceGamblerOECom"] = true, + ["TR_m3_NPC_DiceGamblerOEPoor"] = true, + ["TR_m4_NPC_DiceGambler"] = true, + ["TR_m5_NPC_DiceGambler"] = true, + ["TR_m6_NPC_DiceGambler"] = true, + ["TR_m7_NPC_DiceGambler"] = true, + ["TR_m1_NPC_Fervas_Shulisa"] = true, + ["TR_m1_NPC_Gilen_Indothan"] = true, + ["TR_m1_NPC_Malvas_Relvani"] = true, + ["TR_m1_T_Seducer"] = true, + ["TR_m3_q_vampambush"] = true, +} + +local wabbajackCreatures = { + "T_Mw_UNI_GrahlWabbajack", -- This version of the Grahl does not have fireregenScript attached to it; I saw a crash occur while it was being executed, but I am not sure why. + "scamp", + "T_Glb_Cre_LandDreu_01", + "T_Glb_Cre_TrollCave_03", + "mudcrab", + "T_Ham_Fau_Goat_01", + "Rat", + "golden saint" +} + return { td_summon_effects = td_summon_effects, td_bound_effects = td_bound_effects, @@ -620,4 +732,8 @@ return { td_potions = td_potions, td_enchanted_items = td_enchanted_items, td_ingredients = td_ingredients, + distractedVoiceLines = distractedVoiceLines, + sanguineRoseDaedra = sanguineRoseDaedra, + safeScripts = safeScripts, + wabbajackCreatures = wabbajackCreatures, } diff --git a/Data Files/Tamriel_Data.omwscripts b/Data Files/Tamriel_Data.omwscripts index 3c47086..377eec8 100644 --- a/Data Files/Tamriel_Data.omwscripts +++ b/Data Files/Tamriel_Data.omwscripts @@ -1,7 +1,13 @@ MENU: scripts/TamrielData/menu_settings.lua GLOBAL: scripts/TamrielData/global_restrict_equipment.lua -GLOBAL: scripts/TamrielData/global_magic_passwall.lua 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_miscspells.lua +GLOBAL: scripts/TamrielData/global_summons.lua +PLAYER, NPC, CREATURE: scripts/TamrielData/actor_magic.lua +PLAYER, NPC, CREATURE: scripts/TamrielData/actor_summons.lua +LOAD: scripts/TamrielData/load_magic.lua +CUSTOM: scripts/TamrielData/container_banish.lua diff --git a/Data Files/l10n/TamrielData/en.yaml b/Data Files/l10n/TamrielData/en.yaml index 13047df..d2a955a 100644 --- a/Data Files/l10n/TamrielData/en.yaml +++ b/Data Files/l10n/TamrielData/en.yaml @@ -5,6 +5,10 @@ Settings_TamrielData_page01Main_group01Main_restrictEquipment_Description: "Prev Settings_TamrielData_page01Main_group02Magic: "Magic" Settings_TamrielData_page01Main_group02Magic_miscSpells: "Add New Miscellaneous Spells" Settings_TamrielData_page01Main_group02Magic_miscSpells_Description: "Adds new spells that do not fit into usual categories." +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_group02Magic_miscBlinkIndicator: "Indicator for Blink" +Settings_TamrielData_page01Main_group02Magic_miscBlinkIndicator_Description: "Shows where Tamriel Data's Blink effect will teleport you to." 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." @@ -21,4 +25,132 @@ 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_banishFailure: "This spell is too weak to banish {target}!" +Magic_corruptionScript: "{target} cannot be corrupted." +Magic_corruptionSummon: "You cannot corrupt a being summoned by the Skull of Corruption." +Magic_wabbajackFailure: "{target} is too strong to be Wabbajacked!" +Magic_wabbajackAlready: "{target} is already Wabbajacked!" + +Magic_summonDevourer: "Summon Devourer" +Magic_summonDevourerDesc: "This effect summons a devourer from Oblivion. It appears six feet in front of the caster and attacks any entity that attacks the caster until the effect ends or the summoning is killed. At death, or when the effect ends, the summoning disappears, returning to Oblivion. If summoned in town, the guards will attack you and the summoning on sight." +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." + +Magic_miscPasswall: "Passwall" +Magic_miscPasswallDesc: "In an indoor area, this effect permits the caster to pass through a solid barrier to a vacant space behind it. The effect will fail if the destination beyond the traversed barrier is filled with water, is blocked by a forcefield, sigil gate, or ward, or lies above or below the caster." +Magic_miscBanish: "Banish Daedra" +Magic_miscBanishDesc: "Banishes any daedra that the spell is cast upon if the spell's magnitude is greater than or equal to the target's level. If the daedra is wounded, then it will be easier to banish. Banishing a daedra will transfer any of their important belongings to a sigil that is left behind." +Magic_miscReflectDamage: "Reflect Damage" +Magic_miscReflectDamageDesc: "This effect allows the subject to reflect physical damage back at an attacker. The effect's magnitude is the percent damage that will be reflected for each attack. Any unreflected damage is dealt to the defender normally." +Magic_miscDetectHumanoid: "Detect Humanoid" +Magic_miscDetectHumanoidDesc: "The caster of this effect can detect any entity animated by a spirit; they appear on the map as symbols. This effect includes all people. The effect's magnitude is the range in feet from the caster that humanoids are detected." +Magic_miscRadiantShield: "Radiant Shield" +Magic_miscRadiantShieldDesc: "This effect creates a shield of brilliant light around the subject's entire body. The spell adds its magnitude to the subject's Armor Rating, resists harmful magic, and briefly blinds attackers in melee." +Magic_miscRadiantShieldBlindness: "Blinding Radiance" +Magic_miscWabbajack: "Wabbajack" +Magic_miscWabbajackDesc: "Wabbajack!" +Magic_miscInsight: "Insight" +Magic_miscInsightDesc: "This effect lightly twists fate, increasing the chance of discovering valuable items." +Magic_miscArmorResartus: "Armor Resartus" +Magic_miscArmorResartusDesc: "This effect mends and recharges enchanted armor that is equipped by the caster. The magnitude is the units of condition and charge restored, which are distributed across all of the caster's enchanted armor." +Magic_miscWeaponResartus: "Weapon Resartus" +Magic_miscWeaponResartusDesc: "This effect mends and recharges an enchanted weapon that is equipped by the caster. The magnitude is the units of condition and charge restored." +Magic_miscCorruption: "Corruption" +Magic_miscCorruptionDesc: "This effect creates a shadowy counterpart of the target that will aid the caster in combat." +Magic_miscDistractCreature: "Distract Creature" +Magic_miscDistractCreatureDesc: "This effect compels a creature to wander away from their current position while attempting to keep their distance from the caster. The effect's magnitude is the maximum distance that the target can travel and the effect cannot be casted again on the target while it is active. Using this effect will fail if the target is aware of the caster's presence. When the effect ends, the target begins to return to their original location and cannot be distracted again until they do." +Magic_miscDistractHumanoid: "Distract Humanoid" +Magic_miscDistractHumanoidDesc: "This effect compels a person to wander away from their current position while attempting to keep their distance from the caster. The effect's magnitude is the maximum distance that the target can travel and the effect cannot be casted again on the target while it is active. Using this effect will fail if the target is aware of the caster's presence. When the effect ends, the target begins to return to their original location and cannot be distracted again until they do." +Magic_miscGazeOfVeloth: "Gaze of Veloth" +Magic_miscGazeOfVelothDesc: "Witness the Face of Veloth!" +Magic_miscDetectEnemy: "Detect Enemy" +Magic_miscDetectEnemyDesc: "The caster of this effect can detect any entity animated by a spirit; they appear on the map as symbols. This effect includes all hostile beings. The effect's magnitude is the range in feet from the caster that enemies are detected." +Magic_miscDetectInvisibility: "Detect Invisibility" +Magic_miscDetectInvisibilityDesc: "The caster of this effect can detect any entity animated by a spirit; they appear on the map as symbols. This effect includes all beings affected by chameleon or invisibility effects. The effect's magnitude is the range in feet from the caster that hidden beings are detected. The chameleon and invisibility effects on detected entities are also weakened." +Magic_miscBlink: "Blink" +Magic_miscBlinkDesc: "This effect teleports the caster in whatever direction they are looking in. The effect's magnitude is the maximum distance that the caster can move." +Magic_miscFortifyCasting: "Fortify Casting" +Magic_miscFortifyCastingDesc: "This effect raises the subject's chance of successfully casting a spell." +Magic_miscPrismaticLight: "Prismatic Light" +Magic_miscPrismaticLightDesc: "This effect creates a projectile of prismatic light. Upon striking a target, the projectile illuminates the area for the duration of the effect. The light projectile does not cause any damage." +Magic_miscBloodMagic: "Blood Magic" +Magic_miscBloodMagicDesc: "Placeholder" +Magic_miscSanguineRose: "Sanguine Rose" +Magic_miscSanguineRoseDesc: "This effect summons a random 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_miscDetectValuables: "Detect Valuables" +Magic_miscDetectValuablesDesc: "The caster of this effect can detect items valued at 4000 drakes or more; they appear on the map as symbols. The effect's magnitude is the range in feet from the caster that items are detected." +Magic_miscMagickaWard: "Magicka Ward" +Magic_miscMagickaWardDesc: "Placeholder" +Magic_miscEthereal: "Ethereal" +Magic_miscEtherealDesc: "The caster of this effect becomes incorporeal and can pass through other entities. The caster is incapable of being harmed by them, but also cannot act upon them, cast magic, use items, or physically interact with the world in general. The caster cannot pass through objects such as walls and still obeys the laws of gravity." + +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 b08c38a..0a65906 100644 --- a/Data Files/l10n/TamrielData/fr.yaml +++ b/Data Files/l10n/TamrielData/fr.yaml @@ -5,6 +5,10 @@ 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_group02Magic_miscBlinkIndicator: "Indicateur pour l'effet de Transfert" +Settings_TamrielData_page01Main_group02Magic_miscBlinkIndicator_Description: "Indique où l'effet magique de Transfert du mod vous téléportera quand vous le lancerez." 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." @@ -21,4 +25,132 @@ 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_banishFailure: "Ce sort est trop faible pour bannir : {target} !" +Magic_corruptionScript: "{target} ne peut être corrompu." +Magic_corruptionSummon: "Vous ne pouvez corrompre un être invoqué par le Crâne de Corruption." +Magic_wabbajackFailure: "{target} est trop puissant pour que Wabbajack l'affecte !" +Magic_wabbajackAlready: "{target} est déjà sous l'effet de Wabbajack !" + +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." + +Magic_miscPasswall: "Passe-muraille" +Magic_miscPasswallDesc: "En intérieur, cet effet permet au lanceur de traverser une barrière solide vers un espace vide derrière celle-ci. L'effet échouera si la destination au-delà de la barrière traversée est emplie d'eau, bloquée par un champ de force, une porte scellée ou une barrière, ou se trouve au-dessus ou au-dessous du lanceur." +Magic_miscBanish: "Bannissement de Daedra" +Magic_miscBanishDesc: "Bannit tout Daedra sur lequel ce sort est lancé, à condition que la cible soit d'un niveau suffisamment bas comparé à la puissance du sort. Si le Daedra est blessé, il sera plus facile à bannir. Bannir un Daedra transfert tous ses biens d'importance dans un sceau laissé à sa place." +Magic_miscReflectDamage: "Réflexion de dégâts" +Magic_miscReflectDamageDesc: "Cet effet permet de renvoyer des dégâts physiques à un agresseur. La puissance de l'effet détermine le pourcentage de dégâts qui sera reflété pour chaque attaque. Tout dégât non réfléchi affecte normalement sa cible." +Magic_miscDetectHumanoid: "Détection des humanoïdes" +Magic_miscDetectHumanoidDesc: "Cet effet permet de détecter n'importe quelle entité animée par un esprit ; elles apparaissent sous forme de symboles sur la carte. Cet effet comprend tous les personnages. La puissance de l'effet détermine la portée à laquelle le lanceur peut détecter des individus (en pieds).", +Magic_miscRadiantShield: "Bouclier radieux" +Magic_miscRadiantShieldDesc: "Cet effet crée un bouclier de lumière brillante autour du sujet. La puissance de l'effet s'ajoute à la valeur d'armure du sujet, réduit considérablement les effets des attaques magiques, et aveugle brièvement les agresseurs au corps-à-corps." +Magic_miscRadiantShieldBlindness: "Brillance aveuglante" +Magic_miscWabbajack: "Wabbajack" +Magic_miscWabbajackDesc: "Wabbajack !" +Magic_miscInsight: "Perspicacité" +Magic_miscInsightDesc: "Cet effet influe légèrement sur le destin en augmentant les chances de découvrir des objets de valeur." +Magic_miscArmorResartus: "Armure raccommodée" +Magic_miscArmorResartusDesc: "Cet effet répare et recharge l'armure enchantée équipée par le lanceur. La puissance de l'effet correspond au nombre d'unités de condition et de charge restaurées, qui sont distribuées entre chacun des pièces d'armure enchantées du lanceur." +Magic_miscWeaponResartus: "Arme raccommodée" +Magic_miscWeaponResartusDesc: "Cet effet répare et recharge l'arme enchantée équipée par le lanceur. La puissance de l'effet correspond au nombre d'unités de condition et de charge restaurées." +Magic_miscCorruption: "Corruption" +Magic_miscCorruptionDesc: "Cet effet crée un double ténébreux de la cible qui aidera le lanceur au combat." +Magic_miscDistractCreature: "Distraction des créatures" +Magic_miscDistractCreatureDesc: "Cet effet incite une créature à s'éloigner de sa position actuelle tout en tentant de garder ses distances par rapport au lanceur. La puissance de l'effet correspond à la distance maximale à laquelle la cible peut s'éloigner de sa position, et l'effet ne peut être lancé à nouveau sur la cible tant qu'il est actif. Cet effet échouera si la cible a conscience de la présence du lanceur. Quand l'effet prend fin, la cibl commence à rejoindre sa position initiale et ne peut être distraite à nouveau jusqu'à ce qu'elle l'atteigne." +Magic_miscDistractHumanoid: "Distraction des humanoïdes" +Magic_miscDistractHumanoidDesc: "Cet effet incite une personne à s'éloigner de sa position actuelle tout en tentant de garder ses distances par rapport au lanceur. La puissance de l'effet correspond à la distance maximale à laquelle la cible peut s'éloigner de sa position, et l'effet ne peut être lancé à nouveau sur la cible tant qu'il est actif. Cet effet échouera si la cible a conscience de la présence du lanceur. Quand l'effet prend fin, la cible commence à rejoindre sa position initiale et ne peut être distraite à nouveau jusqu'à ce qu'elle l'atteigne." +Magic_miscGazeOfVeloth: "Regard de Véloth" +Magic_miscGazeOfVelothDesc: "Soyez témoin du visage de Véloth !" +Magic_miscDetectEnemy: "Détection des ennemis" +Magic_miscDetectEnemyDesc: "Cet effet permet de détecter n'importe quelle entité hostile ; elles apparaissent sous forme de symboles sur la carte. La puissance de l'effet détermine la portée à laquelle le lanceur peut détecter des entités hostiles (en pieds)." +Magic_miscDetectInvisibility: "Détection d'invisibilité" +Magic_miscDetectInvisibilityDesc: "Cet effet permet de détecter n'importe quelle entité affectée par un effet d'invisibilité ou de caméléon ; elles apparaissent sous forme de symboles sur la carte. La puissance de l'effet détermine la portée à laquelle le lanceur peut détecter des entités dissimulées (en pieds). Les effets d'invisibilité et de caméléon des entités détectées sont également affaiblis." +Magic_miscBlink: "Transfert" +Magic_miscBlinkDesc: "Cet effet téléporte le lanceur dans la direction vers laquelle il regarde. La puissance de l'effet correspond à la distance maximale qui peut être parcourue." +Magic_miscFortifyCasting: "Sorts fortifiés" +Magic_miscFortifyCastingDesc: "Cet effet augmente la chance du sujet de parvenir à lancer un sort." +Magic_miscPrismaticLight: "Lumière prismatique" +Magic_miscPrismaticLightDesc: "Cet effet crée un projectile de lumière prismatique. Quand il touche une cible, le projectile illumine la zone pour la durée de l'effet. Le projectile de lumière n'inflige aucun dégât." +Magic_miscBloodMagic: "Magie du sang" +Magic_miscBloodMagicDesc: "Placeholder" +Magic_miscSanguineRose: "Rose de Sanguiyn" +Magic_miscSanguineRoseDesc: "Cet effet permet d'invoquer un Daedra aléatoire 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_miscDetectValuables: "Détection des objets précieux" +Magic_miscDetectValuablesDesc: "Cet effet permet de détecter les objets précieux valant au moins 4000 drakes ; ils apparaissent sous forme de symboles sur la carte. La puissance de l'effet détermine la portée à laquelle le lanceur peut détecter des objets précieux (en pieds)." +Magic_miscMagickaWard: "Barrière magique" +Magic_miscMagickaWardDesc: "Placeholder" +Magic_miscEthereal: "Forme éthérée" +Magic_miscEtherealDesc: "Le lanceur de cet effet revêt une forme incorporelle et peut traverser les autres entités. Le lanceur ne peut être blessé par celles-ci, mais ne peut pas non plus agir sur elles, lancer des sorts, utiliser des objets, ou généralement interagir physiquement avec le monde. Le lanceur ne peut pas traverser des objets comme des murs et obéit toujours aux lois de la gravité." + +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 f82947c..9236950 100644 --- a/Data Files/l10n/TamrielData/pl.yaml +++ b/Data Files/l10n/TamrielData/pl.yaml @@ -1 +1,131 @@ -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." + +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" + +TamrielData_magic_passwallWard: "Nie możesz tam przeniknąć." +TamrielData_magic_passwallAlpha: "Nie możesz przez to przeniknąć." +TamrielData_magic_passwallExterior: "Musisz być w zamkniętej przestrzeni." +TamrielData_magic_passwallDoorExterior: "Musisz pozostać w zamkniętej przestrzeni." +TamrielData_magic_passwallUnderwater: "Nie możesz być pod wodą." +Magic_banishFailure: "Cel: {target} nie może zostać wypędzony, zaklęcie jest zbyt słabe!" +Magic_wabbajackFailure: "Cel: {target} jest zbyt potężny, nie może być poddany efektowi Łabadżaka!" +Magic_wabbajackAlready: "Cel: {target} jest już pod wpływem efektu Łabadżaka!" + +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!" + +Magic_miscPasswall: "Przeniknięcie Ściany" +Magic_miscPasswallDesc: "Pozwala przeniknąć przez stałe bariery w obszarach wewnętrznych do wolnej przestrzeni poza nimi. Efekt zawiedzie, jeśli miejsce docelowe jest wypełnione wodą, położone jest poza polem siłowym, zapieczętowaną bramą, lub znajduje się powyżej lub poniżej poziomu, na któym znajduje się rzucający zaklęcie." +Magic_miscBanish: "Wypędzenie Daedry" +Magic_miscBanishDesc: "Wypędza daedrę będącą celem zaklęcia, jeśli jej poziom jest wystarczająco niski w porównaniu ze stopniem efektu. Odniesione przez daedrę obrażenia powodują większą podatność na wypędzenie. W przypadku sukcesu ważniejszy dobytek daedry znajdzie się w pozostawionej pieczęci." +Magic_miscReflectDamage: "Odbicie Obrażeń" +Magic_miscReflectDamageDesc: "Odbija fizyczne obrażenia w stronę atakującego. Stopień efektu określa procentową ilość odbitych obrażeń dla każdego ataku. Nieodbite obrażenia odniosą normalny skutek." +Magic_miscDetectHumanoid: "Wykrycie Humanoida" +Magic_miscDetectHumanoidDesc: "Rzucający zaklęcie może wykrywać na odległość obecność istot humanoidalnych. Zostaną one oznaczone na mapie specjalnym symbolem. Efekt obejmuje wszystkie postacie, a jego poziom to promień (w stopach) obszaru, który zostanie magicznie przeszukany." +Magic_miscRadiantShield: "Tarcza Blasku" +Magic_miscRadiantShieldDesc: "Tworzy świetlistą osłonę dookoła celu. Stopień efektu dodawany jest do klasy pancerza. Odporność celu na szkodliwe efekty magiczne wzrasta. Dodatkowo, krótkotrwale oślepia przeciwników w zwarciu." +Magic_miscWabbajack: "Łabadżak" +Magic_miscWabbajackDesc: "Łabadżak!" +Magic_miscInsight: "Intuicja" +Magic_miscInsightDesc: "Nieznacznie wypacza los, zwiększając szansę na znalezienie wartościowych przedmiotów." +Magic_miscArmorResartus: "Odnowienie Pancerza" +Magic_miscArmorResartusDesc: "Odnawia wyposażony zaklęty pancerz. Stopień efektu odpowiada ilości ładunku oraz stanu, która zostanie przywrócona, rozdzielając punkty pomiędzy wszyskie wyposażone zaklęte elementy pancerza." +Magic_miscWeaponResartus: "Odnowienie Broni" +Magic_miscWeaponResartusDesc: "Odnawia wyposażony zaklęty oręż. Stopień efektu odpowiada ilości ładunku oraz stanu, która zostanie przywrócona." +Magic_miscCorruption: "Wypaczenie" +Magic_miscCorruptionDesc: "Tworzy cienisty odpowiednik celu, który wspomoże rzucającego zaklęcie w walce." +Magic_miscDistractCreature: "Rozproszenie Istoty" +Magic_miscDistractCreatureDesc: "Zmusza istotę do oddalenia się z obecnej pozycji, jednocześnie próbując zachować dystans od rzucającego zaklęcie. Stopień efektu określa maksymalną odległość (w stopach), jaką cel może przebyć. Jeśli cel jest już pod wpływem efektu, nie może być rzucony ponownie. Efekt zawiedzie, jeśli cel jest świadomy obecności rzucającego zaklęcie. Po zakończeniu trwania efektu, cel nie może zostać rozproszony, dopóki nie powróci do oryginalnej pozycji." +Magic_miscDistractHumanoid: "Rozproszenie Humanoida" +Magic_miscDistractHumanoidDesc: "Zmusza osobę do oddalenia się z obecnej pozycji, jednocześnie próbując zachować dystans od rzucającego zaklęcie. Stopień efektu określa maksymalną odległość (w stopach), jaką cel może przebyć. Jeśli cel jest już pod wpływem efektu, nie może być rzucony ponownie. Efekt zawiedzie, jeśli cel jest świadomy obecności rzucającego zaklęcie. Po zakończeniu trwania efektu, cel nie może zostać rozproszony, dopóki nie powróci do oryginalnej pozycji." +Magic_miscGazeOfVeloth: "Wejrzenie Velotha" +Magic_miscGazeOfVelothDesc: "Doświadcz Oblicza Velotha!" +Magic_miscDetectEnemy: "Wykrycie Przeciwnika" +Magic_miscDetectEnemyDesc: "Rzucający zaklęcie może wykrywać na odległość obecność istot niemechanicznych. Zostaną one oznaczone na mapie specjalnym symbolem. Efekt obejmuje wszystkich przeciwników, a jego poziom to promień (w stopach) obszaru, który zostanie magicznie przeszukany." +Magic_miscDetectInvisibility: "Wykrycie Niewidzialności" +Magic_miscDetectInvisibilityDesc: "Rzucający zaklęcie może wykrywać na odległość obecność istot niemechanicznych. Zostaną one oznaczone na mapie specjalnym symbolem. Efekt obejmuje wszystkie istoty pod wpływem efektu kameleona lub niewidzialności, a jego poziom to promień (w stopach) obszaru, który zostanie magicznie przeszukany. Wykryte efekty kameleona oraz niewidzialności zostaną również osłabione." +Magic_miscBlink: "Migotanie" +Magic_miscBlinkDesc: "Teleportuje rzucającego zaklęcie w kierunku, w który patrzy. Stopień efektu określa maksymalną odległość (w stopach), jaki cel może przebyć." +Magic_miscFortifyCasting: "Premia do Magii" +Magic_miscFortifyCastingDesc: "Tymczasowo zwiększa szanse postaci na skuteczne rzucenie zaklęcia." +Magic_miscPrismaticLight: "Pryzmatyczne Światło" +Magic_miscPrismaticLightDesc: "Tworzy magiczny pocisk, który po uderzeniu w cel rozświetla na pewien czas okolicę. Nie zadaje obrażeń." +Magic_miscBloodMagic: "Magia Krwi" +Magic_miscBloodMagicDesc: "Tekst zastępczy" +Magic_miscSanguineRose: "Róża Sanguine'a" +Magic_miscSanguineRoseDesc: "Przywołuje z Otchłani losową 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_miscDetectValuables: "Wykrycie Kosztowności" +Magic_miscDetectValuablesDesc: "Rzucający zaklęcie może wykrywać na odległość kosztowne przedmioty. Stopień efektu określa promień (w stopach) obszaru, który zostanie magicznie przeszukany." + +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/actor_magic.lua b/Data Files/scripts/TamrielData/actor_magic.lua new file mode 100644 index 0000000..e0e8f47 --- /dev/null +++ b/Data Files/scripts/TamrielData/actor_magic.lua @@ -0,0 +1,294 @@ +local animation = require('openmw.animation') +local core = require('openmw.core') +local I = require('openmw.interfaces') +local nearby = require('openmw.nearby') +local self = require('openmw.self') +local types = require('openmw.types') +local util = require('openmw.util') +local auxUtil = require('openmw_aux.util') +local l10n = core.l10n('TamrielData') +local helpers = require('scripts.TamrielData.actor_magic_blink') + +local FT_TO_UNITS = 22.1 + +local activeEffects = self.type.activeEffects(self) +local activeSpells = self.type.activeSpells(self) + +local function calculateReflect(health, fatigue) + local reflectedHealth = 0 + local reflectedFatigue = 0 + for _, spell in pairs(activeSpells) do + for _, effect in pairs(spell.effects) do + if effect.id == 't_mysticism_reflectdmg' then + local mult = effect.magnitudeThisFrame / 100 + reflectedHealth = reflectedHealth + health * mult + health = health * (1 - mult) + reflectedFatigue = reflectedFatigue + fatigue * mult + fatigue = fatigue * (1 - mult) + end + end + end + if health <= 0 then + health = nil + end + if fatigue <= 0 then + fatigue = nil + end + if reflectedHealth <= 0 then + reflectedHealth = nil + end + if reflectedFatigue <= 0 then + reflectedFatigue = nil + end + return health, fatigue, reflectedHealth, reflectedFatigue +end + +I.Combat.addOnHitHandler(function(attack) + if not attack.successful or not attack.damage or not attack.attacker or not attack.attacker:isValid() then + return + elseif attack.sourceType ~= I.Combat.ATTACK_SOURCE_TYPES.Melee and attack.sourceType ~= I.Combat.ATTACK_SOURCE_TYPES.Ranged then + return + end + local health = attack.damage.health or 0 + local fatigue = attack.damage.fatigue or 0 + if health <= 0 and fatigue <= 0 then + return + elseif activeEffects:getEffect('t_mysticism_reflectdmg').magnitude <= 0 then + return + end + local newHealth, newFatigue, reflectedHealth, reflectedFatigue = calculateReflect(health, fatigue) + local reflectedAttack = auxUtil.shallowCopy(attack) + reflectedAttack.attacker = self.object + reflectedAttack.sourceType = I.Combat.ATTACK_SOURCE_TYPES.Unspecified + reflectedAttack.damage = {} + if attack.damage.health then + attack.damage.health = newHealth + reflectedAttack.damage.health = reflectedHealth + end + if attack.damage.fatigue then + attack.damage.fatigue = newFatigue + reflectedAttack.damage.fatigue = reflectedFatigue + end + attack.attacker:sendEvent('Hit', reflectedAttack) +end) + +local function getDistractDestination(caster, range) + local casterPos = caster and caster.position + local selfPos = self.position + local agentBounds = self.type.getPathfindingAgentBounds(self) + + local function getCasterPenalty(candidate) + if not casterPos then + return 0 + end + local status, path = nearby.findPath(selfPos, candidate, { agentBounds = agentBounds }) + local penalty = (candidate - casterPos):length() * 0.25 + if status == nearby.FIND_PATH_STATUS.Success and next(path) then + local min = math.huge + for _, point in pairs(path) do + local distance = (point - casterPos):length2() + min = math.min(min, distance) + end + penalty = penalty + min + end + return penalty + end + + local bestPos = nil + local bestScore = 0 + local SAMPLES = 12 + + for i = 1, SAMPLES do + local candidate = nearby.findRandomPointAroundCircle(selfPos, range, { agentBounds = agentBounds }) + if candidate and math.abs(candidate.z - selfPos.z) < 384 then + local score = getCasterPenalty(candidate) + (candidate - selfPos):length() * 0.5 + if score > bestScore then + bestScore = score + bestPos = candidate + end + end + end + return bestPos +end + +function playDistractedVoiceLine(isEnd) + if types.NPC.objectIsInstance(self) and not self.type.isDead(self) and not self.type.isWerewolf(self) and activeEffects:getEffect('Vampirism').magnitude <= 0 then + -- Handling this in a global script so we only need one instance of the voice lines table in memory + core.sendGlobalEvent('T_DistractVoice', { actor = self.object, isEnd = isEnd }) + end +end + +local state = {} + +local timer = 0 + +return { + engineHandlers = { + onInactive = function() + core.sendGlobalEvent('T_ActorInactive', self.object) + end, + onSave = function() + return state + end, + onLoad = function(data) + if data then + state = data + end + end, + onUpdate = function(dt) + if not state.distract or not state.distract.returning then + return + end + timer = timer + dt + if timer >= 1 then + timer = 0 + local active = I.AI.getActivePackage() + if not active or active.type ~= 'Travel' then + self.type.stats.ai.hello(self).base = state.distract.hello + local resetRotation = true + if state.distract.wander then + resetRotation = state.distract.wander.distance == 0 + I.AI.startPackage(state.distract.wander) + end + if resetRotation then + local yaw = self.rotation:getYaw() + self.controls.yawChange = state.distract.originYaw - yaw + end + state.distract = nil + end + end + end + }, + eventHandlers = { + Died = function() + state.distract = nil + if state.banish then + core.sendGlobalEvent('T_BanishCorpse', { actor = self.object, height = state.banish }) + state.banish = nil + end + end, + T_Distract = function(data) + local active = I.AI.getActivePackage() + if active and active.type ~= 'Wander' then + return + end + local destination = getDistractDestination(data.caster, data.magnitude * FT_TO_UNITS) + if destination then + if not state.distract then + local hello = self.type.stats.ai.hello(self) + state.distract = { + hello = hello.base, + origin = self.position, + originYaw = self.rotation:getYaw(), + worldSpace = self.cell.worldSpaceId + } + if active then + state.distract.wander = { + type = 'Wander', + distance = active.distance, + duration = active.duration, + idle = active.idle and auxUtil.shallowCopy(active.idle), + isRepeat = active.isRepeat + } + end + hello.base = 0 + end + state.distract.returning = false + if math.random() < 0.45 then + playDistractedVoiceLine(false) + end + I.AI.startPackage({ type = 'Travel', destPosition = destination, cancelOther = true, isRepeat = false }) + end + end, + T_DistractFinished = function(effect) + if not state.distract then + return + end + if activeEffects:getEffect(effect).magnitude <= 0 then + state.distract.returning = true + if math.random() < 0.45 then + playDistractedVoiceLine(true) + end + if self.cell and self.cell.worldSpaceId == state.distract.worldSpace then + timer = 0 + I.AI.startPackage({ type = 'Travel', destPosition = state.distract.origin, cancelOther = true, isRepeat = false }) + end + end + end, + T_MarkWabbajack = function(data) + local dynamic = types.Actor.stats.dynamic + for _, key in pairs({ 'health', 'magicka', 'fatigue' }) do + local stat = dynamic[key](self) + local v = stat.base * data[key] + if v < 2 and key == 'health' then + v = 2 + end + stat.current = v + end + core.sound.playSound3d('alteration hit', self, { loop = false }) + activeSpells:add({ id = 'T_Dae_Alt_UNI_WabbajackTrans', effects = { 0 }, ignoreResistances = true, ignoreSpellAbsorption = true, ignoreReflect = true, caster = data.caster }) + end, + T_EndWabbajack = function(data) + local dynamic = types.Actor.stats.dynamic + local kill = false + for _, key in pairs({ 'health', 'magicka', 'fatigue' }) do + local stat = dynamic[key](self) + local v = stat.base * data[key] + if key == 'health' and v < 2 then + kill = data[key] <= 0 + v = 2 + end + stat.current = v + end + core.sound.playSound3d('alteration hit', self, { loop = false }) + if kill then + -- makes crime work + -- TODO: !5302 + types.Actor._onHit(self, { + damage = { health = 999 }, + sourceType = I.Combat.ATTACK_SOURCE_TYPES.Unspecified, + attacker = data.caster, + successful = true + }) + end + end, + T_AttemptBanish = function(data) + for _, actor in pairs(I.AI.getTargets('Follow')) do -- Could check Escort as well, I guess + if actor == data.caster then + return + end + end + local targetLevel = types.Actor.stats.level(self).current + local health = types.Actor.stats.dynamic.health(self) + if data.magnitude < targetLevel / 2 * (1 + health.current / math.max(health.base, 1)) then + I.AI.startPackage({ type = 'Combat', target = data.caster }) + if types.Player.objectIsInstance(data.caster) then + local record = self.type.records[self.recordId] + local name = record.name + if not name or name == '' then + name = record.id + end + data.caster:sendEvent('ShowMessage', { message = l10n('Magic_banishFailure', { target = name }) }) + end + return + end + activeEffects:remove('soultrap') + state.banish = self.type.getPathfindingAgentBounds(self).halfExtents.z * 2 -- yields better results than getBoundingBox + I.AnimationController.addPlayBlendedAnimationHandler(function(groupName, options) + if groupName:find('death') then + options.speed = 100 + end + end) + health.current = 0 + local model = types.Static.records['T_VFX_Banish'].model + core.sendGlobalEvent('SpawnVfx', { model = model, position = self.position }) + core.sound.playSound3d('mysticism hit', self) -- TODO !3029 + end, + T_Blink = function(magnitude) + -- TODO: check if levitation is disabled + local destination, options = helpers.getBlinkDestination(magnitude) + -- TODO: don't use teleportation and preserve momentum + core.sendGlobalEvent('T_Teleport', { object = self.object, cell = self.cell.id, position = destination, options = options }) + end + } +} diff --git a/Data Files/scripts/TamrielData/actor_magic_blink.lua b/Data Files/scripts/TamrielData/actor_magic_blink.lua new file mode 100644 index 0000000..a13f999 --- /dev/null +++ b/Data Files/scripts/TamrielData/actor_magic_blink.lua @@ -0,0 +1,45 @@ +local core = require('openmw.core') +local nearby = require('openmw.nearby') +local self = require('openmw.self') +local util = require('openmw.util') + +local FT_TO_UNITS = 22.1 +local BLINK_COLLISION = nearby.COLLISION_TYPE.AnyPhysical + nearby.COLLISION_TYPE.VisualOnly - nearby.COLLISION_TYPE.Water - nearby.COLLISION_TYPE.Projectile + +local function getBlinkDestination(magnitude) + local range = magnitude * FT_TO_UNITS + local halfExtents = self.type.getPathfindingAgentBounds(self).halfExtents + local start = self.position + util.vector3(0, 0, halfExtents.z * 1.4) + local destination = start + self.rotation * util.vector3(0, range, 0) + local rayOptions = { ignore = self, collisionType = BLINK_COLLISION } + local result = nearby.castRay(start, destination, rayOptions) + local options + local ground + if result.hit then + destination = result.hitPos - self.rotation * util.vector3(0, halfExtents.y + 16, 0) + end + local height = util.vector3(0, 0, halfExtents.z * 2) + result = nearby.castRay(destination, destination + height, rayOptions) + if result.hit then -- bumped into the ceiling + local floor = result.hitPos - height + rayOptions.ignore = result.hitObject + result = nearby.castRay(result.hitPos, floor, rayOptions) + if result.hit then -- bumped into the floor; no room here + destination = self.position + else + destination = floor + end + end + if self.cell.isExterior then + local height = core.land.getHeightAt(destination, self.cell) + if destination.z < height then + ground = height + options = { onGround = true } + end + end + return destination, options, ground +end + +return { + getBlinkDestination = getBlinkDestination +} diff --git a/Data Files/scripts/TamrielData/actor_summons.lua b/Data Files/scripts/TamrielData/actor_summons.lua new file mode 100644 index 0000000..30f1b83 --- /dev/null +++ b/Data Files/scripts/TamrielData/actor_summons.lua @@ -0,0 +1,76 @@ +local core = require('openmw.core') + +if not core.magic.effects.records['T_summon_Devourer'] and not core.magic.effects.records['T_conjuration_SanguineRose'] then + return +end + +local I = require('openmw.interfaces') +local nearby = require('openmw.nearby') +local self = require('openmw.self') +local util = require('openmw.util') + +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 + +local state = {} + +return { + eventHandlers = { + T_GetSummonPosition = function(data) + local position = getSafeSpawn() + data.position = position + core.sendGlobalEvent('T_Summon', data) + end, + T_MarkSummon = function(data) + state.caster = data.caster + state.id = data.id + state.index = data.index + self.type.stats.ai.fight(self).base = 30 -- we should probably be using dedicated creature variants + if data.tag == 't_conjuration_corruptionsummon' then + self.type.stats.ai.alarm(self).base = 0 + self.type.stats.ai.flee(self).base = 0 + self.type.stats.ai.hello(self).base = 0 + end + end, + Died = function() + if state.caster ~= nil then + core.sendGlobalEvent('T_Unsummon', { creature = self.object, caster = state.caster, id = state.id, index = state.index }) + end + end + }, + engineHandlers = { + onSave = function() + return state + end, + onLoad = function(data) + if data then + state = data + end + end + } +} diff --git a/Data Files/scripts/TamrielData/container_banish.lua b/Data Files/scripts/TamrielData/container_banish.lua new file mode 100644 index 0000000..933069e --- /dev/null +++ b/Data Files/scripts/TamrielData/container_banish.lua @@ -0,0 +1,31 @@ +local core = require('openmw.core') +local self = require('openmw.self') + +local state + +local timer = math.random() + +return { + engineHandlers = { + onInit = function(light) + state = light + end, + onSave = function() + return state + end, + onLoad = function(data) + state = data + end, + onUpdate = function(dt) + timer = timer + dt + if timer < 1 then + return + end + timer = timer - 1 + for _, item in pairs(self.type.inventory(self):getAll()) do + return + end + core.sendGlobalEvent('T_BanishContainer', { container = self.object, light = state }) + 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..38c7000 --- /dev/null +++ b/Data Files/scripts/TamrielData/global_magic.lua @@ -0,0 +1,242 @@ +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, dt) + local track = { ignore = false } + auxUtil.callEventHandlers(effectUpdateHandlers, actor, spell, effect, dt, 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 MAX_WAIT = 0.25 + +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() * MAX_WAIT, + 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 = {}, + actor = actor + } + persistentState.actors[id] = state + tempState[id] = initActorState(actor, state) + elseif not tempState[id] then + tempState[id] = { + waited = math.random() * MAX_WAIT, + 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, dt) + 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 + elseif s == STATE_ONCE then + canDiscard = false + end + if s == STATE_ACTIVE then + if onEffectUpdate(actor, spell, effect, dt) 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 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, dt) +end + +local activeActors = world.activeActors + +return { + engineHandlers = { + onSave = function() + return persistentState + end, + 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) + 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, 0) + 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_magic_passwall.lua b/Data Files/scripts/TamrielData/global_magic_passwall.lua deleted file mode 100644 index aa94041..0000000 --- a/Data Files/scripts/TamrielData/global_magic_passwall.lua +++ /dev/null @@ -1,51 +0,0 @@ -if not require("scripts.TamrielData.utils.version_check").isFeatureSupported("miscSpells") then - return -end - -local types = require('openmw.types') -local world = require('openmw.world') -local crimes = require('openmw.interfaces').Crimes - -local function triggerCrimeIfTrespassing(data) - if not data.targetObject or not data.targetObject.owner or not types.Lockable.isLocked(data.targetObject) then - return - end - - if data.targetObject.globalVariable and world.mwscript.getGlobalVariables(data.player)[data.targetObject.globalVariable] ~= 0 then - return - end - - local ownerData = data.targetObject.owner - - local isTrespassing = - ownerData.recordId - or - (ownerData.factionId and types.NPC.getFactionRank(data.player, ownerData.factionId) == 0) - or - (ownerData.factionId and types.NPC.getFactionRank(data.player, ownerData.factionId) < (ownerData.factionRank or 1)) - - if isTrespassing then - crimes.commitCrime( - data.player, - { - faction = ownerData.factionId, - type = types.Player.OFFENSE_TYPE.Trespassing - } - ) - end -end - -local function teleportPlayer(data) - data.player:teleport(data.cell, data.position, { onGround = true, rotation = data.rotation }) - - triggerCrimeIfTrespassing(data) - - local passwall_target_effect_model = types.Static.records[data.vfxStatic].model - world.vfx.spawn(passwall_target_effect_model, data.position) -end - -return { - eventHandlers = { - T_Passwall_teleportPlayer = teleportPlayer, - } -} diff --git a/Data Files/scripts/TamrielData/global_miscspells.lua b/Data Files/scripts/TamrielData/global_miscspells.lua new file mode 100644 index 0000000..ffcd750 --- /dev/null +++ b/Data Files/scripts/TamrielData/global_miscspells.lua @@ -0,0 +1,476 @@ +local core = require('openmw.core') +local passwallEffect = core.magic.effects.records['T_mysticism_Passwall'] + +if not passwallEffect then + return +end + +local I = require('openmw.interfaces') +local types = require('openmw.types') +local util = require('openmw.util') +local world = require('openmw.world') +local l10n = core.l10n('TamrielData') +local magicData = require('MWSE.mods.TamrielData.magicdata') + +local passwall_target_effect_model = types.Static.records[passwallEffect.hitStatic].model +local distractedVoices = {} +for _, line in pairs(magicData.distractedVoiceLines) do + local raceID, isFemale, voicesStart, voicesEnd = unpack(line) + raceID = raceID:lower() + distractedVoices[raceID] = distractedVoices[raceID] or {} + distractedVoices[raceID][isFemale and "female" or "male"] = { voicesStart, voicesEnd } +end +local safeScripts = {} +for k, v in pairs(magicData.safeScripts) do + safeScripts[k:lower()] = v +end +local wabbajackVfx = types.Static.records['T_VFX_Wabbajack'].model + +local function triggerCrimeIfTrespassing(data) + if not data.targetObject or not data.targetObject.owner or not types.Lockable.isLocked(data.targetObject) then + return + end + + if data.targetObject.globalVariable and world.mwscript.getGlobalVariables(data.player)[data.targetObject.globalVariable] ~= 0 then + return + end + + local ownerData = data.targetObject.owner + + local isTrespassing = + ownerData.recordId + or + (ownerData.factionId and types.NPC.getFactionRank(data.player, ownerData.factionId) == 0) + or + (ownerData.factionId and types.NPC.getFactionRank(data.player, ownerData.factionId) < (ownerData.factionRank or 1)) + + if isTrespassing then + I.Crimes.commitCrime( + data.player, + { + faction = ownerData.factionId, + type = types.Player.OFFENSE_TYPE.Trespassing + } + ) + end +end + +local function teleportPlayer(data) + data.player:teleport(data.cell, data.position, { onGround = true, rotation = data.rotation }) + + triggerCrimeIfTrespassing(data) + + world.vfx.spawn(passwall_target_effect_model, data.position) +end + +local function resartusEquipment(actor, magnitude, type) + if magnitude <= 0 then + return + end + local equipment = actor.type.getEquipment(actor) + local toFix = {} + for slot, item in pairs(equipment) do + if type.objectIsInstance(item) then + local data = types.Item.itemData(item) + local record = item.type.records[item.recordId] + local maxHealth = record.health + local maxCharge = 0 + if record.enchant then + local enchantment = core.magic.enchantments.records[record.enchant] + if enchantment then + -- FIXME: this is incorrect for autocalc + maxCharge = enchantment.charge + end + end + local hasDamage = data.condition and data.condition < maxHealth + local missingCharge = data.enchantmentCharge and data.enchantmentCharge < maxCharge + if hasDamage or missingCharge then + table.insert(toFix, { + data = data, + hasDamage = hasDamage, + missingCharge = missingCharge, + maxHealth = maxHealth, + maxCharge = maxCharge + }) + end + end + end + local healthRemaining = magnitude + local chargeRemaining = magnitude + while healthRemaining > 0 and chargeRemaining > 0 do + local changed = false + for _, data in pairs(toFix) do + if data.hasDamage and healthRemaining > 0 then + local health = math.min(data.data.condition + 1, data.maxHealth) + data.hasDamage = health ~= data.maxHealth + data.data.condition = health + healthRemaining = healthRemaining - 1 + changed = true + end + if data.missingCharge and chargeRemaining > 0 then + local charge = math.min(data.data.enchantmentCharge + 1, data.maxCharge) + data.missingCharge = charge ~= data.maxCharge + data.data.enchantmentCharge = charge + chargeRemaining = chargeRemaining - 1 + changed = true + end + end + if not changed then + break + end + end +end + +local function playDistractedVoiceLine(data) + local record = data.actor.type.records[data.actor.recordId] + local race = distractedVoices[record.race] + if not race then + return + end + local lines = race[record.isMale and "male" or "female"] + if lines then + local files = data.isEnd and lines[2] or lines[1] + local path = files and files[math.random(#files)] + if path then + core.sound.say('sound/' .. path, data.actor) + end + end +end + +local function banishCorpse(data) + local actor = data.actor + if not actor.type.isDead(actor) then + return -- Somehow Palpascamp returned + end + local items = {} + for _, item in pairs(actor.type.inventory(actor):getAll()) do + -- TODO: filter items. Don't copy MWSE, it doesn't account for script added items + if not types.Ingredient.objectIsInstance(item) then + table.insert(items, item) + end + end + if #items > 0 then + local container = world.createObject('T_Glb_BanishDae_Empty') + for _, item in pairs(items) do + item:moveInto(container) + end + local rotation = util.transform.rotateZ(actor.rotation:getYaw()) + local position = actor.position + util.vector3(0, 0, data.height) + container:teleport(actor.cell, position, rotation) + local light = world.createObject('T_Glb_BanishDae_Light') + light:teleport(actor.cell, position, rotation) + container:addScript('scripts/TamrielData/container_banish.lua', light) + end + actor:teleport('T_Banish', util.vector3(0, 0, 0)) +end + +local function banishContainer(data) + data.container:remove() + data.light:remove() +end + +local function canBeCorrupted(target) + if types.Player.objectIsInstance(target) then + return false + end + local record = target.type.records[target.recordId] + local script = record.mwscript + if script and not (script:find("t_scnpc") and not script:find("_were") or safeScripts[script]) then + return false + end + for _, item in pairs(target.type.inventory(target):getAll()) do + if item.type.records[item.recordId].mwscript then + return false + end + end + return true +end + +local function restoreCharge(item, caster) + --TODO !3029 + if not item or not I.SpellCasting then + return + end + local charge = I.SpellCasting.getCostCharge(item, caster) + local data = types.Item.itemData(item) + --TODO cap + data.enchantmentCharge = data.enchantmentCharge + charge +end + +local function toKey(actor, id, index) + return actor.id .. ',' .. id .. ',' .. index +end + +local state = { + effects = {}, + wabbajack = {} +} + +local function store(target, spell, effect) + local id = spell.activeSpellId + local index = effect.index + local key = toKey(target, id, index) + state.effects[key] = { id = id, index = index, actor = target, magnitude = effect.magnitudeThisFrame, effect = effect.id } +end + +local function distract(type) + return function(target, spell, effect, track) + if type.objectIsInstance(target) and not types.Player.objectIsInstance(target) then + target:sendEvent('T_Distract', { magnitude = effect.magnitudeThisFrame, caster = spell.caster }) + store(target, spell, effect) + track.ignore = false + else + target.type.activeEffects(target):remove(effect.id) + end + end +end + +local function getName(record) + local name = record.name + if not name or name == '' then + return record.id + end + return name +end + +local onStart = { + t_mysticism_passwall = function(target, spell, effect, track) + if types.Player.objectIsInstance(target) then + track.ignore = false + target:sendEvent('T_Passwall_Cast', effect.magnitudeThisFrame) + end + end, + t_mysticism_banishdae = function(target, spell, effect, track) + if types.Creature.objectIsInstance(target) and not state.wabbajack[target.id] then + local record = types.Creature.records[target.recordId] + if record.type == types.Creature.TYPE.Daedra then + track.ignore = false + target:sendEvent('T_AttemptBanish', { caster = spell.caster, magnitude = effect.magnitudeThisFrame }) + return + end + end + target.type.activeEffects(target):remove(effect.id) + end, + t_mysticism_reflectdmg = function(target, spell, effect, track) + track.ignore = false + end, + t_alteration_wabbajack = function(target, spell, effect, track) + local record = target.type.records[target.recordId] + if types.Creature.objectIsInstance(target) and not record.canWalk and not record.isBiped or types.Player.objectIsInstance(target) then + target.type.activeEffects(target):remove(effect.id) + restoreCharge(spell.item, spell.caster) + return + end + local level = target.type.stats.level(target).current + if level >= 30 then + if spell.caster and types.Player.objectIsInstance(spell.caster) then + spell.caster:sendEvent('ShowMessage', { message = l10n('Magic_wabbajackFailure', { target = getName(record) }) }) + core.sound.playSound3d('Spell Failure Alteration', target, { loop = false }) + end + target.type.activeEffects(target):remove(effect.id) + restoreCharge(spell.item, spell.caster) + return + end + local data = state.wabbajack[target.id] + if data then + if spell.caster and types.Player.objectIsInstance(spell.caster) then + spell.caster:sendEvent('ShowMessage', { message = l10n('Magic_wabbajackAlready', { target = data.name }) }) + core.sound.playSound3d('Spell Failure Alteration', target, { loop = false }) + end + target.type.activeEffects(target):remove(effect.id) + restoreCharge(spell.item, spell.caster) + return + end + local maxDuration = 16 + local minDuration = 4 + local effectiveLevel = 0 + if level > 5 then + effectiveLevel = level - 5 + end + local duration = maxDuration - (maxDuration - minDuration) * (effectiveLevel / 24) + local creature = world.createObject(magicData.wabbajackCreatures[math.random(#magicData.wabbajackCreatures)]) + data = { name = getName(record), target = target, duration = duration, actor = creature, caster = spell.caster } + state.wabbajack[creature.id] = data + creature:teleport(target.cell, target.position, target.rotation) + local event = { caster = spell.caster } + local dynamic = types.Actor.stats.dynamic + for _, key in pairs({ 'health', 'magicka', 'fatigue' }) do + local stat = dynamic[key](target) + event[key] = stat.current / math.max(stat.base, 1) + end + creature:sendEvent('T_MarkWabbajack', event) + creature:sendEvent('StartAIPackage', { type = 'Follow', target = target }) -- Makes the guards ignore the creature + creature:sendEvent('StartAIPackage', { type = 'Combat', target = spell.caster, cancelOther = false }) + creature:sendEvent('AddVfx', { model = wabbajackVfx }) + target:teleport('T_Wabbajack', util.vector3(0, 0, 53.187)) + track.ignore = false + end, + t_alteration_wabbajackhelper = function(target, spell, effect, track) + store(target, spell, effect) + track.ignore = false + end, + t_restoration_armorresartus = function(target, spell, effect, track) + resartusEquipment(target, effect.magnitudeThisFrame, types.Armor) + track.ignore = false + end, + t_restoration_weaponresartus = function(target, spell, effect, track) + resartusEquipment(target, effect.magnitudeThisFrame, types.Weapon) + track.ignore = false + end, + t_conjuration_corruption = function(target, spell, effect, track) + if not spell.caster or not spell.caster:isValid() then + return + end + if I.T_SummonMagic.isCorruptionSummon(target) then + if types.Player.objectIsInstance(spell.caster) then + spell.caster:sendEvent('ShowMessage', { message = l10n('Magic_corruptionSummon') }) + end + target.type.activeEffects(target):remove(effect.id) + restoreCharge(spell.item, spell.caster) + elseif canBeCorrupted(target) then + I.T_SummonMagic.setCorruptedId(spell.caster, target.recordId) + track.ignore = false + types.Actor.activeSpells(spell.caster):add({ id = 'T_Dae_Cnj_UNI_CorruptionSummon', effects = { 0 }, ignoreResistances = true, ignoreSpellAbsorption = true, ignoreReflect = true, caster = spell.caster }) + else + if types.Player.objectIsInstance(spell.caster) then + local record = target.type.records[target.recordId] + spell.caster:sendEvent('ShowMessage', { message = l10n('Magic_corruptionScript', { target = getName(record) }) }) + end + target.type.activeEffects(target):remove(effect.id) + restoreCharge(spell.item, spell.caster) + end + end, + t_illusion_distractcreature = distract(types.Creature), + t_illusion_distracthumanoid = distract(types.NPC), + t_mysticism_blink = function(target, spell, effect, track) + target:sendEvent('T_Blink', effect.magnitudeThisFrame) + track.ignore = false + end, + t_restoration_fortifycasting = function(target, spell, effect, track) + local activeEffects = target.type.activeEffects(target) + activeEffects:modify(-effect.magnitudeThisFrame, 'sound') + store(target, spell, effect) + track.ignore = false + end, +} + +local onUpdate = { + t_alteration_wabbajackhelper = function(target, spell, effect, dt, track) + -- TODO: replace this with a regular duration when possible and make the affect apply once + local data = state.wabbajack[target.id] + if data then + data.duration = data.duration - dt + if data.duration <= 0 then + target.type.activeEffects(target):remove(effect.id) + end + else + track.ignore = true + end + end +} + +local onEnd = { + t_restoration_fortifycasting = function(effect) + local activeEffects = effect.actor.type.activeEffects(effect.actor) + activeEffects:modify(effect.magnitude, 'sound') + end, + t_illusion_distractcreature = function(effect) + effect.actor:sendEvent('T_DistractFinished', effect.effect) + end, + t_illusion_distracthumanoid = function(effect) + effect.actor:sendEvent('T_DistractFinished', effect.effect) + end, + t_alteration_wabbajackhelper = function(effect) + local creature = effect.actor + local data = state.wabbajack[creature.id] + if not data then + return + end + state.wabbajack[creature.id] = nil + local target = data.target + if target:isValid() then + target:teleport(creature.cell, creature.position, creature.rotation) + local event = { caster = data.caster } + local dynamic = types.Actor.stats.dynamic + for _, key in pairs({ 'health', 'magicka', 'fatigue' }) do + local stat = dynamic[key](creature) + event[key] = stat.current / math.max(stat.base, 1) + end + target:sendEvent('T_EndWabbajack', event) + target:sendEvent('AddVfx', { model = wabbajackVfx }) + end + creature:remove() + end +} + +I.T_ActorMagic.addEffectStartHandler(function(target, spell, effect, track) + local handler = onStart[effect.id] + if handler then + handler(target, spell, effect, track) + end +end) + +I.T_ActorMagic.addEffectUpdateHandler(function(target, spell, effect, dt, track) + local handler = onUpdate[effect.id] + if handler then + handler(target, spell, effect, dt, track) + end +end) + +I.T_ActorMagic.addEffectEndHandler(function(actor, id, index) + local key = toKey(actor, id, index) + local effect = state.effects[key] + if effect then + local handler = onEnd[effect.effect] + if handler then + handler(effect) + end + state.effects[key] = nil + end +end) + +return { + engineHandlers = { + onSave = function() + return state + end, + onLoad = function(data) + if data then + state = data + local effects = {} + for _, actorData in pairs(data.effects) do + if actorData.actor:isValid() then + local key = toKey(actorData.actor, actorData.id, actorData.index) + effects[key] = actorData + end + end + state.effects = effects + local wabbajack = {} + for _, actorData in pairs(data.wabbajack) do + if actorData.actor:isValid() then + wabbajack[actor.id] = actorData + end + end + state.wabbajack = wabbajack + end + end + }, + eventHandlers = { + T_Passwall_teleportPlayer = teleportPlayer, + T_DistractVoice = playDistractedVoiceLine, + T_BanishCorpse = banishCorpse, + T_BanishContainer = banishContainer, + T_Teleport = function(data) + data.object:teleport(world.getCellById(data.cell), data.position, data.options or data.rotation) + end, + T_BlinkIndicator = function(data) + local vfxId = 'T_BlinkIndicator' .. data.actor.id + world.vfx.remove(vfxId) + if data.position then + local options = { vfxId = vfxId, loop = true } + world.vfx.spawn('meshes/td/td_vfx_blink_indicator.nif', data.position, options) + world.vfx.spawn('meshes/td/td_vfx_blink_ground.nif', data.groundPos or data.position, options) + end + 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..2977ad8 --- /dev/null +++ b/Data Files/scripts/TamrielData/global_summons.lua @@ -0,0 +1,155 @@ +local core = require('openmw.core') + +if not core.magic.effects.records['T_summon_Devourer'] and not core.magic.effects.records['T_conjuration_SanguineRose'] 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 = {}, + corruption = {}, + corruptionSummons = {} +} + +local function toKey(actor, id, index) + return actor.id .. ',' .. id .. ',' .. index +end + +local function getSummon(effectId, caster) + if effectId == 't_conjuration_sanguinerose' then + return magicData.sanguineRoseDaedra[math.random(#magicData.sanguineRoseDaedra)] + elseif effectId == 't_conjuration_corruptionsummon' then + local target = state.corruption[caster.id] + return target and target.id or 'T_Glb_Cre_Gremlin_01', effectId + end + return summons[effectId] +end + +I.T_ActorMagic.addEffectStartHandler(function(caster, spell, effect, track) + local creature, tag = getSummon(effect.id, caster) + 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, actor = caster, tag = tag } + caster:sendEvent('T_GetSummonPosition', { key = key }) + track.ignore = false +end) + +local function unsummon(creature) + if creature:isValid() then + state.corruptionSummons[creature.id] = nil + world.vfx.spawn(startVfx, creature.position) + creature:remove() + end +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 then + unsummon(creature) + end + state.summons[key] = nil +end) + +local function blockActivation() + return false +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 + 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 + local corruption = {} + for _, actorData in pairs(data.corruption) do + if actorData.actor:isValid() then + corruption[actorData.actor.id] = actorData + end + end + state.corruption = corruption + local corruptionSummons = {} + for _, actor in pairs(data.corruptionSummons) do + if actor:isValid() then + corruptionSummons[actor.id] = actor + end + end + state.corruptionSummons = corruptionSummons + end + end + }, + eventHandlers = { + T_Summon = function(data) + local effect = state.summons[data.key] + if not effect then + return + end + local creature = world.createObject(effect.creatureId) + local caster = effect.actor + creature:teleport(caster.cell, data.position, { onGround = true }) + creature:sendEvent('StartAIPackage', { type = 'Follow', target = caster }) + creature:sendEvent('T_MarkSummon', { index = effect.index, id = effect.id, caster = caster, tag = effect.tag }) + creature:sendEvent('AddVfx', { model = startVfx }) + effect.creatureId = nil + effect.creature = creature + if effect.tag == 't_conjuration_corruptionsummon' then + state.corruptionSummons[creature.id] = creature + I.Activation.addHandlerForObject(creature, blockActivation) + end + end, + T_Unsummon = function(data) + unsummon(data.creature) + local key = toKey(data.caster, data.id, data.index) + local effect = state.summons[key] + if effect then + state.summons[key] = nil + I.T_ActorMagic.removeEffect(data.caster, effect.id, effect.index) + end + end + }, + interfaceName = 'T_SummonMagic', + interface = { + version = 1, + setCorruptedId = function(caster, id) + if id then + state.corruption[caster.id] = { actor = caster, id = id } + else + state.corruption[caster.id] = nil + end + end, + isCorruptionSummon = function(actor) + return state.corruptionSummons[actor.id] or false + 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..a20030c --- /dev/null +++ b/Data Files/scripts/TamrielData/load_magic.lua @@ -0,0 +1,246 @@ +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') + +local function t(key) + if not key then + return '' + end + 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 + if row.id == 'T_mysticism_Passwall' then + row.range = RANGE.self + row.magnitudeMin = row.area + row.magnitudeMax = row.area + row.area = nil + else + row.range = RANGE[row.range] + row.magnitudeMin = row.min or row.magnitude + row.magnitudeMax = row.max or row.magnitude + end + row.min = nil + row.max = nil + row.magnitude = nil + end + return implemented, effects +end + +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 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 implemented, effects = parseEffects(values, 4) + local spell = spells[id] + if spell and implemented then + if cost then + spell.cost = cost + end + spell.type = types[type] + if name then + spell.name = t(name) + end + spell.effects = effects + end + 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 + effect.affectedSkill = row.skill + end + end + end + end +end + +local function addSummons() + local effects = content.magicEffects.records + for _, values in pairs(magicData.td_summon_effects) do + local id, name, creature, cost, icon, desc, template = unpack(values) + if template == 'callBear' then + template = 'summonbear' + end + effects[id] = { template = effects[template], baseCost = cost, icon = icon, name = t(name), description = t(desc), allowsSpellmaking = true, allowsEnchanting = true } + implementedEffects[id] = true + end +end + +local function addMiscEffects() + local effects = content.magicEffects.records + local function addMiscEffect(id, params) + local name, cost, icon, desc, template = unpack(magicData.td_misc_effects[id]) + params.name = t(name) + params.baseCost = params.baseCost or cost + params.icon = icon + params.description = t(desc) + params.template = effects[template] + effects[id] = params + implementedEffects[id] = true + end + addMiscEffect('T_mysticism_Passwall', { + onTarget = false, onTouch = false, hasDuration = false, + baseCost = magicData.td_misc_effects.T_mysticism_Passwall[2] * 0.5 -- compensate for MWSE using area instead of magnitude + }) + addMiscEffect('T_mysticism_BanishDae', { + hasDuration = false, hasMagnitude = true, unreflectable = true, hitSound = 'T_SndObj_Silence', + hitStatic = 'T_VFX_Empty', areaSound = 'T_SndObj_Silence', areaStatic = 'T_VFX_Empty', harmful = false + }) + addMiscEffect('T_mysticism_ReflectDmg', {}) + --addMiscEffect('T_mysticism_DetHuman', {}) -- Requires map dehardcoding + --addMiscEffect('T_alteration_RadShield', {}) -- Requires a (more elegant) way of applying variable magnitude blind effects + addMiscEffect('T_alteration_Wabbajack', { + allowsSpellmaking = false, allowsEnchanting = false, hasDuration = false, onSelf = false, onTarget = true, + onTouch = true, harmful = true, unreflectable = true, hitSound = 'T_SndObj_Silence', hitStatic = 'T_VFX_Empty', + areaSound = 'T_SndObj_Silence', areaStatic = 'T_VFX_Empty' + }) + addMiscEffect('T_alteration_WabbajackHelper', { + isAppliedOnce = false, allowsSpellmaking = false, allowsEnchanting = false, onSelf = false, onTarget = true, + onTouch = true, unreflectable = true, hitSound = 'T_SndObj_Silence', hitStatic = 'T_VFX_Empty' + }) + addMiscEffect('T_restoration_ArmorResartus', { hasDuration = false }) + addMiscEffect('T_restoration_WeaponResartus', { hasDuration = false }) + addMiscEffect('T_conjuration_Corruption', { + allowsSpellmaking = false, allowsEnchanting = false, hasDuration = false, onSelf = false, + onTarget = true, onTouch = true, harmful = true, unreflectable = true + }) + addMiscEffect('T_conjuration_CorruptionSummon', { allowsSpellmaking = false, allowsEnchanting = false }) + addMiscEffect('T_illusion_DistractCreature', { unreflectable = true, onSelf = false, harmful = false }) + addMiscEffect('T_illusion_DistractHumanoid', { unreflectable = true, onSelf = false, harmful = false }) + addMiscEffect('T_mysticism_Blink', { hasDuration = false, hitSound = 'T_SndObj_BlinkHit', hitStatic = 'T_VFX_Empty' }) + addMiscEffect('T_restoration_FortifyCasting', {}) + addMiscEffect('T_conjuration_SanguineRose', { allowsSpellmaking = false, allowsEnchanting = false }) +end + +return { + engineHandlers = { + onContentFilesLoaded = function() + if version_check.isFeatureEnabled('summoningSpells') then + addSummons() + end + if version_check.isFeatureEnabled('miscSpells') then + addMiscEffects() + end + replaceSpells(magicData.td_summon_spells) + replaceSpells(magicData.td_misc_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/player_magic.lua b/Data Files/scripts/TamrielData/player_magic.lua index f5ace98..2b695a7 100644 --- a/Data Files/scripts/TamrielData/player_magic.lua +++ b/Data Files/scripts/TamrielData/player_magic.lua @@ -1,33 +1,106 @@ -local types = require('openmw.types') -local self = require('openmw.self') -local version_check = require("scripts.TamrielData.utils.version_check") -local magic_passwall = require("scripts.TamrielData.player_magic_passwall") - --- Run a perpetual check for any active spells which need a TD override - -local checkFrequency = 0.5 -- No need to check for magic that often -local checkCounter = 0.0 - -local function checkForAnyActiveSpells(timeSinceLastCheck) - checkCounter = checkCounter + timeSinceLastCheck - if checkCounter < checkFrequency then - return - end - checkCounter = 0 - for _, spell in pairs(types.Actor.activeSpells(self)) do - if spell.id == "t_com_mys_uni_passwall" then - if version_check.isFeatureEnabled("miscSpells") then - if magic_passwall then - types.Actor.activeSpells(self):remove(spell.activeSpellId) - magic_passwall.onCastPasswall() - end - end - end - end -end - -return { - engineHandlers = { - onUpdate = checkForAnyActiveSpells - } -} \ No newline at end of file +local core = require('openmw.core') + +if not core.magic.effects.records['T_mysticism_Passwall'] then + return +end +local nearby = require('openmw.nearby') +local self = require('openmw.self') +local types = require('openmw.types') +local util = require('openmw.util') +local Actor = types.Actor + +local version_check = require('scripts.TamrielData.utils.version_check') +local magic_passwall = require('scripts.TamrielData.player_magic_passwall') +local magic_blink = require('scripts.TamrielData.actor_magic_blink') + +local blinkOn = false +local cachedMagnitude = { + spell = {}, + item = {} +} + +local function getBlinkMagnitude() + local spell = Actor.getSelectedSpell(self) + local effects + local cache + if spell then + cache = cachedMagnitude.spell + if cache.id == spell.id then + return cache.magnitude + else + cache.id = spell.id + cache.magnitude = nil + end + effects = spell.effects + else + local item = Actor.getSelectedEnchantedItem(self) + if not item then + return + end + cache = cachedMagnitude.item + if cache.id == item.recordId then + return cache.magnitude + else + cache.id = item.recordId + cache.magnitude = nil + end + local record = item.type.records[item.recordId] + if record.enchant then + local enchantment = core.magic.enchantments.records[record.enchant] + effects = enchantment and enchantment.effects + end + end + if not effects then + return + end + for _, effect in pairs(effects) do + if effect.id == 't_mysticism_blink' and effect.range == core.magic.RANGE.Self then + cache.magnitude = effect.magnitudeMin + return cache.magnitude + end + end +end + +local function showBlinkIndicator() + -- TODO: switch to RTT/UI + if Actor.getStance(self) == Actor.STANCE.Spell then + local magnitude = getBlinkMagnitude() + if magnitude then + local destination, _, ground = magic_blink.getBlinkDestination(magnitude) + local groundPos + if ground then + groundPos = util.vector3(destination.x, destination.y, ground + 6) + else + groundPos = util.vector3(destination.x, destination.y, destination.z - 7168) + local result = nearby.castRay(destination, groundPos, { ignore = self }) + if result.hitPos then + groundPos = result.hitPos + util.vector3(0, 0, 6) + end + end + local position = util.vector3(destination.x, destination.y, (ground or destination.z) + 24) + core.sendGlobalEvent('T_BlinkIndicator', { position = position, groundPos = groundPos, actor = self }) + blinkOn = true + return true + end + end + return false +end + +return { + eventHandlers = { + T_Passwall_Cast = magic_passwall.onCastPasswall + }, + engineHandlers = { + onUpdate = function() + if version_check.isFeatureEnabled('blinkIndicator') then + if showBlinkIndicator() then + return + end + end + if blinkOn then + blinkOn = false + core.sendGlobalEvent('T_BlinkIndicator', { actor = self }) + end + end + } +} diff --git a/Data Files/scripts/TamrielData/player_magic_passwall.lua b/Data Files/scripts/TamrielData/player_magic_passwall.lua index 8690c23..ddcdb33 100644 --- a/Data Files/scripts/TamrielData/player_magic_passwall.lua +++ b/Data Files/scripts/TamrielData/player_magic_passwall.lua @@ -1,7 +1,3 @@ -if not require("scripts.TamrielData.utils.version_check").isFeatureSupported("miscSpells") then - return -end - local self = require('openmw.self') local ambient = require('openmw.ambient') local async = require('openmw.async') @@ -15,11 +11,10 @@ local l10n = core.l10n("TamrielData") local debug = require("scripts.TamrielData.utils.debug_logging") local FT_TO_UNITS = 22.1 -local maxSpellDistance = 25 * FT_TO_UNITS -- 25ft is a default Passwall spell range in the MWSE version -local maxSpellDistanceSquared = maxSpellDistance * maxSpellDistance local veryCloseSquared = 11 * 11 -- an arbitrary value representing a close enough object that no wall is between local passwallSpellId = "t_com_mys_uni_passwall" -local passwallFailureSound = core.stats.Skill.records[core.magic.spells.records[passwallSpellId].effects[1].effect.school].school.failureSound +local passwallFailureSound = core.stats.Skill.records[core.magic.effects.records.T_mysticism_Passwall.school].school.failureSound +local activationDistance = core.getGMST("iMaxActivateDist") + 0.1 local function calculatePlayerHeight() local playerRecord = types.NPC.record(self) @@ -38,17 +33,11 @@ local function getActivationVector() return util.vector3(cameraVector.x, cameraVector.y, 0.0):normalize() end -local function getActivationDistance() - return core.getGMST("iMaxActivateDist") + 0.1 -end - local function getRaycastingInputData() local activationVector = getActivationVector() - local activateDistance = getActivationDistance() return { startPos = self.position + util.vector3(0, 0, calculatePlayerHeight() * 0.7), -- castPosition as in MWSE version - directionVector = activationVector, - activateDistance = activateDistance + directionVector = activationVector } end @@ -59,8 +48,7 @@ local function startTeleporting(newPosition, newCell, newRotation, targetObject) position = newPosition, cell = newCell, rotation = newRotation, - targetObject = targetObject, - vfxStatic = core.magic.spells.records[passwallSpellId].effects[1].effect.hitStatic + targetObject = targetObject }) end @@ -186,7 +174,7 @@ local function isBlockedByIllegalActivator(object) return false end -local function isThereAReachableItemFromPosition(startPosition) +local function isThereAReachableItemFromPosition(startPosition, maxSpellDistanceSquared) -- If no other check passed until now, then perhaps there is nothing of interest except items in that area. -- In that case a reachable item hopefully is close by, so no need for far checks. @@ -203,7 +191,7 @@ local function isThereAReachableItemFromPosition(startPosition) return false end -local function isCalculatedPositionIntendedForThePlayer(position) +local function isCalculatedPositionIntendedForThePlayer(position, range) if not position then return false end @@ -231,7 +219,7 @@ local function isCalculatedPositionIntendedForThePlayer(position) return true end end - return isThereAReachableItemFromPosition(position) + return isThereAReachableItemFromPosition(position, range * range) end local function isRayHitOnBlocker(rayHit) @@ -239,7 +227,7 @@ local function isRayHitOnBlocker(rayHit) return isBlockedByWard(object) or isBlockedByIllegalActivator(object) end -local function calculatePasswallPosition(intermediateRayHits, limitingPosition, directionVector) +local function calculatePasswallPosition(intermediateRayHits, limitingPosition, directionVector, range) local rayTestOffset = 19 -- We could say that a 2*19 square is enough to fit the player in local minDistanceSquared = 108 * 108 -- minDistance from the MWSE version but squared local maxZDifference = 105 -- upCoord from the MWSE version @@ -300,7 +288,7 @@ local function calculatePasswallPosition(intermediateRayHits, limitingPosition, local isIntendedForThePlayer = isPositionNotTooClose and isPositionNotTooHighOrLow and isPositionNotTooFar if isIntendedForThePlayer then - isIntendedForThePlayer = isCalculatedPositionIntendedForThePlayer(navMeshPosition) + isIntendedForThePlayer = isCalculatedPositionIntendedForThePlayer(navMeshPosition, range) end if isIntendedForThePlayer then return navMeshPosition @@ -319,10 +307,10 @@ local function calculatePasswallPosition(intermediateRayHits, limitingPosition, return nil end -local function gatherAllRayHitsAndLimitingPosition(raycastingInputData, firstRaycastHit) - local remainingTeleportDistance = maxSpellDistance +local function gatherAllRayHitsAndLimitingPosition(raycastingInputData, firstRaycastHit, range) + local remainingTeleportDistance = range local intermediateRayHits = {firstRaycastHit} - local limitingPosition = firstRaycastHit.hitPos + raycastingInputData.directionVector * maxSpellDistance + local limitingPosition = firstRaycastHit.hitPos + raycastingInputData.directionVector * range local previousRaycastSourceObjects = {} while remainingTeleportDistance > 0 do @@ -348,7 +336,8 @@ end local PSW = {} -function PSW.onCastPasswall() +function PSW.onCastPasswall(magnitude) + local range = math.max(magnitude, 0) * FT_TO_UNITS + activationDistance debug.log( string.format( "START: pos:%s, cell:%s, rotation:%s, race:%s, isMale:%s, navHalfExtents:%s, navShapeType:%s", @@ -375,7 +364,7 @@ function PSW.onCastPasswall() end local raycastingInputData = getRaycastingInputData() - local raycastingEnd = raycastingInputData.startPos + raycastingInputData.directionVector * raycastingInputData.activateDistance + local raycastingEnd = raycastingInputData.startPos + raycastingInputData.directionVector * activationDistance local firstRaycastHit = nearby.castRay( raycastingInputData.startPos, @@ -411,11 +400,11 @@ function PSW.onCastPasswall() return onPasswallFail() end - local intermediateRayHits, limitingPosition = gatherAllRayHitsAndLimitingPosition(raycastingInputData, firstRaycastHit) + local intermediateRayHits, limitingPosition = gatherAllRayHitsAndLimitingPosition(raycastingInputData, firstRaycastHit, range) -- intermediateRayHits include the first raycast hit (a spell target object, i.e. wall) as element [1] -- limitingPosition is the max distance the spell could reach: should be farther from the player than (or as far as) all intermediateRayHits - local finalTeleportPosition = calculatePasswallPosition(intermediateRayHits, limitingPosition, raycastingInputData.directionVector) + local finalTeleportPosition = calculatePasswallPosition(intermediateRayHits, limitingPosition, raycastingInputData.directionVector, range) if finalTeleportPosition then startTeleporting(finalTeleportPosition, self.cell.name, self.rotation, targetObject) diff --git a/Data Files/scripts/TamrielData/utils/feature_data.lua b/Data Files/scripts/TamrielData/utils/feature_data.lua index fb2ff48..351c913 100644 --- a/Data Files/scripts/TamrielData/utils/feature_data.lua +++ b/Data Files/scripts/TamrielData/utils/feature_data.lua @@ -13,11 +13,23 @@ features["restrictEquipment"] = { settingsKey = "Settings_TamrielData_page01Main_group01Main_restrictEquipment" } features["miscSpells"] = { - requiredLuaApi = 71, + requiredLuaApi = 129, settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic", settingsEnabledByDefault = true, settingsKey = "Settings_TamrielData_page01Main_group02Magic_miscSpells" } +features["summoningSpells"] = { + requiredLuaApi = 129, + settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic", + settingsEnabledByDefault = true, + settingsKey = "Settings_TamrielData_page01Main_group02Magic_summoningSpells" +} +features["blinkIndicator"] = { + requiredLuaApi = 129, + settingsPlayerSectionStorageId = "Settings_TamrielData_page01Main_group02Magic", + settingsEnabledByDefault = true, + settingsKey = "Settings_TamrielData_page01Main_group02Magic_miscBlinkIndicator" +} 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