require "ISUI/ISPanelJoypad" ISHealthPanel = ISPanelJoypad:derive("ISHealthPanel"); ISHealthPanel.cheat = false or getDebug(); local PAD_BOTTOM = 8 local FONT_HGT_SMALL = getTextManager():getFontHeight(UIFont.Small) ----- ISNewHealthPanel = ISUIElement:derive("ISNewHealthPanel") function ISNewHealthPanel:instantiate() self.javaObject = NewHealthPanel.new(self.x, self.y, self.character) self.javaObject:setTable(self) self.javaObject:setX(self.x) self.javaObject:setY(self.y) self.javaObject:setMovable(false); -- self.javaObject:setWidth(self.width) -- self.javaObject:setHeight(self.height) self.javaObject:setAnchorLeft(self.anchorLeft) self.javaObject:setAnchorRight(self.anchorRight) self.javaObject:setAnchorTop(self.anchorTop) self.javaObject:setAnchorBottom(self.anchorBottom) end function ISNewHealthPanel:onClick(button) if button.internal == "FITNESS" then if JoypadState.players[self.playerNum+1] then getPlayerInfoPanel(self.playerNum):toggleView(xpSystemText.health) end if ISFitnessUI.instance and ISFitnessUI.instance[self.character:getPlayerNum()+1] then ISFitnessUI.instance[self.character:getPlayerNum()+1]:removeFromUIManager(); ISFitnessUI.instance[self.character:getPlayerNum()+1] = nil; end if ISFitnessUI.instance and ISFitnessUI.instance[self.character:getPlayerNum()+1] and ISFitnessUI.instance[self.character:getPlayerNum()+1]:isVisible() then return; end local modal = ISFitnessUI:new(0,0, 600, 350, self.character); modal:initialise() modal:addToUIManager() if JoypadState.players[self.character:getPlayerNum()+1] then setJoypadFocus(self.character:getPlayerNum(), modal) end end end function ISNewHealthPanel:new(x, y, character) local o = ISUIElement:new(x, y, 123, 123) setmetatable(o, self) self.__index = self o.character = character return o end ----- ISHealthBodyPartPanel = ISBodyPartPanel:derive("ISHealthBodyPartPanel") function ISHealthBodyPartPanel:onMouseUp(x, y) if self.selectedBp then local dragging = ISInventoryPane.getActualItems(ISMouseDrag.dragging) self.parent:dropItemsOnBodyPart(self.selectedBp.bodyPart, dragging) end end function ISHealthBodyPartPanel:prerender() self.nodeAlpha = 0.0 self.selectedAlpha = 0.1 if self.selectedBp then for index,item in ipairs(self.parent.listbox.items) do if item.item.bodyPart == self.selectedBp.bodyPart then self.nodeAlpha = 1.0 self.selectedAlpha = 0.5 break end end end ISBodyPartPanel.prerender(self) end function ISHealthBodyPartPanel:cbSetSelected(bp) if bp == nil then self.parent.listbox.selected = 0 return end for index,item in ipairs(self.parent.listbox.items) do if item.item.bodyPart == bp.bodyPart then self.parent.listbox.selected = index break end end end function ISHealthBodyPartPanel:new(character, x, y) local o = ISBodyPartPanel.new(self, character, x, y, nil, self.cbSetSelected) o.functionTarget = o return o end ----- ISHealthBodyPartListBox = ISScrollingListBox:derive("ISHealthBodyPartListBox") function ISHealthBodyPartListBox:onMouseUp(x, y) ISScrollingListBox.onMouseUp(self, x, y) local row = self:rowAt(x, y) local listItem = self.items[row] if not listItem then return end if ISMouseDrag.dragging and (#ISMouseDrag.dragging > 0) then local dragging = ISInventoryPane.getActualItems(ISMouseDrag.dragging) self.parent:dropItemsOnBodyPart(listItem.item.bodyPart, dragging) end end function ISHealthBodyPartListBox:new(x, y, width, height) local o = ISScrollingListBox.new(self, x, y, width, height) return o end ----- --************************************************************************-- --** ISPanel:initialise --** --************************************************************************-- function ISHealthPanel:initialise() ISPanelJoypad.initialise(self); end function ISHealthPanel:createChildren() self.healthPanel = ISNewHealthPanel:new(0, 8, self.character) self.healthPanel:initialise() self.healthPanel:instantiate() self.healthPanel:setVisible(true) self:addChild(self.healthPanel) self.listbox = ISHealthBodyPartListBox:new(180 - 15, 59, self.width - (180 - 15), self.height); self.listbox:initialise(); self.listbox:instantiate(); self.listbox:setAnchorLeft(true); self.listbox:setAnchorRight(true); self.listbox:setAnchorTop(true); self.listbox:setAnchorBottom(false); self.listbox.itemheight = 128; self.listbox.drawBorder = false self.listbox.backgroundColor.a = 0 self.listbox.drawText = ISHealthPanel.drawText; self:addChild(self.listbox) self.bodyPartPanel = ISHealthBodyPartPanel:new(self.character, 0, 8); self.bodyPartPanel:initialise(); self.bodyPartPanel:setAlphas(0.0, 1.0, 0.5, 0.0, 0.0) -- self.bodyPartPanel:setEnableSelectLines( true, self.bpAnchorX, self.bpAnchorY ); self.bodyPartPanel:enableNodes( "media/ui/BodyParts/bps_node_diamond", "media/ui/BodyParts/bps_node_diamond_outline" ); -- self.bodyPartPanel:overrideNodeTexture( BodyPartType.Torso_Upper, "media/ui/BodyParts/bps_node_big", "media/ui/BodyParts/bps_node_big_outline" ); -- self.bodyPartPanel:setColorScheme(self.colorScheme); self:addChild(self.bodyPartPanel); self.fitness = ISButton:new(self.healthPanel.x + 165, self.healthPanel.y, 100, 20, getText("ContextMenu_Fitness"), self, ISNewHealthPanel.onClick); self.fitness.internal = "FITNESS"; self.fitness.anchorTop = false self.fitness.anchorBottom = true self.fitness:initialise(); self.fitness:instantiate(); -- self.fitness.borderColor = self.buttonBorderColor; self:addChild(self.fitness); if getCore():getGameMode() == "Tutorial" then self.fitness:setVisible(false); end self.blockingAlpha = 0.0; -- print "instant"; end function ISHealthPanel:setVisible(visible) -- self.parent:setVisible(visible); -- self.doctorLevel = self.character:getPerkLevel(Perks.Doctor); self.otherPlayer = nil; self.javaObject:setVisible(visible); -- ISHealthPanel.cheat = self.character:getAccessLevel() ~= "None"; end function ISHealthBodyPartListBox:onRightMouseUp(x, y) if UIManager.getSpeedControls():getCurrentGameSpeed() == 0 then if not getDebug() then return end end local row = self:rowAt(x, y) if row < 1 or row > #self.items then return end self.selected = row local healthPanel = self.parent healthPanel:doBodyPartContextMenu(self.items[row].item.bodyPart, self:getX() + x, self:getY() + y) end function ISHealthPanel:toPlayerInventory(playerObj, item, bodyPart) if item:getContainer() ~= playerObj:getInventory() then local action = ISInventoryTransferAction:new(playerObj, item, item:getContainer(), playerObj:getInventory()) ISTimedActionQueue.add(action) -- FIXME: ISHealthPanel.actions never gets cleared self.actions = self.actions or {} self.actions[action] = bodyPart end end ISHealthPanel.onCheatCurrentPlayer = function(bodyPart, action, player) if action == "bleeding" then bodyPart:setBleedingTime((bodyPart:getBleedingTime() > 0) and 0 or 10) end if action == "hole" then player:addHole(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(bodyPart:getType()))); end if action == "patch" then player:addBasicPatch(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(bodyPart:getType()))); end if action == "blood" then player:addBlood(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(bodyPart:getType())), false, true, false); end if action == "removeblood" then player:getVisual():setBlood(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(bodyPart:getType())), 0); player:resetModelNextFrame(); end if action == "dirt" then player:addDirt(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(bodyPart:getType())), nil, false); end if action == "removedirt" then player:getVisual():setDirt(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(bodyPart:getType())), 0); player:resetModelNextFrame(); end if action == "bite" then if bodyPart:bitten() then bodyPart:SetBitten(false); bodyPart:SetInfected(false); bodyPart:SetFakeInfected(false); else bodyPart:SetBitten(true); end end if action == "holeback" then player:addHole(BloodBodyPartType.Back); end if action == "bullet" then if bodyPart:haveBullet() then local deepWound = bodyPart:isDeepWounded() local deepWoundTime = bodyPart:getDeepWoundTime() local bleedTime = bodyPart:getBleedingTime() bodyPart:setHaveBullet(false, 0) bodyPart:setDeepWoundTime(deepWoundTime) bodyPart:setDeepWounded(deepWound) bodyPart:setBleedingTime(bleedTime) else bodyPart:setHaveBullet(true, 0) end end if action == "burned" then if bodyPart:getBurnTime() > 0 then bodyPart:setBurnTime(0) else bodyPart:setBurnTime(50) end end if action == "burnWash" then if bodyPart:getBurnTime() > 0 then bodyPart:setNeedBurnWash(not bodyPart:isNeedBurnWash()) end end if action == "deepWound" then if bodyPart:getDeepWoundTime() > 0 then bodyPart:setDeepWoundTime(0) bodyPart:setDeepWounded(false) bodyPart:setBleedingTime(0) else bodyPart:generateDeepWound(); end end if action == "fracture" then if bodyPart:getFractureTime() > 0 then bodyPart:setFractureTime(0) else bodyPart:setFractureTime(21) end end if action == "healthFull" then bodyPart:RestoreToFullHealth(); if bodyPart:getStiffness() > 0 then bodyPart:setStiffness(0) player:getFitness():removeStiffnessValue(BodyPartType.ToString(bodyPart:getType())) end end if action == "healthFullBody" then local bodyParts = player:getBodyDamage():getBodyParts() for i=1, bodyParts:size() do local bP = bodyParts:get(i-1) bP:RestoreToFullHealth(); if bP:getStiffness() > 0 then bP:setStiffness(0) player:getFitness():removeStiffnessValue(BodyPartType.ToString(bP:getType())) end end end if action == "glass" then bodyPart:generateDeepShardWound(); end if action == "infected" then if bodyPart:isInfectedWound() then bodyPart:setWoundInfectionLevel(-1) else bodyPart:setWoundInfectionLevel(10) end end if action == "scratched" then if bodyPart:getScratchTime() > 0 then bodyPart:setScratched(false, true) bodyPart:setScratchTime(0) else bodyPart:setScratched(true, false); end end if action == "cut" then if bodyPart:isCut() then bodyPart:setCut(false) bodyPart:setCutTime(0) else bodyPart:setCut(true) end end if action == "fatique" then if bodyPart:getStiffness() > 0 then bodyPart:setStiffness(0) player:getFitness():removeStiffnessValue(BodyPartType.ToString(bodyPart:getType())) else bodyPart:setStiffness(100) end end end ISHealthPanel.onCheatOtherPlayer = function(bodyPart, action, player, otherPlayer) local args = { bodyPartIndex = BodyPartType.ToIndex(bodyPart:getType()), action = action, id = player:getOnlineID() } sendClientCommand(otherPlayer, "player", "onHealthCheat", args) end ISHealthPanel.onCheat = function(bodyPart, action, player, otherPlayer) if otherPlayer == nil then ISHealthPanel.onCheatCurrentPlayer(bodyPart, action, player) else ISHealthPanel.onCheatOtherPlayer(bodyPart, action, player, otherPlayer) end end ISHealthPanel.onCheatItem = function(itemType, playerObj) playerObj:getInventory():AddItem(itemType) end function ISHealthPanel:update() ISPanelJoypad.update(self) if self.otherPlayer then -- ISCollapsableWindow:close() just hides the window if not self.parent:getIsVisible() then self.parent:removeFromUIManager() if self.joyfocus then self.joyfocus.focus = nil end self:getDoctor():stopReceivingBodyDamageUpdates(self:getPatient()) return end if self:getDoctor():getAccessLevel() == "None" and (math.abs(self.otherPlayer:getX() - self.otherPlayerX) > 0.5 or math.abs(self.otherPlayer:getY() - self.otherPlayerY) > 0.5 or math.abs(self.character:getX() - self.characterX) > 0.5 or math.abs(self.character:getY() - self.characterY) > 0.5) then self.parent:removeFromUIManager() if self.joyfocus then self.joyfocus.focus = nil end self:getDoctor():stopReceivingBodyDamageUpdates(self:getPatient()) return end if (math.abs(self.otherPlayer:getX() - self.character:getX()) > 2 or math.abs(self.otherPlayer:getY() - self.character:getY()) > 2) and not ISHealthPanel.cheat then if not self.blockingMessage then self:getDoctor():stopReceivingBodyDamageUpdates(self:getPatient()) self:getPatient():getBodyDamageRemote():RestoreToFullHealth() self.listbox:clear() self.damagedParts = {} self.textRight = 0 self.listbox.textRight = 0 end self.blockingMessage = getText("IGUI_TradingUI_TooFarAway", self.character:getDisplayName()) self.blockingAlpha = math.min(1.0, self.blockingAlpha + 0.05) return; else if self.blockingMessage then self:getDoctor():startReceivingBodyDamageUpdates(self:getPatient()) end self.blockingMessage = nil; self.blockingAlpha = math.max(0.0, self.blockingAlpha - 0.05) end end if self:getIsVisible() then self:updateBodyPartList() if self.textRight and self.listbox.textRight then local width = math.max(self.textRight, self.listbox.x + self.listbox.textRight) if width > 0 then width = math.max(width, self.healthPanel:getRight()) self:setWidthAndParentWidth(width + 20); end end self:setHeightAndParentHeight(math.max(self.healthPanel:getBottom(), self.allTextHeight or 0) + FONT_HGT_SMALL + PAD_BOTTOM * 2); -- self.healthPanel:setX(self:getAbsoluteX()); -- self.healthPanel:setY(self:getAbsoluteY() + 8); else self.textRight = 0 self.listbox.textRight = 0 end end function ISHealthPanel:prerender() if self:isMouseOver() and ISMouseDrag.dragging and (#ISMouseDrag.dragging > 0) then self.bodyPartPanel:setVisible(true) else self.bodyPartPanel:setVisible(false) self.bodyPartPanel:deselect() end ISPanelJoypad.prerender(self) end function ISHealthPanel:render() if self.otherPlayer then self.fitness:setVisible(false); end -- self.healthPanel:render(); local fontHgt = getTextManager():getFontHeight(UIFont.Small); local y = self.healthPanel.y; self.fitness:setY(y); y = y + 30; self:drawText(getText("IGUI_health_Overall_Body_Status"), self.healthPanel.x + 165, y, 1.0, 1.0, 1.0, 1.0, UIFont.Small) y = y + fontHgt local InjuryRedTextTint = (100 - self:getPatient():getBodyDamage():getHealth()) / 100 InjuryRedTextTint = math.max(InjuryRedTextTint, 0.2) local str = self.healthPanel.javaObject:getDamageStatusString() self:drawText(str, self.healthPanel.x + 165, y, 1.0, 1.0 - InjuryRedTextTint, 1.0 - InjuryRedTextTint, 1.0, UIFont.Small) y = y + fontHgt local x = 180; local fgBar = {r=0.5, g=0.5, b=0.5, a=0.5} local doctor = self.otherPlayer or self.character if doctor:getJoypadBind() ~= -1 then self:drawTextureScaled(self.abutton, 8, self.height - PAD_BOTTOM - fontHgt, fontHgt, fontHgt, 1.0, 1.0, 1.0, 1.0); self:drawText(getText("IGUI_health_JoypadTreatment"), 8 + fontHgt + 2, self.height - PAD_BOTTOM - fontHgt, 1, 1, 1, 1, UIFont.Small); else self:drawText(getText("IGUI_health_RightClickTreatement"), 8, self.height - PAD_BOTTOM - fontHgt, 1, 1, 1, 1, UIFont.Small); end -- for each damaged body part, we gonna display the body part name + the damage type local painLevel = self:getPatient():getMoodles():getMoodleLevel(MoodleType.Pain) if isClient() and not self:getPatient():isLocalPlayer() then painLevel = self:getPatient():getBodyDamageRemote():getRemotePainLevel() end if (self.doctorLevel > 4 or self.character == getPlayer() or ISHealthPanel.cheat) and painLevel > 0 then self:drawText(getText("Moodles_pain_lvl" .. painLevel), x - 15, y, 1, 1, 1, 1, UIFont.Small); y = y + fontHgt; end if self.cheat and self.character:getBodyDamage():getFakeInfectionLevel() > 0 then self:drawText("Fake infection level " .. self.character:getBodyDamage():getFakeInfectionLevel(), x - 15, y, 1, 1, 1, 1, UIFont.Small); y = y + fontHgt; end if self.cheat and self.character:getReduceInfectionPower() > 0 then self:drawText("Antibiotic level " .. self.character:getReduceInfectionPower(), x - 15, y, 1, 1, 1, 1, UIFont.Small); y = y + fontHgt; end local listItemsHeight = self.listbox:getScrollHeight() local myHeight = y + listItemsHeight + fontHgt + PAD_BOTTOM * 2 local myY = self:getY() local parent = self.parent while parent and parent.parent do myY = myY + parent:getY() parent = parent.parent end if myY + myHeight > getCore():getScreenHeight() then myHeight = getCore():getScreenHeight() - myY end self.listbox:setY(y) self.listbox:setHeight(myHeight - (fontHgt + PAD_BOTTOM * 2) - y) self.listbox.vscroll:setHeight(self.listbox:getHeight()) self.allTextHeight = myHeight - (fontHgt + PAD_BOTTOM * 2) if self.blockingMessage then self:drawRect(0, 0, self.width, self.height, 0.9*self.blockingAlpha, 0, 0, 0); self:drawText(self.blockingMessage, self.width/2 - (getTextManager():MeasureStringX(UIFont.Medium, self.blockingMessage) / 2), (self.height / 2) - 5, 1,1,1,1, UIFont.Medium); end end function ISHealthPanel:getDoctor() return self.otherPlayer or self.character end function ISHealthPanel:getPatient() return self.character end function ISHealthPanel:getDamagedParts() local result = {} local bodyParts = self:getPatient():getBodyDamage():getBodyParts() if isClient() and not self:getPatient():isLocalPlayer() then bodyParts = self:getPatient():getBodyDamageRemote():getBodyParts() end for i=1,bodyParts:size() do local bodyPart = bodyParts:get(i-1) local bodyPartAction = self.bodyPartAction and self.bodyPartAction[bodyPart] if ISHealthPanel.cheat or bodyPart:HasInjury() or bodyPart:bandaged() or bodyPart:stitched() or bodyPart:getSplintFactor() > 0 or bodyPart:getAdditionalPain() > 10 or bodyPart:getStiffness() > 5 then table.insert(result, bodyPart) end end return result end function ISHealthPanel:updateBodyPartList() -- These aid in reloading the .lua when debugging self.listbox.drawText = self.drawText local damagedParts = self:getDamagedParts() local changed = false if #damagedParts == #self.damagedParts then for i=1,#damagedParts do if damagedParts[i] ~= self.damagedParts[i] then changed = true break end end else changed = true end if not changed then return end self.listbox:clear() for i=1,#damagedParts do local bodyPart = damagedParts[i] local data = {} data.bodyPart = bodyPart self.listbox:addItem('dummy', data) end self.damagedParts = damagedParts self.textRight = 0 self.listbox.textRight = 0 end function ISHealthPanel:drawText(str, x, y, r, g, b, a, font) ISUIElement.drawText(self, str, x, y, r, g, b, a, font) local width = getTextManager():MeasureStringX(font or UIFont.Small, str) self.textRight = math.max(self.textRight or 0, x + width) end function ISHealthBodyPartListBox:doDrawItem(y, item, alt) local healthPanel = self.parent local bodyPart = item.item.bodyPart; local bodyPartAction = healthPanel.bodyPartAction and healthPanel.bodyPartAction[bodyPart] local x = 15; local fontHgt = FONT_HGT_SMALL local fgBar = {r=0.5, g=0.5, b=0.5, a=0.5} if item.itemindex == self.selected then self:drawRect(0, y, self:getWidth(), item.height, 0.2, 1.0, 1.0, 1.0); local selectedBp = self.parent.bodyPartPanel.selectedBp if selectedBp and (bodyPart == selectedBp.bodyPart) then self:drawRectBorder(0, y, self:getWidth() - 1, item.height, 1.0, 1.0, 1.0, 1.0); end elseif item.itemindex == self.mouseoverselected then self:drawRect(0, y, self:getWidth(), item.height, 0.05,1.0,1.0,1.0); if ISMouseDrag.dragging and (#ISMouseDrag.dragging > 0) then self:drawRectBorder(0, y, self:getWidth() - 1, item.height, 1.0, 1.0, 1.0, 1.0); end end if ISHealthPanel.cheat then self:drawText(BodyPartType.getDisplayName(bodyPart:getType()) .. " (health=" .. round(bodyPart:getHealth(), 4) .. ")", x - 15, y, 1, 1, 1, 1, UIFont.Small); else self:drawText(BodyPartType.getDisplayName(bodyPart:getType()), x - 15, y, 1, 1, 1, 1, UIFont.Small); end y = y + fontHgt; if bodyPartAction then self:drawProgressBar(x, y, self.width - 10 - x, fontHgt, bodyPartAction.delta, fgBar) self:drawText(bodyPartAction.jobType, x + 4, y, 0.8, 0.8, 0.8, 1, UIFont.Small) y = y + fontHgt else local actionQueue = ISTimedActionQueue.getTimedActionQueue(healthPanel.otherPlayer or healthPanel.character); if actionQueue and actionQueue.queue and healthPanel.actions and healthPanel.actions[actionQueue.queue[1]] == bodyPart then self:drawProgressBar(x, y, self.width - 10 - x, fontHgt, actionQueue.queue[1]:getJobDelta(), fgBar); self:drawText(actionQueue.queue[1].jobType, x + 4, y, 0.8, 0.8, 0.8, 1, UIFont.Small); -- jobType is a hack for CraftingUI as well y = y + fontHgt end end if bodyPart:getPlantainFactor() > 0 then self:drawText("- " .. getText("ContextMenu_PlantainCataplasm"),x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - factor " .. round(bodyPart:getPlantainFactor(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:getComfreyFactor() > 0 then self:drawText("- " .. getText("ContextMenu_ComfreyCataplasm"),x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - factor " .. round(bodyPart:getComfreyFactor(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:getGarlicFactor() > 0 then self:drawText("- " .. getText("ContextMenu_GarlicCataplasm"),x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - factor " .. round(bodyPart:getGarlicFactor(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:scratched() then local text = ""; if healthPanel.doctorLevel > 2 or ISHealthPanel.cheat then -- a doctor will evaluate the wound if bodyPart:getScratchTime() > 17 then text = " (" .. getText("IGUI_health_Severe") ..")"; elseif bodyPart:getScratchTime() > 14 then text = " (" .. getText("IGUI_health_Moderate") ..")"; end end self:drawText("- " .. getText("IGUI_health_Scratched") .. text, x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then if(bodyPart:getScratchTime() > 0) then self:drawText(" - scratch Time " .. round(bodyPart:getScratchTime(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end end if bodyPart:isCut() then local text = ""; if healthPanel.doctorLevel > 2 or ISHealthPanel.cheat then -- a doctor will evaluate the wound if bodyPart:getCutTime() > 17 then text = " (" .. getText("IGUI_health_Severe") ..")"; elseif bodyPart:getCutTime() > 14 then text = " (" .. getText("IGUI_health_Moderate") ..")"; end end self:drawText("- " .. getText("IGUI_health_Cut") .. text, x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then if(bodyPart:getCutTime() > 0) then self:drawText(" - cut Time " .. round(bodyPart:getCutTime(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end end if bodyPart:deepWounded() then local text = ""; if healthPanel.doctorLevel > 4 or ISHealthPanel.cheat then -- a doctor will evaluate the wound if bodyPart:getDeepWoundTime() > 10 then text = " (" .. getText("IGUI_health_Severe") ..")"; elseif bodyPart:getDeepWoundTime() > 8 then text = " (" .. getText("IGUI_health_Moderate") ..")"; end end self:drawText("- " .. getText("IGUI_health_DeepWound") .. " " .. text, x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - deepWound Time " .. round(bodyPart:getDeepWoundTime(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:bitten() then self:drawText("- " .. getText("IGUI_health_Bitten"), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - bite Time " .. round(bodyPart:getBiteTime(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:getAdditionalPain() > 10 then if bodyPart:getAdditionalPain() > 50 then self:drawText("- " .. getText("IGUI_health_HeavyPain"), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); else self:drawText("- " .. getText("IGUI_health_Pain"), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); end y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - additional pain " .. round(bodyPart:getAdditionalPain(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:getStiffness() > 5 then self:drawText("- " .. getText("IGUI_health_Stiffness"), x, y, 1, 0.58, 0, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - exercise fatigue " .. round(bodyPart:getStiffness(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:bleeding() then self:drawText("- " .. getText("IGUI_health_Bleeding"),x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - bleeding Time " .. round(bodyPart:getBleedingTime(),2),x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:getFractureTime() > 0 and bodyPart:getSplintFactor() == 0 then local text = ""; if healthPanel.doctorLevel > 6 or ISHealthPanel.cheat then -- a doctor will evaluate the wound if bodyPart:getFractureTime() > 50 then text = " (" .. getText("IGUI_health_Severe") ..")"; elseif bodyPart:getFractureTime() > 20 then text = " (" .. getText("IGUI_health_Moderate") ..")"; end end self:drawText("- " .. getText("IGUI_health_Fracture") .. " " .. text,x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - fracture Time " .. round(bodyPart:getFractureTime(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:getSplintFactor() > 0 then local text = ""; if healthPanel.doctorLevel > 4 or ISHealthPanel.cheat then -- a doctor will evaluate the wound if bodyPart:getSplintFactor() > 4 then text = " (" .. getText("IGUI_health_Good") ..")"; elseif bodyPart:getFractureTime() > 2 then text = " (" .. getText("IGUI_health_Moderate") ..")"; end end self:drawText("- " .. getText("IGUI_health_Splinted") .. " " .. text,x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - splint Factor " .. round(bodyPart:getSplintFactor(),2), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:bandaged() then if bodyPart:getBandageLife() > 0 then self:drawText("- " .. getText("IGUI_health_Bandaged"), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); else self:drawText("- " .. getText("IGUI_health_DirtyBandage"), x, y, 1, 0.28, 0, 1, UIFont.Small); end y = y + fontHgt; if ISHealthPanel.cheat then if(bodyPart:getBandageLife() > 0) then self:drawText(" - Bandage Life " .. round(bodyPart:getBandageLife(), 4), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; end if(bodyPart:getBleedingTime() > 0) then self:drawText(" - bleeding Time " .. round(bodyPart:getBleedingTime(), 4), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; end if(bodyPart:getScratchTime() > 0) then self:drawText(" - scratch Time " .. round(bodyPart:getScratchTime(), 4), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; end if(bodyPart:getCutTime() > 0) then self:drawText(" - cut Time " .. round(bodyPart:getCutTime(), 4), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; end if(bodyPart:getDeepWoundTime() > 0) then self:drawText(" - deep-wound Time " .. round(bodyPart:getDeepWoundTime(), 4), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; end end end if bodyPart:isInfectedWound() and not bodyPart:bandaged() then if healthPanel.doctorLevel > 8 or (bodyPart:getWoundInfectionLevel() * 10 >= (2.5 - healthPanel.doctorLevel)) or ISHealthPanel.cheat then -- only a good doctor will know fast if a wound is infected or not self:drawText("- " .. getText("IGUI_health_Infected"), x, y, 1, 0.28, 0, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - WOUND infection Time " .. round(bodyPart:getWoundInfectionLevel(), 4), x, y, 1, 0.28, 0, 1, UIFont.Small); y = y + fontHgt; end end end if bodyPart:haveBullet() and not bodyPart:bandaged() then self:drawText("- " .. getText("IGUI_health_LodgedBullet"), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end if bodyPart:getBurnTime() > 0 and not bodyPart:bandaged() then local burnText = ""; if (healthPanel.doctorLevel > 4 or ISHealthPanel.cheat) and bodyPart:isNeedBurnWash() then burnText = " (" .. getText("IGUI_health_NeedCleaning") ..")"; end self:drawText("- " .. getText("IGUI_health_Burned") .. burnText, x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - burn Time " .. round(bodyPart:getBurnTime(), 4) .. "(" .. bodyPart:getLastTimeBurnWash() .. ")", x, y, 1, 0.28, 0, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:stitched() then local text = ""; if healthPanel.doctorLevel > 6 or ISHealthPanel.cheat then -- show if the stitch can be removed if bodyPart:getStitchTime() > 40 then text = " (" .. getText("IGUI_health_Good") ..")"; else text = " (" .. getText("IGUI_health_NeedTime") ..")"; end end self:drawText("- " .. getText("IGUI_health_Stitched") ..text, x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; if ISHealthPanel.cheat then self:drawText(" - stitch Time " .. round(bodyPart:getStitchTime(), 4), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small); y = y + fontHgt; end end if bodyPart:haveGlass() and not bodyPart:bandaged() then self:drawText("- " .. getText("IGUI_health_LodgedGlassShards"), x, y, 0.89, 0.28, 0.28, 1, UIFont.Small); y = y + fontHgt; end y = y + 5; return y; end function ISHealthPanel.setBodyPartActionForPlayer(playerObj, bodyPart, action, jobType, args) if not playerObj or playerObj:isDead() then return end if args then args.jobType = jobType args.delta = action:getJobDelta() end if playerObj:isLocalPlayer() then local infoPanel = getPlayerInfoPanel(playerObj:getPlayerNum()) if infoPanel then infoPanel.healthView:setBodyPartAction(bodyPart, args) end end -- Handle coop and remote players local window = ISMedicalCheckAction.getHealthWindowForPlayer(playerObj) if window then window.nested:setBodyPartAction(bodyPart, args) end end function ISHealthPanel:setBodyPartAction(bodyPart, args) self.bodyPartAction = self.bodyPartAction or {} self.bodyPartAction[bodyPart] = args end function ISHealthPanel:setOtherPlayer(playerObj) self.characterX = self.character:getX() self.characterY = self.character:getY() self.otherPlayer = playerObj self.otherPlayerX = playerObj:getX() self.otherPlayerY = playerObj:getY() end -- This is used by various timed action isValid() functions to check that the patient -- has not moved away from the doctor. function ISHealthPanel.DidPatientMove(doctor, patient, patientX, patientY) if doctor == patient then return false end if patient:getX() == patientX and patient:getY() == patientY then return false end -- Driving in a moving vehicle is not ok if patient:isDriving() then return true end -- Driver in a stopped vehicle or passenger in moving vehicle are both ok if patient:getVehicle() then return false end return true end function ISHealthPanel:onGainJoypadFocus(joypadData) ISPanel.onGainJoypadFocus(self, joypadData) if self.otherPlayer then self.parent.drawJoypadFocus = true else self:setISButtonForY(self.fitness) end end function ISHealthPanel:onLoseJoypadFocus(joypadData) ISPanel.onLoseJoypadFocus(self, joypadData) if self.otherPlayer then self.parent.drawJoypadFocus = false end end function ISHealthPanel:onJoypadDown(button) if self.otherPlayer then if button == Joypad.BButton then self.parent:removeFromUIManager() setJoypadFocus(self.joyfocus.player, nil) self:getDoctor():stopReceivingBodyDamageUpdates(self:getPatient()) end if button == Joypad.AButton then local listItem = self.listbox.items[self.listbox.selected] if listItem then self:doBodyPartContextMenu(listItem.item.bodyPart, 50, 50) end end return end if button == Joypad.BButton then getPlayerInfoPanel(self.playerNum):toggleView(xpSystemText.health) setJoypadFocus(self.playerNum, nil) end if button == Joypad.LBumper then getPlayerInfoPanel(self.playerNum):onJoypadDown(button) end if button == Joypad.RBumper then getPlayerInfoPanel(self.playerNum):onJoypadDown(button) end if button == Joypad.AButton then local listItem = self.listbox.items[self.listbox.selected] if listItem then self:doBodyPartContextMenu(listItem.item.bodyPart, 50, 50) end end if button == Joypad.YButton then self.fitness:forceClick() end end function ISHealthPanel:onJoypadDirUp() self.listbox:onJoypadDirUp() end function ISHealthPanel:onJoypadDirDown() self.listbox:onJoypadDirDown() end function ISHealthPanel:new (player, x, y, width, height) local o = {}; o = ISPanelJoypad:new(x, y, width, height); setmetatable(o, self); self.__index = self; o.otherPlayer = nil; o.progressBarLoaded = false; o.character = player; o.playerNum = player:getPlayerNum() -- o.healthPanel = NewHealthPanel.new(20,20,o.character); -- o.healthPanel:setVisible(true); o.doctorLevel = player:getPerkLevel(Perks.Doctor); o:noBackground(); o.abutton = Joypad.Texture.AButton o.damagedParts = {} ISHealthPanel.instance = o; return o; end ----- HealthPanelAction = ISBaseTimedAction:derive("HealthPanelAction") function HealthPanelAction:isValid() local valid = self.handler:isValid(self.args[1], self.args[2], self.args[3], self.args[4], self.args[5], self.args[6], self.args[7], self.args[8]) -- print(self.handler.Type .. "["..tostring(self.handler).. "].isValid() == " .. tostring(valid)) if valid == true or valid == false then return valid end return valid ~= nil end function HealthPanelAction:start() end function HealthPanelAction:update() self:forceComplete() end function HealthPanelAction:stop() ISBaseTimedAction.stop(self) end function HealthPanelAction:perform() -- print(self.handler.Type .. "["..tostring(self.handler).. "].perform()") self.handler:perform(self, self.args[1], self.args[2], self.args[3], self.args[4], self.args[5], self.args[6], self.args[7], self.args[8]) -- needed to remove from queue / start next. ISBaseTimedAction.perform(self) end function HealthPanelAction:new(character, handler, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) local o = ISBaseTimedAction.new(self, character) o.stopOnWalk = false o.stopOnRun = true o.maxTime = -1 o.handler = handler o.args = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 } return o end ----- local BaseHandler = ISBaseObject:derive("BaseHandler") function BaseHandler:new(panel, bodyPart) local o = {} setmetatable(o, self) self.__index = self o.panel = panel o.bodyPart = bodyPart o.items = {} return o end function BaseHandler:isInjured() local bodyPart = self.bodyPart return (bodyPart:HasInjury() or bodyPart:stitched() or bodyPart:getSplintFactor() > 0) and not bodyPart:bandaged() end function BaseHandler:checkItems() for k,v in pairs(self.items) do table.wipe(v) end local containers = ISInventoryPaneContextMenu.getContainers(self:getDoctor()) local done = {} local childContainers = {} for i=1,containers:size() do local container = containers:get(i-1) done[container] = true table.wipe(childContainers) self:checkContainerItems(container, childContainers) for _,container2 in ipairs(childContainers) do if not done[container2] then done[container2] = true self:checkContainerItems(container2, nil) end end end end function BaseHandler:checkContainerItems(container, childContainers) local containerItems = container:getItems() for i=1,containerItems:size() do local item = containerItems:get(i-1) if item:IsInventoryContainer() then if childContainers then table.insert(childContainers, item:getInventory()) end else self:checkItem(item) end end end function BaseHandler:dropItems(items) return false end function BaseHandler:addItem(items, item) table.insert(items, item) end function BaseHandler:getAllItemTypes(items) local done = {} local types = {} for _,item in ipairs(items) do if not done[item:getFullType()] then table.insert(types, item:getFullType()) done[item:getFullType()] = true end end return types end function BaseHandler:getItemOfType(items, type) for _,item in ipairs(items) do if item:getFullType() == type then return item end end return nil end function BaseHandler:getItemOfTag(items, type) for _,item in ipairs(items) do if item:hasTag(type) then return item end end return nil end function BaseHandler:getAllItemsOfType(items, type) local items = {} for _,item in ipairs(items) do if item:getFullType() == type then table.insert(items, item) end end return items end function BaseHandler:onMenuOptionSelected(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) ISTimedActionQueue.add(HealthPanelAction:new(self:getDoctor(), self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)) end function BaseHandler:toPlayerInventory(item, previousAction) if item:getContainer() ~= self:getDoctor():getInventory() then local action = ISInventoryTransferAction:new(self:getDoctor(), item, item:getContainer(), self:getDoctor():getInventory()) ISTimedActionQueue.addAfter(previousAction, action) -- FIXME: ISHealthPanel.actions never gets cleared self.panel.actions = self.panel.actions or {} self.panel.actions[action] = self.bodyPart return action end return previousAction end function BaseHandler:getDoctor() return self.panel.otherPlayer or self.panel.character end function BaseHandler:getPatient() return self.panel.character end ----- local HApplyBandage = BaseHandler:derive("HApplyBandage") function HApplyBandage:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} return o end function HApplyBandage:checkItem(item) if item:getBandagePower() > 0 then self:addItem(self.items.ITEMS, item) end end function HApplyBandage:addToMenu(context) local types = self:getAllItemTypes(self.items.ITEMS) if #types > 0 and self:isInjured() then local option = context:addOption(getText("ContextMenu_Bandage"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) for i=1,#types do local item = self:getItemOfType(self.items.ITEMS, types[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, types[i]) end end end function HApplyBandage:dropItems(items) local types = self:getAllItemTypes(items) if #self.items.ITEMS > 0 and #types == 1 and self:isInjured() then self:onMenuOptionSelected(types[1]) return true end return false end function HApplyBandage:isValid(itemType) self:checkItems() return self:getItemOfType(self.items.ITEMS, itemType) and self:isInjured() end function HApplyBandage:perform(previousAction, itemType) local item = self:getItemOfType(self.items.ITEMS, itemType) previousAction = self:toPlayerInventory(item, previousAction) local action = ISApplyBandage:new(self:getDoctor(), self:getPatient(), item, self.bodyPart, true) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HRemoveBandage = BaseHandler:derive("HRemoveBandage") function HRemoveBandage:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) return o end function HRemoveBandage:checkItem(item) end function HRemoveBandage:addToMenu(context) if self.bodyPart:bandaged() then context:addOption(getText("ContextMenu_Remove_Bandage"), self, self.onMenuOptionSelected) end end function HRemoveBandage:isValid() return self.bodyPart:bandaged() end function HRemoveBandage:perform(previousAction) local action = ISApplyBandage:new(self:getDoctor(), self:getPatient(), nil, self.bodyPart, false) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HApplyPoultice = BaseHandler:derive("HApplyPoultice") function HApplyPoultice:new(panel, bodyPart, itemType, menuLabel, actionClass) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} o.itemType = itemType o.menuLabel = menuLabel o.actionClass = actionClass return o end function HApplyPoultice:checkItem(item) if item:getType() == self.itemType then self:addItem(self.items.ITEMS, item) end end function HApplyPoultice:addToMenu(context) local types = self:getAllItemTypes(self.items.ITEMS) if #types > 0 and self:isInjured() and self.bodyPart:getPlantainFactor() == 0 and self.bodyPart:getComfreyFactor() == 0 and self.bodyPart:getGarlicFactor() == 0 then local option = context:addOption(getText(self.menuLabel), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) for i=1,#types do local item = self:getItemOfType(self.items.ITEMS, types[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, types[i]) end end end function HApplyPoultice:dropItems(items) local types = self:getAllItemTypes(items) if #self.items.ITEMS > 0 and #types == 1 and self:isInjured() and self.bodyPart:getPlantainFactor() == 0 and self.bodyPart:getComfreyFactor() == 0 and self.bodyPart:getGarlicFactor() == 0 then self:onMenuOptionSelected(types[1]) return true end return false end function HApplyPoultice:isValid(itemType) self:checkItems() return self:getItemOfType(self.items.ITEMS, itemType) and self:isInjured() and self.bodyPart:getPlantainFactor() == 0 and self.bodyPart:getComfreyFactor() == 0 and self.bodyPart:getGarlicFactor() == 0 end function HApplyPoultice:perform(previousAction, itemType) local item = self:getItemOfType(self.items.ITEMS, itemType) previousAction = self:toPlayerInventory(item, previousAction) local action = self.actionClass:new(self:getDoctor(), self:getPatient(), item, self.bodyPart) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HApplyComfrey = HApplyPoultice:derive("HApplyComfrey") function HApplyComfrey:new(panel, bodyPart) return HApplyPoultice.new(self, panel, bodyPart, "ComfreyCataplasm", "ContextMenu_ComfreyCataplasm", ISComfreyCataplasm) end ----- local HApplyGarlic = HApplyPoultice:derive("HApplyGarlic") function HApplyGarlic:new(panel, bodyPart) return HApplyPoultice.new(self, panel, bodyPart, "WildGarlicCataplasm", "ContextMenu_GarlicCataplasm", ISGarlicCataplasm) end ----- local HApplyPlantain = HApplyPoultice:derive("HApplyPlantain") function HApplyPlantain:new(panel, bodyPart) return HApplyPoultice.new(self, panel, bodyPart, "PlantainCataplasm", "ContextMenu_PlantainCataplasm", ISPlantainCataplasm) end ----- local HDisinfect = BaseHandler:derive("HDisinfect") function HDisinfect:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} return o end function HDisinfect:checkItem(item) if item:getAlcoholPower() > 0 then self:addItem(self.items.ITEMS, item) end end function HDisinfect:addToMenu(context) local types = self:getAllItemTypes(self.items.ITEMS) if #types > 0 and self:isInjured() then local option = context:addOption(getText("ContextMenu_Disinfect"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) for i=1,#types do local item = self:getItemOfType(self.items.ITEMS, types[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, types[i]) end end end function HDisinfect:dropItems(items) local types = self:getAllItemTypes(items) if #self.items.ITEMS > 0 and #types == 1 and self:isInjured() then self:onMenuOptionSelected(types[1]) return true end return false end function HDisinfect:isValid(itemType) self:checkItems() return self:getItemOfType(self.items.ITEMS, itemType) and self:isInjured() end function HDisinfect:perform(previousAction, itemType) local item = self:getItemOfType(self.items.ITEMS, itemType) previousAction = self:toPlayerInventory(item, previousAction) local action = ISDisinfect:new(self:getDoctor(), self:getPatient(), item, self.bodyPart) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HStitch = BaseHandler:derive("HStitch") function HStitch:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} return o end function HStitch:checkItem(item) if item:getType() == "Needle" or item:hasTag("SewingNeedle") then self:addItem(self.items.ITEMS, item) end if item:getType() == "Thread" and item:getUsedDelta() >= 0 then self:addItem(self.items.ITEMS, item) end if item:getType() == "SutureNeedle" then self:addItem(self.items.ITEMS, item) end end function HStitch:addToMenu(context) if not self:isInjured() or not self.bodyPart:isDeepWounded() or self.bodyPart:haveGlass() then return false end local needle = self:getItemOfType(self.items.ITEMS, "Base.Needle") or self:getItemOfTag(self.items.ITEMS, "SewingNeedle") local thread = self:getItemOfType(self.items.ITEMS, "Base.Thread") local needlePlusThread = self:getItemOfType(self.items.ITEMS, "Base.SutureNeedle") if (needle and thread) or needlePlusThread then local option = context:addOption(getText("ContextMenu_Stitch"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) if needlePlusThread then subMenu:addOption(needlePlusThread:getName(), self, self.onMenuOptionSelected, needlePlusThread:getFullType(), needlePlusThread:getFullType()) end if needle and thread then local text = needle:getName() .. " + " .. thread:getName() subMenu:addOption(text, self, self.onMenuOptionSelected, needle:getFullType(), thread:getFullType()) end end end function HStitch:dropItems(items) if not self:isInjured() or not self.bodyPart:isDeepWounded() or self.bodyPart:haveGlass() then return false end local needlePlusThread = self:getItemOfType(self.items.ITEMS, "Base.SutureNeedle") if needlePlusThread then self:onMenuOptionSelected(needlePlusThread:getFullType(), needlePlusThread:getFullType()) return true end local needle = self:getItemOfType(self.items.ITEMS, "Base.Needle") or self:getItemOfTag(self.items.ITEMS, "SewingNeedle") local thread = self:getItemOfType(self.items.ITEMS, "Base.Thread") if needle and thread then self:onMenuOptionSelected(needle:getFullType(), thread:getFullType()) return true end return false end function HStitch:isValid(needleType, threadType) if not self:isInjured() or not self.bodyPart:isDeepWounded() or self.bodyPart:haveGlass() then return false end self:checkItems() if needleType == threadType then local needlePlusThread = self:getItemOfType(self.items.ITEMS, needleType) return needlePlusThread ~= nil else local needle = self:getItemOfType(self.items.ITEMS, needleType) local thread = self:getItemOfType(self.items.ITEMS, threadType) return (needle and thread) ~= nil end end function HStitch:perform(previousAction, needleType, threadType) if needleType == threadType then local needle = self:getItemOfType(self.items.ITEMS, needleType) previousAction = self:toPlayerInventory(needle, previousAction) local action = ISStitch:new(self:getDoctor(), self:getPatient(), needle, self.bodyPart, true) ISTimedActionQueue.addAfter(previousAction, action) else local needle = self:getItemOfType(self.items.ITEMS, needleType) local thread = self:getItemOfType(self.items.ITEMS, threadType) previousAction = self:toPlayerInventory(needle, previousAction) previousAction = self:toPlayerInventory(thread, previousAction) local action = ISStitch:new(self:getDoctor(), self:getPatient(), thread, self.bodyPart, true) ISTimedActionQueue.addAfter(previousAction, action) end end ----- local HRemoveStitch = BaseHandler:derive("HRemoveStitch") function HRemoveStitch:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) return o end function HRemoveStitch:checkItem(item) end function HRemoveStitch:addToMenu(context) if self.bodyPart:stitched() then context:addOption(getText("ContextMenu_Remove_Stitch"), self, self.onMenuOptionSelected) end end function HRemoveStitch:isValid() return self.bodyPart:stitched() end function HRemoveStitch:perform(previousAction) local action = ISStitch:new(self:getDoctor(), self:getPatient(), nil, self.bodyPart, false) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HRemoveGlass = BaseHandler:derive("HRemoveGlass") function HRemoveGlass:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} return o end function HRemoveGlass:checkItem(item) if item:hasTag("RemoveGlass") or item:getType() == "SutureNeedleHolder" or item:getType() == "Tweezers" then self:addItem(self.items.ITEMS, item) end end function HRemoveGlass:addToMenu(context) local types = self:getAllItemTypes(self.items.ITEMS) if self:isInjured() and self.bodyPart:haveGlass() then local option = context:addOption(getText("ContextMenu_Remove_Glass"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) if #types > 0 then for i=1,#types do local item = self:getItemOfType(self.items.ITEMS, types[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, types[i]) end end subMenu:addOption(getText("ContextMenu_Hand"), self, self.onMenuOptionSelected, "Hands") end end function HRemoveGlass:dropItems(items) local types = self:getAllItemTypes(items) if #self.items.ITEMS > 0 and #types == 1 and self:isInjured() and self.bodyPart:haveGlass() then self:onMenuOptionSelected(types[1]) return true end return false end function HRemoveGlass:isValid(itemType) self:checkItems() return (self:getItemOfType(self.items.ITEMS, itemType) and self:isInjured() and self.bodyPart:haveGlass()) or (itemType == "Hands" and self:isInjured() and self.bodyPart:haveGlass()) end function HRemoveGlass:perform(previousAction, itemType) if (itemType == "Hands") then local action = ISRemoveGlass:new(self:getDoctor(), self:getPatient(), self.bodyPart, true) ISTimedActionQueue.add(action) else local item = self:getItemOfType(self.items.ITEMS, itemType) previousAction = self:toPlayerInventory(item, previousAction) local action = ISRemoveGlass:new(self:getDoctor(), self:getPatient(), self.bodyPart) ISTimedActionQueue.addAfter(previousAction, action) end end ----- local HSplint = BaseHandler:derive("HSplint") function HSplint:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.splint = {} o.items.plank = {} o.items.rippedSheet = {} return o end function HSplint:checkItem(item) if item:getType() == "Splint" then self:addItem(self.items.splint, item) end if item:getType() == "Plank" or item:getType() == "TreeBranch" or item:getType() == "WoodenStick" then self:addItem(self.items.plank, item) end if item:getType() == "RippedSheets" then self:addItem(self.items.rippedSheet, item) end end function HSplint:addToMenu(context) -- can't splint chest/head if self.bodyPart:getType() == BodyPartType.Head or self.bodyPart:getType() == BodyPartType.Torso_Upper or self.bodyPart:getType() == BodyPartType.Torso_Lower then return false; end; if (not self.bodyPart:HasInjury() or self.bodyPart:stitched() or self.bodyPart:getSplintFactor() > 0) or self.bodyPart:getFractureTime() <= 0 or self.bodyPart:getSplintFactor() > 0 then return false; end local splintType = self:getAllItemTypes(self.items.splint) local plankType = self:getAllItemTypes(self.items.plank) local rippedSheetType = self:getAllItemTypes(self.items.rippedSheet) if #splintType > 0 or (#plankType > 0 and #rippedSheetType > 0) then local option = context:addOption(getText("ContextMenu_Splint"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) for i=1,#splintType do local item = self:getItemOfType(self.items.splint, splintType[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, nil, item:getFullType()) end if #plankType > 0 and #rippedSheetType > 0 then local rippedSheet = self:getItemOfType(self.items.rippedSheet, rippedSheetType[1]) for i=1,#plankType do local plank = self:getItemOfType(self.items.plank, plankType[i]) local text = plank:getName() .. " + " .. rippedSheet:getName() subMenu:addOption(text, self, self.onMenuOptionSelected, rippedSheet:getFullType(), plank:getFullType()) end end end end function HSplint:dropItems(items) if self.bodyPart:getType() == BodyPartType.Head or self.bodyPart:getType() == BodyPartType.Torso_Upper or self.bodyPart:getType() == BodyPartType.Torso_Lower or not (not self.bodyPart:HasInjury() or self.bodyPart:stitched() or self.bodyPart:getSplintFactor() > 0) or self.bodyPart:getFractureTime() <= 0 or self.bodyPart:getSplintFactor() > 0 then return false end local splintType = self:getAllItemTypes(self.items.splint) if #splintType > 0 then self:onMenuOptionSelected(nil, splintType[1]) return true end local plankType = self:getAllItemTypes(self.items.plank) local rippedSheetType = self:getAllItemTypes(self.items.rippedSheet) if #plankType > 0 and #rippedSheetType > 0 then self:onMenuOptionSelected(rippedSheetType[1], plankType[1]) return true end return false end function HSplint:isValid(rippedSheetType, plankType) if (not self.bodyPart:HasInjury() or self.bodyPart:stitched() or self.bodyPart:getSplintFactor() > 0) or self.bodyPart:getFractureTime() <= 0 or self.bodyPart:getSplintFactor() > 0 then return false end self:checkItems() local splints = self.items.splint local planks = self.items.plank local rippedSheets = self.items.rippedSheet return #splints > 0 or (#planks > 0 and #rippedSheets > 0) end function HSplint:perform(previousAction, rippedSheetType, plankType) if rippedSheetType then local rippedSheet = self:getItemOfType(self.items.rippedSheet, rippedSheetType) local plank = self:getItemOfType(self.items.plank, plankType) previousAction = self:toPlayerInventory(rippedSheet, previousAction) previousAction = self:toPlayerInventory(plank, previousAction) local action = ISSplint:new(self:getDoctor(), self:getPatient(), rippedSheet, plank, self.bodyPart, true) ISTimedActionQueue.addAfter(previousAction, action) else local splint = self:getItemOfType(self.items.splint, plankType) previousAction = self:toPlayerInventory(splint, previousAction) local action = ISSplint:new(self:getDoctor(), self:getPatient(), nil, splint, self.bodyPart, true) ISTimedActionQueue.addAfter(previousAction, action) end end ----- local HRemoveSplint = BaseHandler:derive("HRemoveSplint") function HRemoveSplint:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) return o end function HRemoveSplint:checkItem(item) end function HRemoveSplint:addToMenu(context) if (self.bodyPart:HasInjury() or self.bodyPart:stitched() or self.bodyPart:getSplintFactor() > 0) and self.bodyPart:getSplintFactor() > 0 then context:addOption(getText("ContextMenu_Remove_Splint"), self, self.onMenuOptionSelected) end end function HRemoveSplint:isValid() return (self.bodyPart:HasInjury() or self.bodyPart:stitched() or self.bodyPart:getSplintFactor() > 0) and self.bodyPart:getSplintFactor() > 0 end function HRemoveSplint:perform(previousAction) local action = ISSplint:new(self:getDoctor(), self:getPatient(), nil, nil, self.bodyPart, false) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HRemoveBullet = BaseHandler:derive("HRemoveBullet") function HRemoveBullet:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} return o end function HRemoveBullet:checkItem(item) if item:hasTag("RemoveBullet") or item:getType() == "Tweezers" or item:getType() == "SutureNeedleHolder" then self:addItem(self.items.ITEMS, item) end end function HRemoveBullet:addToMenu(context) local types = self:getAllItemTypes(self.items.ITEMS) if #types > 0 and self:isInjured() and self.bodyPart:haveBullet() then local option = context:addOption(getText("ContextMenu_Remove_Bullet"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) for i=1,#types do local item = self:getItemOfType(self.items.ITEMS, types[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, item:getFullType()) end end end function HRemoveBullet:dropItems(items) local types = self:getAllItemTypes(items) if #self.items.ITEMS > 0 and #types == 1 and self:isInjured() and self.bodyPart:haveBullet() then self:onMenuOptionSelected(types[1]) return true end return false end function HRemoveBullet:isValid(itemType) return self:isInjured() and self.bodyPart:haveBullet() and self:getItemOfType(self.items.ITEMS, itemType) end function HRemoveBullet:perform(previousAction, itemType) local item = self:getItemOfType(self.items.ITEMS, itemType) previousAction = self:toPlayerInventory(item, previousAction) local action = ISRemoveBullet:new(self:getDoctor(), self:getPatient(), self.bodyPart) ISTimedActionQueue.addAfter(previousAction, action) end ----- local HCleanBurn = BaseHandler:derive("HCleanBurn") function HCleanBurn:new(panel, bodyPart) local o = BaseHandler.new(self, panel, bodyPart) o.items.ITEMS = {} return o end function HCleanBurn:checkItem(item) if item:getBandagePower() >= 2 then self:addItem(self.items.ITEMS, item) end end function HCleanBurn:addToMenu(context) local types = self:getAllItemTypes(self.items.ITEMS) if #types > 0 and self:isInjured() and self.bodyPart:isNeedBurnWash() then local option = context:addOption(getText("ContextMenu_Clean_Burn"), nil) local subMenu = context:getNew(context) context:addSubMenu(option, subMenu) for i=1,#types do local item = self:getItemOfType(self.items.ITEMS, types[i]) subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, item:getFullType()) end end end function HCleanBurn:dropItems(items) local types = self:getAllItemTypes(items) if #self.items.ITEMS > 0 and #types == 1 and self:isInjured() and self.bodyPart:isNeedBurnWash() then -- FIXME: A bandage can be used to clean a burn or bandage it self:onMenuOptionSelected(types[1]) return true end return false end function HCleanBurn:isValid(itemType) return self:isInjured() and self.bodyPart:isNeedBurnWash() and self:getItemOfType(self.items.ITEMS, itemType) end function HCleanBurn:perform(previousAction, itemType) local item = self:getItemOfType(self.items.ITEMS, itemType) previousAction = self:toPlayerInventory(item, previousAction) local action = ISCleanBurn:new(self:getDoctor(), self:getPatient(), item, self.bodyPart) ISTimedActionQueue.addAfter(previousAction, action) end ----- function ISHealthPanel:checkItems(handlers) local containers = ISInventoryPaneContextMenu.getContainers(self:getDoctor()) local done = {} local childContainers = {} for i=1,containers:size() do local container = containers:get(i-1) done[container] = true table.wipe(childContainers) self:checkContainerItems(container, childContainers, handlers) for _,container2 in ipairs(childContainers) do if not done[container2] then done[container2] = true self:checkContainerItems(container, nil, handlers) end end end end function ISHealthPanel:checkContainerItems(container, childContainers, handlers) local containerItems = container:getItems() for i=1,containerItems:size() do local item = containerItems:get(i-1) if item:IsInventoryContainer() then if childContainers then table.insert(childContainers, item:getInventory()) end else for _,handler in ipairs(handlers) do handler:checkItem(item) end end end end function ISHealthPanel:doBodyPartContextMenu(bodyPart, x, y) local playerNum = self.otherPlayer and self.otherPlayer:getPlayerNum() or self.character:getPlayerNum() local context = ISContextMenu.get(playerNum, x + self:getAbsoluteX(), y + self:getAbsoluteY()); local handlers = {} table.insert(handlers, HRemoveBandage:new(self, bodyPart)) table.insert(handlers, HApplyPlantain:new(self, bodyPart)) table.insert(handlers, HApplyComfrey:new(self, bodyPart)) table.insert(handlers, HApplyGarlic:new(self, bodyPart)) table.insert(handlers, HApplyBandage:new(self, bodyPart)) table.insert(handlers, HDisinfect:new(self, bodyPart)) table.insert(handlers, HStitch:new(self, bodyPart)) table.insert(handlers, HRemoveStitch:new(self, bodyPart)) table.insert(handlers, HRemoveGlass:new(self, bodyPart)) table.insert(handlers, HSplint:new(self, bodyPart)) table.insert(handlers, HRemoveSplint:new(self, bodyPart)) table.insert(handlers, HRemoveBullet:new(self, bodyPart)) table.insert(handlers, HCleanBurn:new(self, bodyPart)) self:checkItems(handlers) for _,handler in ipairs(handlers) do handler:addToMenu(context) end if ISHealthPanel.cheat then local option = context:addOption("Cheat", nil); local cheatSubMenu = context:getNew(context); context:addSubMenu(option, cheatSubMenu); --- Spawn item --- option = cheatSubMenu:addOption("Spawn Item") local cheatSpawnItemSubMenu = cheatSubMenu:getNew(cheatSubMenu) cheatSubMenu:addSubMenu(option, cheatSpawnItemSubMenu) local types = { "Base.Bandage", "Base.Bandaid", "Base.RippedSheets", "Base.Disinfectant", "Base.Needle", "Base.Thread", "Base.SutureNeedle", "Base.Tweezers", "Base.SutureNeedleHolder", "Base.Splint", "Base.TreeBranch", "Base.WoodenStick", "Base.PlantainCataplasm", "Base.WildGarlicCataplasm", "Base.ComfreyCataplasm" } for _,type in ipairs(types) do local scriptItem = getScriptManager():FindItem(type) local name = scriptItem and scriptItem:getDisplayName() or type cheatSpawnItemSubMenu:addOption(name, type, ISHealthPanel.onCheatItem, self.otherPlayer or self.character) end --- Visual change --- option = cheatSubMenu:addOption("Visual change") local cheatVisualChangeSubMenu = cheatSubMenu:getNew(cheatSubMenu) cheatSubMenu:addSubMenu(option, cheatVisualChangeSubMenu) cheatVisualChangeSubMenu:addOption("Add Dirt", bodyPart, ISHealthPanel.onCheat, "dirt", self.character, self.otherPlayer); cheatVisualChangeSubMenu:addOption("Remove Dirt", bodyPart, ISHealthPanel.onCheat, "removedirt", self.character, self.otherPlayer); cheatVisualChangeSubMenu:addOption("Add Blood", bodyPart, ISHealthPanel.onCheat, "blood", self.character, self.otherPlayer); cheatVisualChangeSubMenu:addOption("Remove Blood", bodyPart, ISHealthPanel.onCheat, "removeblood", self.character, self.otherPlayer); cheatVisualChangeSubMenu:addOption("Add Hole", bodyPart, ISHealthPanel.onCheat, "hole", self.character, self.otherPlayer); cheatVisualChangeSubMenu:addOption("Add Patch", bodyPart, ISHealthPanel.onCheat, "patch", self.character, self.otherPlayer); --- Part change --- option = cheatSubMenu:addOption("Part change") local cheatPartChangeSubMenu = cheatSubMenu:getNew(cheatSubMenu) cheatSubMenu:addSubMenu(option, cheatPartChangeSubMenu) cheatPartChangeSubMenu:addOption("Toggle Bleeding", bodyPart, ISHealthPanel.onCheat, "bleeding", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Bullet", bodyPart, ISHealthPanel.onCheat, "bullet", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Burned", bodyPart, ISHealthPanel.onCheat, "burned", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Burn Needs Wash", bodyPart, ISHealthPanel.onCheat, "burnWash", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Deep Wound", bodyPart, ISHealthPanel.onCheat, "deepWound", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Fracture", bodyPart, ISHealthPanel.onCheat, "fracture", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Glass Shards", bodyPart, ISHealthPanel.onCheat, "glass", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Infected", bodyPart, ISHealthPanel.onCheat, "infected", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Scratched", bodyPart, ISHealthPanel.onCheat, "scratched", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Laceration", bodyPart, ISHealthPanel.onCheat, "cut", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Bite", bodyPart, ISHealthPanel.onCheat, "bite", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Toggle Exercise Fatique", bodyPart, ISHealthPanel.onCheat, "fatique", self.character, self.otherPlayer); cheatPartChangeSubMenu:addOption("Health Full", bodyPart, ISHealthPanel.onCheat, "healthFull", self.character, self.otherPlayer); --- Health Full (Body) --- cheatSubMenu:addOption("Health Full (Body)", bodyPart, ISHealthPanel.onCheat, "healthFullBody", self.character, self.otherPlayer) end if self.blockingMessage or context:isEmpty() then context:setVisible(false); end if JoypadState.players[playerNum+1] and context:getIsVisible() then context.mouseOver = 1 context.origin = self JoypadState.players[playerNum+1].focus = context updateJoypadFocus(JoypadState.players[playerNum+1]) end end -- check what anim nodes to play depending on where you bandage yourself function ISHealthPanel.getBandageType(bodyPart) if bodyPart:getType() == BodyPartType.Head or bodyPart:getType() == BodyPartType.Neck then return "Head"; end if bodyPart:getType() == BodyPartType.Torso_Lower or bodyPart:getType() == BodyPartType.Groin then return "LowerBody"; end if bodyPart:getType() == BodyPartType.Torso_Upper then return "UpperBody"; end if bodyPart:getType() == BodyPartType.Hand_L or bodyPart:getType() == BodyPartType.ForeArm_L or bodyPart:getType() == BodyPartType.UpperArm_L then return "LeftArm"; end if bodyPart:getType() == BodyPartType.Hand_R or bodyPart:getType() == BodyPartType.ForeArm_R or bodyPart:getType() == BodyPartType.UpperArm_R then return "RightArm"; end if bodyPart:getType() == BodyPartType.UpperLeg_L or bodyPart:getType() == BodyPartType.LowerLeg_L or bodyPart:getType() == BodyPartType.Foot_L then return "LeftLeg"; end if bodyPart:getType() == BodyPartType.UpperLeg_R or bodyPart:getType() == BodyPartType.LowerLeg_R or bodyPart:getType() == BodyPartType.Foot_R then return "RightLeg"; end end function ISHealthPanel:dropItemsOnBodyPart(bodyPart, items) local handlers = {} table.insert(handlers, HRemoveBandage:new(self, bodyPart)) table.insert(handlers, HApplyPlantain:new(self, bodyPart)) table.insert(handlers, HApplyComfrey:new(self, bodyPart)) table.insert(handlers, HApplyGarlic:new(self, bodyPart)) -- CleanBurn before ApplyBandage because a bandage can be used to clean a burn table.insert(handlers, HCleanBurn:new(self, bodyPart)) table.insert(handlers, HApplyBandage:new(self, bodyPart)) table.insert(handlers, HDisinfect:new(self, bodyPart)) table.insert(handlers, HStitch:new(self, bodyPart)) table.insert(handlers, HRemoveStitch:new(self, bodyPart)) table.insert(handlers, HRemoveGlass:new(self, bodyPart)) table.insert(handlers, HSplint:new(self, bodyPart)) table.insert(handlers, HRemoveSplint:new(self, bodyPart)) table.insert(handlers, HRemoveBullet:new(self, bodyPart)) for _,handler in ipairs(handlers) do for _,item in ipairs(items) do handler:checkItem(item) end if handler:dropItems(items) then break end end end ISHealthPanel.onCheatHealthCommand = function(module, command, args) if not isClient() then return end if module == "ISHealthPanel" and command == "onHealthCheat" then local pl = getPlayer() ISHealthPanel.onCheatCurrentPlayer(pl:getBodyDamage():getBodyParts():get(args.bodyPartIndex), args.action, pl) end end Events.OnServerCommand.Add(ISHealthPanel.onCheatHealthCommand)