commit b576864f31575000048fa5324b22f90ca0ede10b Author: Lilian Jónsdóttir Date: Mon Sep 7 17:21:09 2020 -0700 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1951cd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,92 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/lua,visualstudiocode,windows +# Edit at https://www.toptal.com/developers/gitignore?templates=lua,visualstudiocode,windows + +### Lua ### +# Compiled Lua sources +luac.out + +# luarocks build files +*.src.rock +*.zip +*.tar.gz + +# Object files +*.o +*.os +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo +*.def +*.exp + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + + +### VisualStudioCode ### +.vscode/* +# !.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +[Bb]uild + +# End of https://www.toptal.com/developers/gitignore/api/lua,visualstudiocode,windows + +*.7z +*.zip +meta.ini \ No newline at end of file diff --git a/MWSE/mods/celediel/NoMoreFriendlyFire/common.lua b/MWSE/mods/celediel/NoMoreFriendlyFire/common.lua new file mode 100644 index 0000000..e7b823e --- /dev/null +++ b/MWSE/mods/celediel/NoMoreFriendlyFire/common.lua @@ -0,0 +1,11 @@ +local this = {} + +-- mod info variables +this.modName = "No More Friendly Fire" +this.modConfig = this.modName:gsub("%s", "") +this.modInfo = "Stop friendly fire. Player companions can't damage the player, the player " .. + "can't damage companions, and companions can't damage each other. That's it." +this.author = "Celediel" +this.version = "1.2.1" + +return this diff --git a/MWSE/mods/celediel/NoMoreFriendlyFire/config.lua b/MWSE/mods/celediel/NoMoreFriendlyFire/config.lua new file mode 100644 index 0000000..313cdea --- /dev/null +++ b/MWSE/mods/celediel/NoMoreFriendlyFire/config.lua @@ -0,0 +1,12 @@ +local common = require("celediel.NoMoreFriendlyFire.common") + +local currentConfig +local defaultConfig = {enable = true, debug = false} +local this = {} + +this.getConfig = function() + currentConfig = currentConfig or mwse.loadConfig(common.modConfig, defaultConfig) + return currentConfig +end + +return this diff --git a/MWSE/mods/celediel/NoMoreFriendlyFire/main.lua b/MWSE/mods/celediel/NoMoreFriendlyFire/main.lua new file mode 100644 index 0000000..67a98ef --- /dev/null +++ b/MWSE/mods/celediel/NoMoreFriendlyFire/main.lua @@ -0,0 +1,108 @@ +local common = require("celediel.NoMoreFriendlyFire.common") +local config = require("celediel.NoMoreFriendlyFire.config").getConfig() + +local mag +pcall(function() + mag = require("celediel.MoreAttentiveGuards.interop") +end) + +-- todo: make this not hardcoded somehow +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 + +-- keep track of followers +local followers = {} + +local function buildFollowerList() + local friends = {} + + local msg = "" + local magGuard = mag and mag.getGuardFollower() or nil + + for friend in tes3.iterate(tes3.mobilePlayer.friendlyActors) do + if friend ~= magGuard then + friends[friend.object.id] = true + msg = msg .. friend.object.name .. " " + end + end + log("Friends: %s", msg) + return friends +end + +-- Event functions +local eventFunctions = {} + +eventFunctions.onDamage = function(e) + if not e.attackerReference then return end + + if followers[e.attackerReference.object.id] and followers[e.reference.object.id] then + if config.enable then + log("%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) + 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 + +eventFunctions.onCellChanged = function(e) followers = buildFollowerList() end + +-- hopefully, when telling a follower to follow or wait, rebuild followers list +eventFunctions.onInfoResponse = function(e) + -- the dialogue option clicked on + local dialogue = tostring(e.dialogue):lower() + -- what that dialogue option triggers; this will catch AIFollow commands + local command = e.command:lower() + + for _, item in pairs(followMatches) do + if command:match(item) or dialogue:match(item) then + log("Found %s in dialogue, rebuilding followers", item) + -- wait until game time restarts, and don't set multiple timers + if not postDialogueTimer or postDialogueTimer.state ~= timer.active then + postDialogueTimer = timer.start({ + type = timer.simulate, + duration = 0.5, + iteration = 1, + callback = function() + followers = buildFollowerList() + end + }) + end + end + end +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 +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) + -- wait for summon to be loaded + timer.start({ + type = timer.simulate, + duration = 1, + iterations = 1, + callback = function() followers = buildFollowerList() end + }) + end +end + +-- Register events +local function onInitialized() + for name, func in pairs(eventFunctions) do + event.register(name:gsub("on(%u)", string.lower), func) + log("%s event registered", name) + end + + mwse.log("[%s] Successfully initialized%s", common.modName, mag and " with More Attentive Guards interop" or "") +end + +event.register("modConfigReady", function() mwse.mcm.register(require("celediel.NoMoreFriendlyFire.mcm")) end) +event.register("initialized", onInitialized) diff --git a/MWSE/mods/celediel/NoMoreFriendlyFire/mcm.lua b/MWSE/mods/celediel/NoMoreFriendlyFire/mcm.lua new file mode 100644 index 0000000..b51aa21 --- /dev/null +++ b/MWSE/mods/celediel/NoMoreFriendlyFire/mcm.lua @@ -0,0 +1,24 @@ +local common = require("celediel.NoMoreFriendlyFire.common") +local config = require("celediel.NoMoreFriendlyFire.config").getConfig() + +local template = mwse.mcm.createTemplate(common.modName) +template:saveOnClose(common.modConfig, config) + +local page = template:createSideBarPage({ + label = "Main options", + description = string.format("%s v%s by %s\n\n%s", common.modName, common.version, common.author, common.modInfo) +}) + +local category = page:createCategory(common.modName) + +category:createYesNoButton({ + label = "Stop friendly fire", + variable = mwse.mcm.createTableVariable({id = "enable", table = config}) +}) + +category:createYesNoButton({ + label = "Debug logging", + variable = mwse.mcm.createTableVariable({id = "debug", table = config}) +}) + +return template