companions resist spells if stop damage is enabled

This commit is contained in:
Lilian Jónsdóttir 2020-10-25 16:30:42 -07:00
parent 15df5dacd7
commit 1fd47821ea
4 changed files with 62 additions and 20 deletions

View file

@ -8,4 +8,7 @@ this.modInfo = "Stop friendly fire. Player companions can't damage the player, t
this.author = "Celediel"
this.version = "1.4.0"
-- debug
this.logLevels = {no = 0, small = 1, big = 2}
return this

View file

@ -1,7 +1,7 @@
local common = require("celediel.NoMoreFriendlyFire.common")
local currentConfig
local defaultConfig = {stopDamage = true, stopCombat = true, debug = false, ignored = {}}
local defaultConfig = {stopDamage = true, stopCombat = true, debugLevel = common.logLevels.no, ignored = {}}
local this = {}
this.getConfig = function()

View file

@ -8,7 +8,9 @@ pcall(function() mag = require("celediel.MoreAttentiveGuards.interop") end)
local followMatches = {"follow", "together", "travel", "wait", "stay"}
local postDialogueTimer
local function log(...) if config.debug then mwse.log("[%s] %s", common.modName, string.format(...)) end end
local function log(level, ...)
if config.debugLevel >= level then mwse.log("[%s] %s", common.modName, string.format(...)) end
end
-- keep track of followers
local followers = {}
@ -22,8 +24,8 @@ local function notActuallyFriend(friend)
local ignoredId = config.ignored[obj.id:lower()]
local ignoredMod = config.ignored[obj.sourceMod:lower()]
log("Friend %s: Is MAG Guard:%s, Ignored id:%s, Ignored mod:%s", obj.name, friend == magGuard,
ignoredId or "false", ignoredMod or "false")
log(common.logLevels.small, "Friend %s: Is MAG Guard:%s, Ignored id:%s, Ignored mod:%s", obj.name,
friend == magGuard, ignoredId or "false", ignoredMod or "false")
return friend == magGuard or ignoredId or ignoredMod
end
@ -44,9 +46,22 @@ local function buildFollowerList()
msg = msg .. friend.object.name .. " "
end
end
if msg ~= "" then log("Friends: %s", msg) end
if msg ~= "" then log(common.logLevels.small, "Friends: %s", msg) end
return friends
end
local function isHarmfulSpell(source)
-- look for harmful effects in the source spell
for i = 1, 8 do
local effect = source.effects[i]
if effect.object then
-- todo: get name of spell effect instead of id
log(common.logLevels.big, "effect #%s id:%s: harmful:%s", i, effect.object.id, effect.object.isHarmful)
if effect.object.isHarmful then return true end -- found one!
end
end
return false -- found nothing
end
-- }}}
-- {{{ Event functions
@ -58,23 +73,41 @@ eventFunctions.onDamage = function(e)
if followerCheck(e.attackerReference, e.reference) then
if config.stopDamage then
log("%s hit %s for %s friendly damage, nullifying", e.attackerReference.object.name,
log(common.logLevels.small, "%s hit %s for %s friendly damage, nullifying", e.attackerReference.object.name,
e.reference.object.name, e.damage)
e.damage = 0
return false -- I don't know if this makes a difference or not
else
log("%s hit %s for %s friendly damage", e.attackerReference.object.name, e.reference.object.name, e.damage)
log(common.logLevels.small, "%s hit %s for %s friendly damage", e.attackerReference.object.name,
e.reference.object.name, e.damage)
end
else
log(common.logLevels.big, "%s hit %s for %s damage", e.attackerReference.object.name, e.reference.object.name,
e.damage)
end
end
eventFunctions.onSpellResist = function(e)
-- ignore non-targeted magicka or without caster
if not e.caster or not e.target then return end
-- shortcuts
local caster = e.caster
local target = e.target
local source = e.source
if followerCheck(caster, target) then
log(common.logLevels.small, "%s hit %s with friendly magicka %s", caster, target, source)
if config.stopDamage and isHarmfulSpell(e.source) then
e.resistedPercent = 100
log(common.logLevels.small, "%s spell resist vs harmful %s maxified", target, source)
end
-- uncomment this to see all damage done by everyone to everyone else
-- else
-- log("%s hit %s for %s damage", e.attackerReference.object.name, e.reference.object.name, e.damage)
end
end
-- prevent combat from even happening between friendly actors
eventFunctions.onCombatStart = function(e)
if config.stopCombat and followerCheck(e.actor, e.target) then
log("Friendly combat attempted, putting a stop to it!")
log(common.logLevels.small, "Friendly combat attempted, putting a stop to it!")
return false
end
end
@ -94,10 +127,10 @@ eventFunctions.onInfoResponse = function(e)
if command:match(item) or dialogue:match(item) then
-- wait until game time restarts, and don't set multiple timers
if not postDialogueTimer or postDialogueTimer.state ~= timer.active then
log("Found %s in dialogue, rebuilding followers", item)
log(common.logLevels.big, "Found %s in dialogue, rebuilding followers", item)
postDialogueTimer = timer.start({
type = timer.simulate,
duration = 0.5,
duration = 0.25,
iteration = 1,
callback = function() followers = buildFollowerList() end
})
@ -108,13 +141,14 @@ end
-- rebuild followers list when player casts conjuration, in case its a summon spell
-- false positives are okay because we're not doing anything destructive
-- doesn't work if Skill Based Magicka Progression is activated because e.expGainSchool becomes nil
eventFunctions.onSpellCasted = function(e)
if e.caster == tes3.player and e.expGainSchool == tes3.magicSchool.conjuration then
log("Player cast conjuration spell %s, rebuilding followers list...", e.source.id)
log(common.logLevels.big, "Player cast conjuration spell %s, rebuilding followers list...", e.source.id)
-- wait for summon to be loaded
timer.start({
type = timer.simulate,
duration = 1,
duration = 0.25,
iterations = 1,
callback = function() followers = buildFollowerList() end
})
@ -127,10 +161,10 @@ end
local function onInitialized()
for name, func in pairs(eventFunctions) do
event.register(name:gsub("on(%u)", string.lower), func)
log("%s event registered", name)
log(common.logLevels.small, "%s event registered", name)
end
mwse.log("[%s] Successfully initialized%s", common.modName, mag and " with More Attentive Guards interop" or "")
log(common.logLevels.no, "Successfully initialized%s", mag and " with More Attentive Guards interop" or "")
end
event.register("modConfigReady", function() mwse.mcm.register(require("celediel.NoMoreFriendlyFire.mcm")) end)

View file

@ -21,9 +21,14 @@ category:createYesNoButton({
variable = mwse.mcm.createTableVariable({id = "stopCombat", table = config})
})
category:createYesNoButton({
label = "Debug logging",
variable = mwse.mcm.createTableVariable({id = "debug", table = config})
category:createDropdown({
label = "Debug log level",
options = {
{label = "No", value = common.logLevels.no},
{label = "Small", value = common.logLevels.small},
{label = "Big", value = common.logLevels.big}
},
variable = mwse.mcm.createTableVariable({id = "debugLevel", table = config})
})
template:createExclusionsPage({