morrowind-more-attentive-gu.../MWSE/mods/celediel/MoreAttentiveGuards/combat.lua
Lilian Jónsdóttir dd80dc3d1c prelimary voice support
still need to fill voice.lua with more voices
2021-08-23 18:36:33 -07:00

123 lines
4.7 KiB
Lua

local common = require("celediel.MoreAttentiveGuards.common")
local config = require("celediel.MoreAttentiveGuards.config").getConfig()
local this = {}
-- {{{ helper functions
local function log(...) if config.debug then common.log(...) end end
local function isFriendlyActor(actor)
for friend in tes3.iterate(tes3.mobilePlayer.friendlyActors) do
if actor.object.id == friend.object.id or actor.object.baseObject.id == friend.object.baseObject.id then return true end
end
return false
end
local function doChecks(attacker, target)
if not config.combatEnable then return false end
-- if player initiates combat or combat is not against player, do nothing
if attacker == tes3.mobilePlayer or target ~= tes3.mobilePlayer then return false end
if attacker.isDead or target.isDead then
log("Someone's dead, not helping.")
return false
end
-- inCombat is true after player has taken combat actions or after combat
-- has gone on awhile, but hopefully the guards will already be attacking by
-- then. Should be fine in cities, but will prevent players from provoking
-- NPCs in the wilderness and leading them into town.
if tes3.mobilePlayer.inCombat and attacker.object.objectType == tes3.objectType.npc then
log("Player is in combat, not sure who started it, so not helping.")
return false
end
-- first try baseObject, else try object.baseObject, else settle on object
local obj = attacker.baseObject and attacker.baseObject or
(attacker.object.baseObject and attacker.object.baseObject or attacker.object)
if config.ignored[string.lower(obj.id)] or config.ignored[string.lower(obj.sourceMod)] then
log("Ignored NPC or creature detected, not helping.")
return false
end
if isFriendlyActor(attacker) then
log("Friendly actor, not helping.")
return false
end
if tes3.mobilePlayer.bounty and tes3.mobilePlayer.bounty > 0 then
log("Player is wanted, ignoring combat.")
return false
end
-- ? Guards don't know who started it if the player is being attacked with their weapon out ?
-- seems to fix weird issue when sneak attacking NPCs in town, guards would kill NPC,
-- then player would get murder bounty, so guards would come after player
if tes3.mobilePlayer.weaponReady and attacker.object.objectType == tes3.objectType.npc then
log("NPC Fight, not sure who started it, not helping.")
return false
end
if attacker.object.isGuard then
log("Guards don't fight guards!")
return false
end
-- everything was good
return true
end
local function alertGuards(aggressor, cell)
log("Checking for guards in cell %s to bring justice to %s", cell.name or cell.id, aggressor.object.name)
local playerPos = tes3.mobilePlayer.position
for npc in cell:iterateReferences(tes3.objectType.npc) do
local distance = playerPos:distance(npc.position)
if not npc.disabled and npc.object.isGuard and npc.mobile and distance <= config.combatDistance then
log("Alerting %s, %s units away, to the combat!", npc.object.name, distance)
if config.combatDialogue == common.dialogueMode.text then
local response = common.playGuardText(npc.object.name, table.choice(common.dialogues.text[config.language].join_combat),
aggressor)
log(response)
elseif config.combatDialogue == common.dialogueMode.voice then
local response = common.playGuardVoice(npc.mobile, "join_combat")
log("Playing sound file: %s", response)
end
npc.mobile:startCombat(aggressor)
end
end
end
-- }}}
-- {{{ returned event functions
this.onCombatStarted = function(e)
if not doChecks(e.actor, e.target) then return end
for _, cell in pairs(tes3.getActiveCells()) do alertGuards(e.actor, cell) end
end
-- this will stop guards from attacking ignored actors ever
this.onCombatStart = function(e)
-- first try baseObject, else try object.baseObject, else settle on object
local target = e.target.object.baseObject and e.target.object.baseObject or
(e.target.baseObject and e.target.baseObject or e.target.object)
local attacker = e.actor.object.baseObject and e.actor.object.baseObject or
(e.actor.baseObject and e.actor.baseObject or e.actor.object)
if (config.ignored[string.lower(target.id)] or config.ignored[string.lower(target.sourceMod)]) and attacker.isGuard then
log("Combat started against %s by a guard, %s... stopping...", e.target.object.name, e.actor.object.name)
return false
end
end
-- }}}
return this
-- vim:fdm=marker