Caching hand feasibility, disabling interactions if there are no hands

This commit is contained in:
ZioPao
2024-03-21 19:37:30 +01:00
parent 0e911ec860
commit 1c990f3b9b
9 changed files with 133 additions and 31 deletions

View File

@@ -42,6 +42,7 @@ function ItemsController.Player.RemoveClothingItem(playerObj, clothingItem)
if clothingItem and instanceof(clothingItem, "InventoryItem") then if clothingItem and instanceof(clothingItem, "InventoryItem") then
playerObj:removeWornItem(clothingItem) playerObj:removeWornItem(clothingItem)
---@diagnostic disable-next-line: param-type-mismatch
playerObj:getInventory():Remove(clothingItem) -- Umbrella is wrong, can be an InventoryItem too playerObj:getInventory():Remove(clothingItem) -- Umbrella is wrong, can be an InventoryItem too
TOC_DEBUG.print("found and deleted" .. tostring(clothingItem)) TOC_DEBUG.print("found and deleted" .. tostring(clothingItem))
@@ -123,7 +124,7 @@ function ItemsController.Zombie.SpawnAmputationItem(zombie, amputationFullType)
local itemVisual = ItemVisual:new() local itemVisual = ItemVisual:new()
itemVisual:setItemType(amputationFullType) itemVisual:setItemType(amputationFullType)
itemVisual:setTextureChoice(texId) itemVisual:setTextureChoice(texId)
zombieVisuals:add(itemVisual) if zombieVisuals then zombieVisuals:add(itemVisual) end
zombie:resetModelNextFrame() 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 -- Spawn the item too in the inventory to keep track of stuff this way. It's gonna get deleted when we reload the game

View File

@@ -56,7 +56,7 @@ local og_ISBaseTimedAction_perform = ISBaseTimedAction.perform
--- After each action, level up perks --- After each action, level up perks
---@diagnostic disable-next-line: duplicate-set-field ---@diagnostic disable-next-line: duplicate-set-field
function ISBaseTimedAction:perform() function ISBaseTimedAction:perform()
og_ISBaseTimedAction_perform(self) og_ISBaseTimedAction_perform(self)
TOC_DEBUG.print("Running ISBaseTimedAction.perform override") 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 -- We're checking for only "visible" amputations to prevent from having bleeds everywhere
if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then
local side = CommonMethods.GetSide(limbName) 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 if not dcInst:getIsCicatrized(limbName) and dcInst:getIsProstEquipped(limbName) then
TOC_DEBUG.print("Trying for bleed, player met the criteria") TOC_DEBUG.print("Trying for bleed, player met the criteria")
LocalPlayerController.TryRandomBleed(self.character, limbName) LocalPlayerController.TryRandomBleed(self.character, limbName)
@@ -96,10 +96,9 @@ local og_ISEquipWeaponAction_isValid = ISEquipWeaponAction.isValid
---@diagnostic disable-next-line: duplicate-set-field ---@diagnostic disable-next-line: duplicate-set-field
function ISEquipWeaponAction:isValid() function ISEquipWeaponAction:isValid()
local isValid = og_ISEquipWeaponAction_isValid(self) local isValid = og_ISEquipWeaponAction_isValid(self)
local dcInst = DataController.GetInstance(self.character:getUsername()) if isValid then
if isValid and dcInst:getIsAnyLimbCut() then local isPrimaryHandValid = CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.R)
local isPrimaryHandValid = CheckHandFeasibility(primaryHand) local isSecondaryHandValid = CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.L)
local isSecondaryHandValid = CheckHandFeasibility(secondaryHand)
-- Both hands are cut off, so it's impossible to equip in any way -- Both hands are cut off, so it's impossible to equip in any way
if not isPrimaryHandValid and not isSecondaryHandValid then if not isPrimaryHandValid and not isSecondaryHandValid then
isValid = false isValid = false
@@ -137,10 +136,10 @@ function ISEquipWeaponAction:performWithAmputation(dcInst)
if not self.twoHands then if not self.twoHands then
if getMethodFirst(self.character) and getMethodFirst(self.character):isRequiresEquippedBothHands() then if getMethodFirst(self.character) and getMethodFirst(self.character):isRequiresEquippedBothHands() then
setMethodFirst(self.character, nil) 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 elseif (getMethodFirst(self.character) == self.item or getMethodFirst(self.character) == getMethodSecond(self.character)) then
setMethodFirst(self.character, nil) 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 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 if getMethodFirst(self.character) and instanceof(getMethodFirst(self.character), "HandWeapon") then
setMethodFirst(self.character, nil) setMethodFirst(self.character, nil)
@@ -156,7 +155,6 @@ function ISEquipWeaponAction:performWithAmputation(dcInst)
setMethodFirst(self.character, self.item) setMethodFirst(self.character, self.item)
end end
end end
else else
setMethodFirst(self.character, nil) setMethodFirst(self.character, nil)
setMethodSecond(self.character, nil) setMethodSecond(self.character, nil)
@@ -186,7 +184,6 @@ end
local og_ISEquipWeaponAction_perform = ISEquipWeaponAction.perform local og_ISEquipWeaponAction_perform = ISEquipWeaponAction.perform
---@diagnostic disable-next-line: duplicate-set-field ---@diagnostic disable-next-line: duplicate-set-field
function ISEquipWeaponAction:perform() function ISEquipWeaponAction:perform()
og_ISEquipWeaponAction_perform(self) og_ISEquipWeaponAction_perform(self)
-- TODO Can we do it earlier? -- TODO Can we do it earlier?
@@ -199,18 +196,17 @@ end
function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon, items, player) function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon, items, player)
-- check if hands if not heavy damaged -- 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 -- forbid reequipping skinned items to avoid multiple problems for now
local add = true local add = true
if playerObj:getSecondaryHandItem() == isWeapon and isWeapon:getScriptItem():getReplaceWhenUnequip() then if playerObj:getSecondaryHandItem() == isWeapon and isWeapon:getScriptItem():getReplaceWhenUnequip() then
add = false add = false
end end
if add then 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) equipOption.notAvailable = not CheckHandFeasibility(StaticData.LIMBS_IND_STR.Hand_R)
end end
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 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 -- forbid reequipping skinned items to avoid multiple problems for now
@@ -219,10 +215,65 @@ function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon,
add = false add = false
end end
if add then 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) equipOption.notAvailable = not CheckHandFeasibility(StaticData.LIMBS_IND_STR.Hand_L)
end end
end 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

View File

@@ -154,7 +154,8 @@ function AmputationHandler:execute(damagePlayer)
CachedDataHandler.AddAmputatedLimb(username, dependedLimbName) CachedDataHandler.AddAmputatedLimb(username, dependedLimbName)
end 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 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 if bd:getInfectionLevel() < 20 and bodyPart:IsInfected() and not dcInst:getIsIgnoredPartInfected() then

View File

@@ -11,9 +11,23 @@ local CachedDataHandler = {}
---@param username string ---@param username string
function CachedDataHandler.Setup(username) function CachedDataHandler.Setup(username)
CachedDataHandler.amputatedLimbs[username] = {} CachedDataHandler.amputatedLimbs[username] = {}
-- username -> side
CachedDataHandler.highestAmputatedLimbs[username] = {} CachedDataHandler.highestAmputatedLimbs[username] = {}
-- Local only, doesn't matter for Health Panel
CachedDataHandler.handFeasibility = {}
end end
---Will calculate all the values that we need
function CachedDataHandler.CalculateCacheableValues(username)
CachedDataHandler.CalculateHighestAmputatedLimbs(username)
CachedDataHandler.CalculateBothHandsFeasibility()
end
--* Amputated Limbs caching *-- --* Amputated Limbs caching *--
CachedDataHandler.amputatedLimbs = {} CachedDataHandler.amputatedLimbs = {}
@@ -67,16 +81,6 @@ function CachedDataHandler.CalculateHighestAmputatedLimbs(username)
return return
end 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) CachedDataHandler.CalculateAmputatedLimbs(username)
local amputatedLimbs = CachedDataHandler.amputatedLimbs[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 return CachedDataHandler

View File

@@ -68,6 +68,9 @@ function ProsthesisHandler.SearchAndSetupProsthesis(item, isEquipping)
local dcInst = DataController.GetInstance() local dcInst = DataController.GetInstance()
dcInst:setIsProstEquipped(group, isEquipping) dcInst:setIsProstEquipped(group, isEquipping)
dcInst:apply() dcInst:apply()
-- Calculates hands feasibility once again
CachedDataHandler.CalculateBothHandsFeasibility()
end end
------------------------- -------------------------

View File

@@ -42,7 +42,7 @@ end
function Main.SetupEvents() function Main.SetupEvents()
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler") local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
Events.OnReceivedTocData.Add(CachedDataHandler.CalculateHighestAmputatedLimbs) Events.OnReceivedTocData.Add(CachedDataHandler.CalculateCacheableValues)
end end
function Main.InitializePlayer() function Main.InitializePlayer()

View File

@@ -23,6 +23,7 @@ end
local function GetZombieID(zombie) local function GetZombieID(zombie)
-- Big love to Chuck and Sir Doggy Jvla for this code -- Big love to Chuck and Sir Doggy Jvla for this code
---@diagnostic disable-next-line: param-type-mismatch
local pID = zombie:getPersistentOutfitID() local pID = zombie:getPersistentOutfitID()
local bits = string.split(string.reverse(Long.toUnsignedString(pID, 2)), "") local bits = string.split(string.reverse(Long.toUnsignedString(pID, 2)), "")
while #bits < 16 do bits[#bits+1] = 0 end while #bits < 16 do bits[#bits+1] = 0 end

View 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

View File

@@ -46,7 +46,7 @@ function TestBodyLocations()
end end
-- TODO MultiItem causes a ton of issues... fucking hell -- MultiItem causes a ton of issues... fucking hell
BodyLocationsAPI.MoveOrCreateBeforeOrAfter("TOC_Arm", "FullTop", true) BodyLocationsAPI.MoveOrCreateBeforeOrAfter("TOC_Arm", "FullTop", true)
group:setMultiItem("TOC_Arm", true) group:setMultiItem("TOC_Arm", true)