initial commit
This commit is contained in:
parent
28c957ffbb
commit
1600a513a8
5 changed files with 340 additions and 0 deletions
86
.gitignore
vendored
Normal file
86
.gitignore
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
|
||||
# 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
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/lua,visualstudiocode,windows
|
15
MWSE/mods/celediel/DoorRandomizer/common.lua
Normal file
15
MWSE/mods/celediel/DoorRandomizer/common.lua
Normal file
|
@ -0,0 +1,15 @@
|
|||
local this = {}
|
||||
|
||||
this.modName = "Door Randomizer" -- or something
|
||||
this.author = "Celediel"
|
||||
this.version = "0.0.1"
|
||||
this.modInfo = "When a cell-change door is activated, its destination is randomized, based on various configuration options"
|
||||
this.configPath = string.gsub(this.modName, "%s+", "")
|
||||
this.cellTypes = {
|
||||
interior = 0,
|
||||
exterior = 1,
|
||||
both = 2,
|
||||
match = 3
|
||||
}
|
||||
|
||||
return this
|
21
MWSE/mods/celediel/DoorRandomizer/config.lua
Normal file
21
MWSE/mods/celediel/DoorRandomizer/config.lua
Normal file
|
@ -0,0 +1,21 @@
|
|||
local common = require("celediel.DoorRandomizer.common")
|
||||
|
||||
local defaultConfig = {
|
||||
randomizeChance = 50,
|
||||
interiorExterior = common.cellTypes.both,
|
||||
wildernessCells = true,
|
||||
needDoor = true,
|
||||
debug = false,
|
||||
ignoredCells = {},
|
||||
}
|
||||
|
||||
local currentConfig
|
||||
|
||||
local this = {}
|
||||
|
||||
function this.getConfig()
|
||||
currentConfig = currentConfig or mwse.loadConfig(common.configPath, defaultConfig)
|
||||
return currentConfig
|
||||
end
|
||||
|
||||
return this
|
144
MWSE/mods/celediel/DoorRandomizer/main.lua
Normal file
144
MWSE/mods/celediel/DoorRandomizer/main.lua
Normal file
|
@ -0,0 +1,144 @@
|
|||
-- pick a destination cell at random when activating a door
|
||||
local common = require("celediel.DoorRandomizer.common")
|
||||
local config = require("celediel.DoorRandomizer.config").getConfig()
|
||||
|
||||
local cells = {}
|
||||
|
||||
-- {{{ helper functions
|
||||
local function log(...) if config.debug then mwse.log("[%s] %s", common.modName, string.format(...)) end end
|
||||
|
||||
local function isZero(spot)
|
||||
return spot.position.x == 0 and
|
||||
spot.position.y == 0 and
|
||||
spot.position.z == 0 and
|
||||
spot.orientation.x == 0 and
|
||||
spot.orientation.y == 0 and
|
||||
spot.orientation.z == 0
|
||||
end
|
||||
|
||||
local function isTypeMatch(ogCell, chosenCell)
|
||||
return ((ogCell.isInterior and ogCell.behavesAsExterior) or not ogCell.isInterior) ==
|
||||
((chosenCell.isInterior and chosenCell.behavesAsExterior) or not chosenCell.isInterior)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ cell and position/orientation picking
|
||||
local function pickSpot(cell)
|
||||
-- this will be the position/orientation destination of every door that puts the player into the above chosen cell
|
||||
local spots = {}
|
||||
local spot
|
||||
|
||||
-- peek through doors in that cell to pick a position/orientation for the player
|
||||
for cellDoor in cell:iterateReferences(tes3.objectType.door) do
|
||||
if cellDoor.destination then -- only cell change doors
|
||||
-- loop through doors in THAT cell to find the door that led us there in the first place
|
||||
log("Looking through door %s in %s leading to %s", cellDoor.name or cellDoor.id, cell.id, cellDoor.destination.cell.id)
|
||||
for innerDoor in cellDoor.destination.cell:iterateReferences(tes3.objectType.door) do
|
||||
if innerDoor.destination and innerDoor.destination.cell.id == cell.id then
|
||||
-- found the door, now add where that door puts a player to our table
|
||||
log("Found a door in %s leading to %s with starting position:(%s) and orientation:(%s)",
|
||||
cellDoor.destination.cell.id, innerDoor.destination.cell.id,
|
||||
innerDoor.destination.marker.position, innerDoor.destination.marker.orientation)
|
||||
-- comment this out and set config.needDoor = true to cause infinite recursion
|
||||
table.insert(spots, {
|
||||
position = innerDoor.destination.marker.position,
|
||||
orientation = innerDoor.destination.marker.orientation
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #spots > 0 then
|
||||
log("There %s %s spot%s in %s", #spots > 1 and "were" or "was", #spots, #spots > 1 and "s" or "", cell.id)
|
||||
spot = table.choice(spots)
|
||||
else
|
||||
-- if we don't find any then use 0,0,0, which can be really bad in some cells
|
||||
spot = {position = tes3vector3.new(0, 0, 0), orientation = tes3vector3.new(0, 0, 0)}
|
||||
end
|
||||
|
||||
return spot
|
||||
end
|
||||
|
||||
local function pickCell(ogDest)
|
||||
local picked = table.choice(cells)
|
||||
local cell = tes3.getCell({id = picked})
|
||||
|
||||
if not config.wildernessCells and not cell.name then
|
||||
log("%s is wilderness, trying again...", cell.id)
|
||||
cell = pickCell(ogDest)
|
||||
end
|
||||
|
||||
if config.ignoredCells[cell.id] then
|
||||
log("%s is ignored cell, trying again...", cell.id)
|
||||
cell = pickCell(ogDest)
|
||||
end
|
||||
|
||||
if config.interiorExterior == common.cellTypes.exterior and cell.isInterior and not cell.behavesAsExterior then
|
||||
log("%s is interior, trying again...", cell.id)
|
||||
cell = pickCell(ogDest)
|
||||
elseif config.interiorExterior == common.cellTypes.interior and (not cell.isInterior or cell.behavesAsExterior) then
|
||||
log("%s is exterior, trying again...", cell.id)
|
||||
cell = pickCell(ogDest)
|
||||
elseif config.interiorExterior == common.cellTypes.match and not isTypeMatch(ogDest, cell) then
|
||||
log("%s and %s aren't same cell type, trying again...", ogDest.id, cell.id)
|
||||
cell = pickCell(ogDest)
|
||||
end
|
||||
|
||||
return cell
|
||||
end
|
||||
|
||||
local function pickCellAndSpot(ogDest)
|
||||
local cell = pickCell(ogDest)
|
||||
log("finally settled on %s, now picking position/orientation", cell.id)
|
||||
|
||||
local spot = pickSpot(cell)
|
||||
|
||||
if config.needDoor and isZero(spot) then
|
||||
log("No good spots in %s, starting over!", cell.id)
|
||||
cell, spot = pickCellAndSpot(ogDest)
|
||||
end
|
||||
|
||||
return cell, spot
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ event functions
|
||||
local function onActivate(e)
|
||||
-- only do stuff on cell change doors
|
||||
if e.activator ~= tes3.player and e.target.objectType ~= tes3.objectType.door then return end
|
||||
|
||||
local door = e.target
|
||||
|
||||
-- don't randomize locked doors, or: only randomize when a cell change event happens
|
||||
if door.destination and not tes3.getLocked({reference = door}) then
|
||||
local roll = math.random(0, 100)
|
||||
local rollStr = "Randomize Roll: %s "
|
||||
if config.randomizeChance < roll then
|
||||
log(rollStr .. "> %s, not randomizing", roll, config.randomizeChance)
|
||||
return
|
||||
end
|
||||
|
||||
log(rollStr .. "< %s, randomizing!", roll, config.randomizeChance)
|
||||
|
||||
log("Picking initial cell...")
|
||||
local cell, spot = pickCellAndSpot(door.destination.cell)
|
||||
|
||||
log("Picked %s at (%s) facing (%s)", cell.id, spot.position, spot.orientation)
|
||||
|
||||
-- set the door's destination to the picked cell and position/orientation
|
||||
tes3.setDestination({reference = door, cell = cell, position = spot.position, orientation = spot.orientation})
|
||||
end
|
||||
end
|
||||
|
||||
local function onInitialized(e)
|
||||
for cell, _ in pairs(tes3.dataHandler.nonDynamicData.cells) do table.insert(cells, cell) end
|
||||
|
||||
log("found %s cells", #cells)
|
||||
|
||||
event.register("activate", onActivate)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
event.register("initialized", onInitialized)
|
||||
event.register("modConfigReady", function() mwse.mcm.register(require("celediel.DoorRandomizer.mcm")) end)
|
74
MWSE/mods/celediel/DoorRandomizer/mcm.lua
Normal file
74
MWSE/mods/celediel/DoorRandomizer/mcm.lua
Normal file
|
@ -0,0 +1,74 @@
|
|||
local common = require("celediel.DoorRandomizer.common")
|
||||
local config = require("celediel.DoorRandomizer.config").getConfig()
|
||||
|
||||
local function createTableVar(id)
|
||||
return mwse.mcm.createTableVariable({id = id, table = config})
|
||||
end
|
||||
|
||||
local template = mwse.mcm.createTemplate({name = common.modName})
|
||||
template:saveOnClose(common.configPath, config)
|
||||
|
||||
local page = template:createSideBarPage({
|
||||
label = "Main Options",
|
||||
description = string.format("%s v%s by %s\n\n%s\n\n", common.modName, common.version, common.author, common.modInfo)
|
||||
})
|
||||
|
||||
local category = page:createCategory(common.modName)
|
||||
|
||||
category:createYesNoButton({
|
||||
label = "Pick wilderness cells?",
|
||||
variable = createTableVar("wildernessCells")
|
||||
})
|
||||
|
||||
category:createYesNoButton({
|
||||
label = "Pick only cells that place the player at doors?",
|
||||
variable = createTableVar("needDoor")
|
||||
})
|
||||
|
||||
category:createDropdown({
|
||||
label = "Pick interior or exterior cells only",
|
||||
options = {
|
||||
{label = "Both", value = common.cellTypes.both},
|
||||
{label = "Interior Only", value = common.cellTypes.interior},
|
||||
{label = "Exterior Only", value = common.cellTypes.exterior},
|
||||
{label = "Match Original Destination", value = common.cellTypes.match}
|
||||
},
|
||||
defaultSetting = common.cellTypes.both,
|
||||
variable = createTableVar("interiorExterior")
|
||||
})
|
||||
|
||||
category:createSlider({
|
||||
label = "Randomize Chance",
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
jump = 2,
|
||||
variable = createTableVar("randomizeChance")
|
||||
})
|
||||
|
||||
category:createYesNoButton({
|
||||
label = "Debug logging",
|
||||
variable = createTableVar("debug")
|
||||
})
|
||||
|
||||
template:createExclusionsPage({
|
||||
label = "Ignored cells",
|
||||
description = "These cells will not even be considered when randomizing.",
|
||||
showAllBlocked = false,
|
||||
variable = createTableVar("ignoredCells"),
|
||||
filters = {
|
||||
{
|
||||
label = "Cells",
|
||||
callback = function()
|
||||
local cells = {}
|
||||
for cell, _ in pairs(tes3.dataHandler.nonDynamicData.cells) do
|
||||
table.insert(cells, cell)
|
||||
end
|
||||
return cells
|
||||
end
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return template
|
||||
|
Loading…
Add table
Reference in a new issue