Skip to content

Instantly share code, notes, and snippets.

@celediel
Last active March 9, 2022 01:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save celediel/ecba69a19fc5ac30048534565a666ca3 to your computer and use it in GitHub Desktop.
Save celediel/ecba69a19fc5ac30048534565a666ca3 to your computer and use it in GitHub Desktop.
Cannibals of Morrowind - MWSE ver
local common = {}
common.modName = "Cannibals"
common.modInfo = "Based on Updated Cannibals of Morrowind by Danae " ..
"which is in turn based on Cannibals of Morrowind by Morandir Nailo\n\n" ..
"Adds body part ingredients (brains, hearts, flesh, etc.) to " ..
"all NPC's in the game, on death, which restore fatigue and have further " ..
"properties which reflect the race (for instance, Dunmer Flesh can be eaten, " ..
"or used in a potion, to gain fire resistance).\n\n" ..
"In addition, each NPC has a skull, which can be kept as a trophy, or used as " ..
"a Mortar & Pestle. Most skulls are generic (dunmer skull, nord skull, etc.) " ..
"but certain important NPCs have unique skulls bearing their name, for those " ..
"important kills. More powerful NPC skulls will act as better quality Mortar & " ..
"Pestles. Beasts and vampires have new skull meshes, courtesy of Barabus."
common.codeAuthor = "Celediel"
common.version = "1.0.1"
common.esp = "Cannibals of Morrowind MWSE.esp"
return common
local common = require("celediel.Cannibals.common")
local config = {}
-- mimic the esp version
local currentConfig
local defaultConfig = {addSkulls = true, bodyPartChance = 50, debug = false}
config.getConfig = function()
currentConfig = currentConfig or mwse.loadConfig(common.modName, defaultConfig)
return currentConfig
end
return config
return {
-- always spawn
skulls = {
-- races
["khajiit"] = "mor_apparatus_khajiitskull",
["argonian"] = "mor_apparatus_argoskull",
["orc"] = "mor_apparatus_orcskull",
["breton"] = "mor_apparatus_bretonskull",
["imperial"] = "mor_apparatus_imperialskull",
["nord"] = "mor_apparatus_nordskull",
["redguard"] = "mor_apparatus_redguardskull",
["wood elf"] = "mor_apparatus_bosskull",
["high elf"] = "mor_apparatus_altskull",
["dark elf"] = "mor_apparatus_dunskull",
-- TR races
["t_els_ohmes"] = "mor_apparatus_khajiitskull",
["t_els_cathay"] = "mor_apparatus_khajiitskull",
["t_els_ohmes-raht"] = "mor_apparatus_khajiitskull",
["t_els_suthay"] = "mor_apparatus_khajiitskull",
["t_els_cathay-raht"] = "mor_apparatus_khajiitskull",
["t_sky_reachman"] = "mor_apparatus_nordskull", -- or maybe mor_apparatus_bretonskull ??
["t_pya_seaelf"] = "misc_skull00", -- generic skull until something better
["fallback"] = "misc_skull00", -- generic skull for mod added races
-- vampires
["vampire"] = "mor_apparatus_vampskull",
-- special NPCs
["vivec_god"] = "mor_apparatus_vivskull",
["fargoth"] = "mor_apparatus_fargothskull",
["divayth fyr"] = "mor_apparatus_divaythskull",
["vedam dren"] = "mor_apparatus_dukeskull",
["gothren"] = "mor_apparatus_gothren",
["orvas dren"] = "mor_apparatus_orvasskull",
["dhaunayne aundae"] = "mor_apparatus_aundaeskull",
["raxle berne"] = "mor_apparatus_berneskull",
["volrina quarra"] = "mor_apparatus_quarraskull",
["dandras vules"] = "mor_apparatus_dbskull",
["lalatia varian"] = "mor_apparatus_lalatiaskull",
["varus vatinius"] = "mor_apparatus_varusskull",
["trebonius artorius"] = "mor_apparatus_trebskull",
["eno hlaalu"] = "mor_apparatus_enoskull",
["tholer saryoni"] = "mor_apparatus_saryoniskull",
["stacey"] = "mor_apparatus_jimskull",
},
-- whatever% chance to pick one
randomParts = {
-- NPC races
argonian = {
"mor_arg_brain",
"mor_argo_eye",
"mor_argo_flesh",
"mor_argo_heart",
"mor_argo_tail",
"mor_intestine"
},
khajiit = {
"mor_khajiit_brain",
"mor_khajiit_ear",
"mor_khajiit_eye",
"mor_khajiit_flesh",
"mor_khajiit_heart",
"mor_intestine"
},
orc = {
"mor_orc_brain",
"mor_orc_eye",
"mor_orc_flesh",
"mor_orc_heart",
"mor_intestine"
},
breton = {
"mor_breton_brain",
"mor_breton_eye",
"mor_breton_flesh",
"mor_breton_heart",
"mor_intestine"
},
imperial = {
"mor_imperial_brain",
"mor_imperial_eye",
"mor_imperial_flesh",
"mor_imperial_heart",
"mor_imperial_tongue",
"mor_intestine"
},
nord = {
"mor_nord_bones",
"mor_nord_brain",
"mor_nord_flesh",
"mor_nord_heart",
"mor_intestine"
},
redguard = {
"mor_redguard_brain",
"mor_redguard_eye",
"mor_redguard_flesh",
"mor_redguard_heart",
"mor_intestine"
},
["wood elf"] = {
"mor_bosmer_brain",
"mor_bosmer_eye",
"mor_bosmer_flesh",
"mor_bosmer_heart",
"mor_intestine"
},
["high elf"] = {
"mor_altmer_brain",
"mor_altmer_eye",
"mor_altmer_heart",
"mor_altmer_flesh",
"mor_intestine"
},
["dark elf"] = {
"mor_dunmer_brain",
"mor_dunmer_eye",
"mor_dunmer_flesh",
"mor_dunmer_heart",
"mor_intestine"
},
-- Tamriel Data
-- todo: better these
["t_els_ohmes"] = {
"mor_khajiit_brain",
"mor_khajiit_ear",
"mor_khajiit_eye",
"mor_khajiit_flesh",
"mor_khajiit_heart",
"mor_intestine"
},
["t_els_cathay"] = {
"mor_khajiit_brain",
"mor_khajiit_ear",
"mor_khajiit_eye",
"mor_khajiit_flesh",
"mor_khajiit_heart",
"mor_intestine"
},
["t_els_ohmes-raht"] = {
"mor_khajiit_brain",
"mor_khajiit_ear",
"mor_khajiit_eye",
"mor_khajiit_flesh",
"mor_khajiit_heart",
"mor_intestine"
},
["t_els_suthay"] = {
"mor_khajiit_brain",
"mor_khajiit_ear",
"mor_khajiit_eye",
"mor_khajiit_flesh",
"mor_khajiit_heart",
"mor_intestine"
},
["t_els_cathay-raht"] = {
"mor_khajiit_brain",
"mor_khajiit_ear",
"mor_khajiit_eye",
"mor_khajiit_flesh",
"mor_khajiit_heart",
"mor_intestine"
},
-- Reachmen are descended from Nords and Bretons, so a mix of parts?
-- since it picks one at random, having all of both is okay
-- ! fix it if that changes lol
-- I'm no lore master, so this could probably be better
["t_sky_reachman"] = {
"mor_nord_bones",
"mor_nord_brain",
"mor_nord_flesh",
"mor_nord_heart",
"mor_breton_brain",
"mor_breton_eye",
"mor_breton_flesh",
"mor_breton_heart",
"mor_intestine"
},
-- Generic parts until something better comes along I guess
["t_pya_seaelf"] = {
"mor_intestine"
},
-- todo: bones
-- ["un_skeleton_race"] = {
-- some bones
-- },
-- todo: better mod added race support
fallback = {"mor_intestine"},
-- creatures and such
sleeper = {"aa_skull_sleeper"},
ashGhoul = {"aa_skull_ashghoul"},
ashVampire = {"aa_skull_ashvamp"}
}
}
local data = require("celediel.Cannibals.data")
local common = require("celediel.Cannibals.common")
local config = require("celediel.Cannibals.config").getConfig()
-- send nonsense to the logs
local function log(...) if config.debug then mwse.log("[%s] %s", common.modName, string.format(...)) end end
-- skull/body part picking functions
local function pickSkull(actor)
-- only NPCs get skulls
if actor.actorType ~= tes3.actorType.npc then return end
-- shortcuts
local race = actor.object.race.id:lower()
-- some references have ref.baseObject, some have ref.object.baseObject
-- I really don't know which is the "right one"
-- just try them all or something
local obj = actor.baseObject and actor.baseObject or
(actor.object.baseObject and actor.object.baseObject or actor.object)
local id = obj.id:lower()
local isVampire = obj.head and obj.head.vampiric
local skull
-- log("Picking skull for %s%s (id:%s race:%s)", obj.name, isVampire and ", a vampire" or "", id, race)
if isVampire then
skull = data.skulls["vampire"]
log("Picked %s because vampire", skull)
elseif data.skulls[id] then
skull = data.skulls[id]
log("Picked %s by id:%s", skull, id)
elseif data.skulls[race] then
skull = data.skulls[race]
log("Picked %s by race:%s", skull, race)
else
-- generic skull for mod added races
-- todo: better support for mod added races
skull = data.skulls.fallback
log("Picked generic %s", skull)
end
return skull
end
local function pickBodyPart(actor)
-- log("Picking parts for %s (id:%s race:%s mesh:%s)", actor.object.name, actor.object.id,
-- actor.object.race.id:lower(), actor.object.mesh:lower())
-- list of parts relevant to the actor
local parts = {}
if actor.actorType == tes3.actorType.npc then
local race = actor.object.race.id:lower()
log("Picking parts based on race:%s", race)
parts = data.randomParts[race] or data.randomParts.fallback
elseif actor.actorType == tes3.actorType.creature then
-- todo: probably put this in pickSkull because these are skulls
-- todo: but the original mod had them spawn at the same rate as body parts so I put it here
local mesh = actor.object.mesh:lower()
-- works with SpaceDevo's Divine Dagoths because those meshes follow similar naming convention
-- but other mesh replacing esps could causes issues
if mesh:match("ashghoul") then
parts = data.randomParts.ashGhoul
elseif mesh:match("sleeper") then
parts = data.randomParts.sleeper
elseif mesh:match("ashvampire") then
parts = data.randomParts.ashVampire
end
if #parts > 0 then log("Picked parts based on mesh:%s", mesh) end
end
-- pick one of the parts
return table.choice(parts)
end
local function addParts(ref, skull, bodyPart)
local parts = ""
if skull and config.addSkulls then
parts = parts .. skull
tes3.addItem({reference = ref, item = skull, count = 1, playSound = false})
end
-- all in the name of debug log formatting
if skull and config.addSkulls and bodyPart and config.bodyPartChance > 0 then parts = parts .. " " end
if bodyPart then
local roll = math.random(1, 100)
local addPart = config.bodyPartChance >= roll
-- log("Adding %sparts because %s %s %s", addPart and "" or "no ", config.bodyPartChance, addPart and ">" or "<", roll)
if addPart then
parts = parts .. bodyPart
tes3.addItem({reference = ref, item = bodyPart, count = 1, playSound = false})
end
end
if parts ~= "" then log("Added parts:%s to %s", parts, ref) end
end
-- event function(s)
local eventFunctions = {}
eventFunctions.onDeath = function(e) addParts(e.reference, pickSkull(e.mobile), pickBodyPart(e.mobile)) end
local function onInitialized()
-- check if our esp is active
if not tes3.isModActive(common.esp) then
local msg = string.format("%s must be activated for %s to work!", common.esp, common.modName)
mwse.log("[%s] %s", common.modName, msg)
tes3.messageBox(msg)
return
end
-- now that that's out of the way
for name, func in pairs(eventFunctions) do
log("Registering functions for event: %s", name)
event.register(name:gsub("^on(%u)", string.lower), func)
end
mwse.log("[%s] Initialized with config:%s", common.modName, json.encode(config))
end
event.register("initialized", onInitialized)
event.register("modConfigReady", function() mwse.mcm.register(require("celediel.Cannibals.mcm")) end)
local common = require("celediel.Cannibals.common")
local config = require("celediel.Cannibals.config").getConfig()
local template = mwse.mcm.createTemplate(common.modName)
template:saveOnClose(common.modName, config)
local page = template:createSideBarPage({
label = "Sidebar Page???",
description = string.format("%s v%s Lua code by %s\n\n%s", common.modName,
common.version, common.codeAuthor, common.modInfo)
})
local category = page:createCategory(common.modName)
category:createYesNoButton({
label = "Add skulls to NPCs?",
description = "On death, NPCs will have a skull added to their " ..
"inventory. The type of skull is dependent on the NPC's race. " ..
"Vampires and some unique NPCs have special skulls.",
variable = mwse.mcm.createTableVariable({id = "addSkulls", table = config})
})
category:createSlider({
label = "Chance to add other body parts to NPCs and skulls to ash creatures",
description = "Percent chance to add an additional random body part to NPCs, and skulls to Sleepers, Ash Ghouls and Ash Vampires.",
variable = mwse.mcm.createTableVariable({id = "bodyPartChance", table = config})
})
category:createYesNoButton({
label = "Debug logging",
description = "Enable this if you want a bunch of nonsense in your MWSE.log",
variable = mwse.mcm.createTableVariable({id = "debug", table = config})
})
return template
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment