Caching hand feasibility, disabling interactions if there are no hands
This commit is contained in:
@@ -42,6 +42,7 @@ function ItemsController.Player.RemoveClothingItem(playerObj, clothingItem)
|
||||
if clothingItem and instanceof(clothingItem, "InventoryItem") then
|
||||
playerObj:removeWornItem(clothingItem)
|
||||
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
playerObj:getInventory():Remove(clothingItem) -- Umbrella is wrong, can be an InventoryItem too
|
||||
TOC_DEBUG.print("found and deleted" .. tostring(clothingItem))
|
||||
|
||||
@@ -123,7 +124,7 @@ function ItemsController.Zombie.SpawnAmputationItem(zombie, amputationFullType)
|
||||
local itemVisual = ItemVisual:new()
|
||||
itemVisual:setItemType(amputationFullType)
|
||||
itemVisual:setTextureChoice(texId)
|
||||
zombieVisuals:add(itemVisual)
|
||||
if zombieVisuals then zombieVisuals:add(itemVisual) end
|
||||
zombie:resetModelNextFrame()
|
||||
|
||||
-- Spawn the item too in the inventory to keep track of stuff this way. It's gonna get deleted when we reload the game
|
||||
|
||||
@@ -56,7 +56,7 @@ local og_ISBaseTimedAction_perform = ISBaseTimedAction.perform
|
||||
--- After each action, level up perks
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISBaseTimedAction:perform()
|
||||
og_ISBaseTimedAction_perform(self)
|
||||
og_ISBaseTimedAction_perform(self)
|
||||
|
||||
TOC_DEBUG.print("Running ISBaseTimedAction.perform override")
|
||||
|
||||
@@ -70,7 +70,7 @@ function ISBaseTimedAction:perform()
|
||||
-- We're checking for only "visible" amputations to prevent from having bleeds everywhere
|
||||
if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then
|
||||
local side = CommonMethods.GetSide(limbName)
|
||||
LocalPlayerController.playerObj:getXp():AddXP(Perks["Side_" .. side], 1) -- TODO Make it dynamic
|
||||
LocalPlayerController.playerObj:getXp():AddXP(Perks["Side_" .. side], 1) -- TODO Make it dynamic
|
||||
if not dcInst:getIsCicatrized(limbName) and dcInst:getIsProstEquipped(limbName) then
|
||||
TOC_DEBUG.print("Trying for bleed, player met the criteria")
|
||||
LocalPlayerController.TryRandomBleed(self.character, limbName)
|
||||
@@ -96,10 +96,9 @@ local og_ISEquipWeaponAction_isValid = ISEquipWeaponAction.isValid
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISEquipWeaponAction:isValid()
|
||||
local isValid = og_ISEquipWeaponAction_isValid(self)
|
||||
local dcInst = DataController.GetInstance(self.character:getUsername())
|
||||
if isValid and dcInst:getIsAnyLimbCut() then
|
||||
local isPrimaryHandValid = CheckHandFeasibility(primaryHand)
|
||||
local isSecondaryHandValid = CheckHandFeasibility(secondaryHand)
|
||||
if isValid then
|
||||
local isPrimaryHandValid = CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.R)
|
||||
local isSecondaryHandValid = CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.L)
|
||||
-- Both hands are cut off, so it's impossible to equip in any way
|
||||
if not isPrimaryHandValid and not isSecondaryHandValid then
|
||||
isValid = false
|
||||
@@ -137,10 +136,10 @@ function ISEquipWeaponAction:performWithAmputation(dcInst)
|
||||
if not self.twoHands then
|
||||
if getMethodFirst(self.character) and getMethodFirst(self.character):isRequiresEquippedBothHands() then
|
||||
setMethodFirst(self.character, nil)
|
||||
-- if this weapon is already equiped in the 2nd hand, we remove it
|
||||
-- if this weapon is already equiped in the 2nd hand, we remove it
|
||||
elseif (getMethodFirst(self.character) == self.item or getMethodFirst(self.character) == getMethodSecond(self.character)) then
|
||||
setMethodFirst(self.character, nil)
|
||||
-- if we are equipping a handgun and there is a weapon in the secondary hand we remove it
|
||||
-- if we are equipping a handgun and there is a weapon in the secondary hand we remove it
|
||||
elseif instanceof(self.item, "HandWeapon") and self.item:getSwingAnim() and self.item:getSwingAnim() == "Handgun" then
|
||||
if getMethodFirst(self.character) and instanceof(getMethodFirst(self.character), "HandWeapon") then
|
||||
setMethodFirst(self.character, nil)
|
||||
@@ -156,7 +155,6 @@ function ISEquipWeaponAction:performWithAmputation(dcInst)
|
||||
setMethodFirst(self.character, self.item)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
setMethodFirst(self.character, nil)
|
||||
setMethodSecond(self.character, nil)
|
||||
@@ -186,7 +184,6 @@ end
|
||||
local og_ISEquipWeaponAction_perform = ISEquipWeaponAction.perform
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISEquipWeaponAction:perform()
|
||||
|
||||
og_ISEquipWeaponAction_perform(self)
|
||||
|
||||
-- TODO Can we do it earlier?
|
||||
@@ -199,18 +196,17 @@ end
|
||||
|
||||
function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon, items, player)
|
||||
-- check if hands if not heavy damaged
|
||||
if (not playerObj:isPrimaryHandItem(isWeapon) or (playerObj:isPrimaryHandItem(isWeapon) and playerObj:isSecondaryHandItem(isWeapon))) and not getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):isDeepWounded() and (getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getFractureTime() == 0 or getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getSplintFactor() > 0) then
|
||||
if (not playerObj:isPrimaryHandItem(isWeapon) or (playerObj:isPrimaryHandItem(isWeapon) and playerObj:isSecondaryHandItem(isWeapon))) and not getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):isDeepWounded() and (getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getFractureTime() == 0 or getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getSplintFactor() > 0) then
|
||||
-- forbid reequipping skinned items to avoid multiple problems for now
|
||||
local add = true
|
||||
if playerObj:getSecondaryHandItem() == isWeapon and isWeapon:getScriptItem():getReplaceWhenUnequip() then
|
||||
add = false
|
||||
end
|
||||
if add then
|
||||
local equipOption = context:addOption(getText("ContextMenu_Equip_Primary"), items, ISInventoryPaneContextMenu.OnPrimaryWeapon, player)
|
||||
local equipOption = context:addOption(getText("ContextMenu_Equip_Primary"), items,
|
||||
ISInventoryPaneContextMenu.OnPrimaryWeapon, player)
|
||||
equipOption.notAvailable = not CheckHandFeasibility(StaticData.LIMBS_IND_STR.Hand_R)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
if (not playerObj:isSecondaryHandItem(isWeapon) or (playerObj:isPrimaryHandItem(isWeapon) and playerObj:isSecondaryHandItem(isWeapon))) and not getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_L):isDeepWounded() and (getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_L):getFractureTime() == 0 or getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_L):getSplintFactor() > 0) then
|
||||
-- forbid reequipping skinned items to avoid multiple problems for now
|
||||
@@ -219,10 +215,65 @@ function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon,
|
||||
add = false
|
||||
end
|
||||
if add then
|
||||
local equipOption = context:addOption(getText("ContextMenu_Equip_Secondary"), items, ISInventoryPaneContextMenu.OnSecondWeapon, player)
|
||||
local equipOption = context:addOption(getText("ContextMenu_Equip_Secondary"), items,
|
||||
ISInventoryPaneContextMenu.OnSecondWeapon, player)
|
||||
|
||||
equipOption.notAvailable = not CheckHandFeasibility(StaticData.LIMBS_IND_STR.Hand_L)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local noHandsImpossibleActions = {
|
||||
getText("ContextMenu_Add_escape_rope_sheet"),
|
||||
getText("ContextMenu_Add_escape_rope"),
|
||||
getText("ContextMenu_Remove_escape_rope"),
|
||||
getText("ContextMenu_Barricade"),
|
||||
getText("ContextMenu_Unbarricade"),
|
||||
getText("ContextMenu_MetalBarricade"),
|
||||
getText("ContextMenu_MetalBarBarricade"),
|
||||
getText("ContextMenu_Open_window"),
|
||||
getText("ContextMenu_Close_window"),
|
||||
getText("ContextMenu_PickupBrokenGlass"),
|
||||
getText("ContextMenu_Open_door"),
|
||||
getText("ContextMenu_Close_door"),
|
||||
|
||||
}
|
||||
|
||||
|
||||
local og_ISWorldObjectContextMenu_createMenu = ISWorldObjectContextMenu.createMenu
|
||||
|
||||
---@param player integer
|
||||
---@param worldobjects any
|
||||
---@param x any
|
||||
---@param y any
|
||||
---@param test any
|
||||
function ISWorldObjectContextMenu.createMenu(player, worldobjects, x, y, test)
|
||||
---@type ISContextMenu
|
||||
local ogContext = og_ISWorldObjectContextMenu_createMenu(player, worldobjects, x, y, test)
|
||||
|
||||
-- check if no hands, disable various interactions
|
||||
if not CachedDataHandler.GetBothHandsFeasibility() then
|
||||
TOC_DEBUG.print("NO hands :((")
|
||||
for i = 1, #noHandsImpossibleActions do
|
||||
local optionName = noHandsImpossibleActions[i]
|
||||
local option = ogContext:getOptionFromName(optionName)
|
||||
if option then
|
||||
option.notAvailable = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return ogContext
|
||||
end
|
||||
|
||||
|
||||
local og_ISOpenCloseDoor_perform = ISOpenCloseDoor.perform
|
||||
function ISOpenCloseDoor:perform()
|
||||
|
||||
if CachedDataHandler.GetBothHandsFeasibility() then
|
||||
og_ISOpenCloseDoor_perform(self)
|
||||
else
|
||||
--getCore():getKey("Interact")
|
||||
|
||||
ISBaseTimedAction.perform(self)
|
||||
end
|
||||
end
|
||||
@@ -154,7 +154,8 @@ function AmputationHandler:execute(damagePlayer)
|
||||
CachedDataHandler.AddAmputatedLimb(username, dependedLimbName)
|
||||
end
|
||||
|
||||
CachedDataHandler.CalculateHighestAmputatedLimbs(username)
|
||||
-- Cache highest amputation and hand feasibility
|
||||
CachedDataHandler.CalculateCacheableValues(username)
|
||||
|
||||
-- If the part was actually infected, heal the player, if they were in time (infectionLevel < 20)
|
||||
if bd:getInfectionLevel() < 20 and bodyPart:IsInfected() and not dcInst:getIsIgnoredPartInfected() then
|
||||
|
||||
@@ -11,9 +11,23 @@ local CachedDataHandler = {}
|
||||
---@param username string
|
||||
function CachedDataHandler.Setup(username)
|
||||
CachedDataHandler.amputatedLimbs[username] = {}
|
||||
-- username -> side
|
||||
CachedDataHandler.highestAmputatedLimbs[username] = {}
|
||||
|
||||
|
||||
-- Local only, doesn't matter for Health Panel
|
||||
CachedDataHandler.handFeasibility = {}
|
||||
end
|
||||
|
||||
---Will calculate all the values that we need
|
||||
function CachedDataHandler.CalculateCacheableValues(username)
|
||||
CachedDataHandler.CalculateHighestAmputatedLimbs(username)
|
||||
CachedDataHandler.CalculateBothHandsFeasibility()
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--* Amputated Limbs caching *--
|
||||
CachedDataHandler.amputatedLimbs = {}
|
||||
|
||||
@@ -67,16 +81,6 @@ function CachedDataHandler.CalculateHighestAmputatedLimbs(username)
|
||||
return
|
||||
end
|
||||
|
||||
-- if CachedDataHandler.amputatedLimbs == nil or CachedDataHandler.amputatedLimbs[username] == nil then
|
||||
-- --- This function gets ran pretty early, we need to account for the Bob stuff
|
||||
-- -- if username == "Bob" then
|
||||
-- -- TOC_DEBUG.print("skip, Bob is default char")
|
||||
-- -- return
|
||||
-- -- end
|
||||
|
||||
-- TOC_DEBUG.print("Amputated limbs weren't calculated. Trying to calculate them now for " .. username)
|
||||
-- CachedDataHandler.CalculateAmputatedLimbs(username)
|
||||
-- end
|
||||
CachedDataHandler.CalculateAmputatedLimbs(username)
|
||||
|
||||
local amputatedLimbs = CachedDataHandler.amputatedLimbs[username]
|
||||
@@ -103,4 +107,38 @@ end
|
||||
|
||||
|
||||
|
||||
--* Hand feasibility caching *--
|
||||
CachedDataHandler.handFeasibility = {}
|
||||
|
||||
---@param limbName string
|
||||
function CachedDataHandler.CalculateHandFeasibility(limbName)
|
||||
local dcInst = DataController.GetInstance()
|
||||
local side = CommonMethods.GetSide(limbName)
|
||||
CachedDataHandler.handFeasibility[side] = not dcInst:getIsCut(limbName) or dcInst:getIsProstEquipped(limbName)
|
||||
end
|
||||
|
||||
|
||||
function CachedDataHandler.GetHandFeasibility(side)
|
||||
return CachedDataHandler.handFeasibility[side]
|
||||
end
|
||||
|
||||
|
||||
function CachedDataHandler.CalculateBothHandsFeasibility()
|
||||
CachedDataHandler.CalculateHandFeasibility("Hand_L")
|
||||
CachedDataHandler.CalculateHandFeasibility("Hand_R")
|
||||
|
||||
if not CachedDataHandler.GetBothHandsFeasibility() then
|
||||
TOC_DEBUG.print("Disabling interact key")
|
||||
getCore():addKeyBinding("Interact", Keyboard.KEY_NONE)
|
||||
else
|
||||
-- FIX DEFAULT ONE!!!!!!!
|
||||
TOC_DEBUG.print("Re-enabling interact key")
|
||||
getCore():addKeyBinding("Interact", Keyboard.KEY_E)
|
||||
end
|
||||
end
|
||||
|
||||
function CachedDataHandler.GetBothHandsFeasibility()
|
||||
return CachedDataHandler.handFeasibility["L"] or CachedDataHandler.handFeasibility["R"]
|
||||
end
|
||||
|
||||
return CachedDataHandler
|
||||
@@ -68,6 +68,9 @@ function ProsthesisHandler.SearchAndSetupProsthesis(item, isEquipping)
|
||||
local dcInst = DataController.GetInstance()
|
||||
dcInst:setIsProstEquipped(group, isEquipping)
|
||||
dcInst:apply()
|
||||
|
||||
-- Calculates hands feasibility once again
|
||||
CachedDataHandler.CalculateBothHandsFeasibility()
|
||||
end
|
||||
|
||||
-------------------------
|
||||
|
||||
@@ -42,7 +42,7 @@ end
|
||||
|
||||
function Main.SetupEvents()
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
Events.OnReceivedTocData.Add(CachedDataHandler.CalculateHighestAmputatedLimbs)
|
||||
Events.OnReceivedTocData.Add(CachedDataHandler.CalculateCacheableValues)
|
||||
end
|
||||
|
||||
function Main.InitializePlayer()
|
||||
|
||||
@@ -23,6 +23,7 @@ end
|
||||
local function GetZombieID(zombie)
|
||||
|
||||
-- Big love to Chuck and Sir Doggy Jvla for this code
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local pID = zombie:getPersistentOutfitID()
|
||||
local bits = string.split(string.reverse(Long.toUnsignedString(pID, 2)), "")
|
||||
while #bits < 16 do bits[#bits+1] = 0 end
|
||||
|
||||
7
media/lua/server/TOC/LimitActionsController.lua
Normal file
7
media/lua/server/TOC/LimitActionsController.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
function ISObjectClickHandler.doClickCurtain(object, playerNum, playerObj)
|
||||
TOC_DEBUG.print("Opening door")
|
||||
|
||||
if not object:canInteractWith(playerObj) then return false end
|
||||
object:ToggleDoor(playerObj)
|
||||
return true
|
||||
end
|
||||
@@ -46,7 +46,7 @@ function TestBodyLocations()
|
||||
|
||||
end
|
||||
|
||||
-- TODO MultiItem causes a ton of issues... fucking hell
|
||||
-- MultiItem causes a ton of issues... fucking hell
|
||||
|
||||
BodyLocationsAPI.MoveOrCreateBeforeOrAfter("TOC_Arm", "FullTop", true)
|
||||
group:setMultiItem("TOC_Arm", true)
|
||||
|
||||
Reference in New Issue
Block a user