Intial Commit
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
-- Per-compartment flags on the original world object. No Quartermaster data is changed.
|
||||
QMIA = QMIA or {}
|
||||
QMIA.MOD_ID = "QuartermasterItemArrange"
|
||||
QMIA.DATA_KEY = "QMIArrange"
|
||||
|
||||
function QMIA.isMarked(obj, ci)
|
||||
if not obj or ci == nil or not obj:hasModData() then return false end
|
||||
local flags = obj:getModData()[QMIA.DATA_KEY]
|
||||
return type(flags) == "table" and flags[tostring(ci)] == true
|
||||
end
|
||||
|
||||
function QMIA.containerTarget(container)
|
||||
if not container then return nil end
|
||||
local obj = container:getParent()
|
||||
if not obj or not obj.getContainerCount or not obj.getSquare then return nil end
|
||||
for ci = 0, obj:getContainerCount() - 1 do
|
||||
if obj:getContainerByIndex(ci) == container then return obj, ci end
|
||||
end
|
||||
end
|
||||
|
||||
-- Also called by the authoritative timed action, where Quartermaster's client helpers
|
||||
-- aren't loaded. Respect safehouse rules on both sides of a multiplayer connection.
|
||||
function QMIA.canAccess(square, player)
|
||||
if not square or not player then return false end
|
||||
if SafeHouse and SafeHouse.isSafehouseAllowLoot then
|
||||
return SafeHouse.isSafehouseAllowLoot(square, player) ~= false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function QMIA.writeMark(obj, ci, enabled)
|
||||
local md = obj:getModData()
|
||||
local flags = md[QMIA.DATA_KEY] or {}
|
||||
flags[tostring(ci)] = enabled and true or nil
|
||||
md[QMIA.DATA_KEY] = flags
|
||||
obj:transmitModData()
|
||||
end
|
||||
|
||||
-- Validate a client request against the current world. No client-supplied ModData
|
||||
-- snapshot is accepted, so changing one compartment cannot overwrite another.
|
||||
function QMIA.applyRequest(player, args)
|
||||
if type(args) ~= "table" or type(args.enabled) ~= "boolean" then return false end
|
||||
for _, key in ipairs({ "x", "y", "z", "oi", "ci" }) do
|
||||
local value = args[key]
|
||||
if type(value) ~= "number" or value ~= value or value == math.huge
|
||||
or value == -math.huge or value ~= math.floor(value) then return false end
|
||||
end
|
||||
if args.ci < 0 or args.oi < 0 or not player then return false end
|
||||
local square = getCell():getGridSquare(args.x, args.y, args.z)
|
||||
if not QMIA.canAccess(square, player) then return false end
|
||||
if math.abs(player:getX() - args.x) > 20 or math.abs(player:getY() - args.y) > 20
|
||||
or math.abs(player:getZ() - args.z) > 1 then return false end
|
||||
local objects = square:getObjects()
|
||||
if args.oi >= objects:size() then return false end
|
||||
local obj = objects:get(args.oi)
|
||||
if not obj or not obj.getContainerCount or args.ci >= obj:getContainerCount()
|
||||
or not obj:getContainerByIndex(args.ci) then return false end
|
||||
QMIA.writeMark(obj, args.ci, args.enabled)
|
||||
return true
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
require "QMIA_State"
|
||||
require "IAArrange"
|
||||
require "TimedActions/IAArrangeAction"
|
||||
|
||||
-- Use Item Arrange's actual drop/arrange implementation and duration. Keeping this
|
||||
-- class in shared makes its complete() available to Build 42 multiplayer servers.
|
||||
QMIArrangeAction = IAArrangeAction:derive("QMIArrangeAction")
|
||||
|
||||
function QMIArrangeAction:new(character, item, srcContainer, destContainer)
|
||||
local obj = QMIA.containerTarget(destContainer)
|
||||
local o = IAArrangeAction.new(self, character, item, srcContainer, obj and obj:getSquare())
|
||||
o.destContainer = destContainer
|
||||
o.stopOnWalk = true
|
||||
o.stopOnRun = true
|
||||
o.stopOnAim = true
|
||||
return o
|
||||
end
|
||||
|
||||
-- A full surface / missing load must not cancel the remaining Quartermaster haul.
|
||||
-- Revalidate at start and complete instead; skipped items stay in their carrier.
|
||||
function QMIArrangeAction:isValid() return true end
|
||||
|
||||
function QMIArrangeAction:canArrange()
|
||||
local item, src, square, player = self.item, self.srcContainer, self.dropSquare, self.character
|
||||
if not item or not src or not square or not player then return false end
|
||||
local obj, ci = QMIA.containerTarget(self.destContainer)
|
||||
if not obj or obj:getObjectIndex() < 0 or obj:getSquare() ~= square
|
||||
or not QMIA.isMarked(obj, ci) then return false end
|
||||
-- Only unload carried items. A skipped Quartermaster load is never teleported.
|
||||
if not src:isInCharacterInventory(player) or not src:contains(item)
|
||||
or item:getContainer() ~= src or not src:isRemoveItemAllowed(item) then return false end
|
||||
if item:isEquipped() or item:isFavorite() or item:getIsCraftingConsumed() then return false end
|
||||
if not QMIA.canAccess(square, player) then return false end
|
||||
local here = player:getSquare()
|
||||
if not here or here:getZ() ~= square:getZ()
|
||||
or math.abs(here:getX() - square:getX()) > 1
|
||||
or math.abs(here:getY() - square:getY()) > 1
|
||||
or here:isSomethingTo(square) then return false end
|
||||
return IA.CheckSpace(square, item) == true
|
||||
end
|
||||
|
||||
function QMIArrangeAction:waitToStart()
|
||||
if not self:canArrange() then return false end
|
||||
self.character:faceLocation(self.dropSquare:getX(), self.dropSquare:getY())
|
||||
local waitingForTransaction = IAArrangeAction.waitToStart(self)
|
||||
return self.character:shouldBeTurning() or waitingForTransaction
|
||||
end
|
||||
|
||||
function QMIArrangeAction:start()
|
||||
self.qmiaSkip = not self:canArrange()
|
||||
if self.qmiaSkip then
|
||||
self.action:setTime(0)
|
||||
return
|
||||
end
|
||||
self.character:faceLocation(self.dropSquare:getX(), self.dropSquare:getY())
|
||||
IAArrangeAction.start(self)
|
||||
end
|
||||
|
||||
function QMIArrangeAction:update()
|
||||
if self.qmiaSkip then return end
|
||||
self.character:faceLocation(self.dropSquare:getX(), self.dropSquare:getY())
|
||||
IAArrangeAction.update(self)
|
||||
end
|
||||
|
||||
function QMIArrangeAction:complete()
|
||||
-- The server rechecks ownership, distance and available space immediately
|
||||
-- before using Item Arrange's own removal/drop/arrange implementation.
|
||||
if self.qmiaSkip or not self:canArrange() then return true end
|
||||
return IAArrangeAction.complete(self)
|
||||
end
|
||||
Reference in New Issue
Block a user