Jump to content

How to make a tool stay on hitting 0% durability?


Recommended Posts

So, we're trying to make a tool for the player to use, that, when it hits 0% durability, instead of breaking, will go in the player inventory and stay there, unusable until it gets repaired.

I'm aware that we'd need to add a repair action, but we're struggling to actually work out how to make this happen. I did find an old thread with some code from w00tydood, but it didn't actually work. Could use a hand here on figuring out how to make this work.

Link to comment
Share on other sites

6 minutes ago, Aquaterion said:

This is all from memory but if it has an onbreak/ondeplete function, you could add a different item that acts as the broken version which spawns when the real one breaks. If not, you would probably have to adjust the armr component a bit

We tried that. It didn't give the item. Going to need an example to work with.

Link to comment
Share on other sites

local function checkCondition(inst, percent)
	if percent <= 0 then
		local owner = inst.components.inventoryitem.owner
		if owner ~= nil then
			local brokenitem = GLOBAL.SpawnPrefab("broken_armor")
			owner.components.inventory:GiveItem(brokenitem)
		end
	end
end

--after adding armor component
inst:ListenForEvent("percentusedchange", checkCondition)

 

Link to comment
Share on other sites

	local assets =
{
    Asset("ANIM", "anim/lightshield.zip"),
    Asset("ANIM", "anim/swap_lightshield.zip"),
}
	local prefabs =
{
    "opalpreciousgem"
}
	
local function onbreak(inst, owner)
    local x,y,z = owner.Transform:GetWorldPosition()
    local opal = SpawnPrefab("opalpreciousgem")
    opal.Transform:SetPosition(x,y,z)
end
	local function OnBlocked(owner, attacker) 
    owner.SoundEmitter:PlaySound("dontstarve/wilson/hit_marble")
end
	local function onequip(inst, owner)
    owner.AnimState:OverrideSymbol("swap_object", "swap_lightshield", "swap_lightshield")
    owner.AnimState:SetMultiSymbolExchange("swap_object", "hand")
    owner.AnimState:Show("ARM_carry")
    owner.AnimState:Hide("ARM_normal")
    inst:ListenForEvent("blocked", OnBlocked, owner)
    owner:AddTag("holdingshield")
    inst.Light:Enable(true)
end
	local function onunequip(inst, owner)
    owner.AnimState:ClearSymbolExchanges()
    owner.AnimState:Hide("ARM_carry")
    owner.AnimState:Show("ARM_normal")
    inst:RemoveEventCallback("blocked", OnBlocked, owner)
    owner:RemoveTag("holdingshield")
    inst.Light:Enable(false)
end
	--[[local function absorptionamount(inst, dt)
    if inst.components.armor.condition < inst.components.armor.maxcondition then
        inst.components.armor:SetAbsorption(inst.components.armor.condition/inst.components.armor.maxcondition)
    end
end]]--
	local function fn()
    local inst = CreateEntity()
	    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddNetwork()
    inst.entity:AddSoundEmitter()
    inst.entity:AddLight()
	    MakeInventoryPhysics(inst)
	    inst.AnimState:SetBank("lightshield")
    inst.AnimState:SetBuild("lightshield")
    inst.AnimState:PlayAnimation("idle")
	    inst.entity:SetPristine()
    
    
    if not TheWorld.ismastersim then
        return inst
    end
	    inst:AddComponent("inspectable")
	    -------
	
    -------
    MakeHauntableLaunch(inst)
    -------
	
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem.imagename = "lightshield"
    inst.components.inventoryitem.atlasname = "images/inventoryimages/InventoryShieldLight.xml"
    
    inst:AddComponent("armor")
    inst.components.armor:InitCondition(DURABILITYLIGHT, 0.95)
    --[[if DURABILITYLIGHT == "150" then
        inst.components.armor:InitCondition(150, 1)
    elseif DURABILITYLIGHT == "200" then
        inst.components.armor:InitCondition(200, 1)
    elseif DURABILITYLIGHT == "250" then
        inst.components.armor:InitCondition(250, 1)
    elseif DURABILITYLIGHT == "300" then
        inst.components.armor:InitCondition(300, 1)
    elseif DURABILITYLIGHT == "350" then
        inst.components.armor:InitCondition(350, 1)
    end]]--
    inst:AddTag("metal")
    inst:AddTag("ruins")
    inst:AddComponent("equippable")
    inst.components.equippable:SetOnEquip(onequip)
    inst.components.equippable:SetOnUnequip(onunequip)
    inst:ListenForEvent("armorbroke", onbreak)
    
    inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(0)
    
    --inst:DoPeriodicTask(1, function() absorptionamount(inst, 1) end)
    inst.Light:SetIntensity(.75)
    inst.Light:SetColour(252 / 255, 251 / 255, 237 / 255)
    inst.Light:SetFalloff(.6)
    inst.Light:SetRadius(10)
    inst.Light:Enable(true)
    
	    return inst
end
return Prefab("common/inventory/lightshield", fn, assets, prefabs)

Edited by Silentdarkness1
Link to comment
Share on other sites

it seems event is never caught. I am not that familiar yet with the event system but could you try 

inst.components.inventoryitem.owner:ListenForEvent("armorbroke", onbreak)

instead of 

inst:ListenForEvent("armorbroke", onbreak)

 

Link to comment
Share on other sites

12 minutes ago, Ricoom said:

it seems event is never caught. I am not that familiar yet with the event system but could you try 


inst.components.inventoryitem.owner:ListenForEvent("armorbroke", onbreak)

instead of 


inst:ListenForEvent("armorbroke", onbreak)

 

[00:01:20]: [string "../mods/Shields - Unfinished/scripts/prefab..."]:104: attempt to index field 'owner' (a nil value) LUA ERROR stack traceback: ../mods/Shields - Unfinished/scripts/prefabs/lightshield.lua:104 in (field) fn (Lua) <48-118> scripts/mainfunctions.lua:206 in () ? (Lua) <195-237> =[C]:-1 in (method) SpawnPrefab (C) <-1--1> scripts/mainfunctions.lua:254 in (global) SpawnPrefab (Lua) <248-256> scripts/util.lua:24 in (global) DebugSpawn (Lua) <20-31> scripts/consolecommands.lua:365 in (global) c_give (Lua) <361-376> c_give("lightshield"):1 in () ? (main) <0-0> =[C]:-1 in (global) pcall (C) <-1--1> scripts/mainfunctions.lua:1409 in (global) ExecuteConsoleCommand (Lua) <1401-1418> scripts/screens/consolescreen.lua:146 in (method) Run (Lua) <133-148> scripts/screens/consolescreen.lua:159 in (field) fn (Lua) <157-164> scripts/scheduler.lua:177 in (method) OnTick (Lua) <155-207> scripts/scheduler.lua:371 in (global) RunScheduler (Lua) <369-377> scripts/update.lua:170 in () ? (Lua) <149-228>

We added this to the code....

inst:DoPeriodicTask(5, function() if inst.components.inventoryitem.owner ~= nil then inst.components.inventoryitem.owner:ListenForEvent("armorbroke", onbreak) end end)

 

And got this instead:

[00:01:58]: [string "../mods/Shields - Unfinished/scripts/prefab..."]:14: attempt to index field 'Transform' (a nil value) LUA ERROR stack traceback: ../mods/Shields - Unfinished/scripts/prefabs/lightshield.lua:14 in (local) fn (Lua) <13-17> scripts/entityscript.lua:1035 in (method) PushEvent (Lua) <1022-1049> scripts/components/armor.lua:7 in (local) fn (Lua) <1-10> scripts/entityscript.lua:1035 in (method) PushEvent (Lua) <1022-1049> scripts/components/armor.lua:77 in (method) SetCondition (Lua) <71-90> scripts/components/armor.lua:133 in (method) TakeDamage (Lua) <132-138> scripts/components/inventory.lua:285 in (method) ApplyDamage (Lua) <252-290> scripts/components/combat.lua:417 in (method) GetAttacked (Lua) <405-480> scripts/components/combat.lua:843 in (method) DoAttack (Lua) <793-867> scripts/stategraphs/SGhound.lua:72 in (field) fn (Lua) <72-72> scripts/stategraph.lua:568 in (method) UpdateState (Lua) <536-580> scripts/stategraph.lua:607 in (method) Update (Lua) <599-627> scripts/stategraph.lua:125 in (method) Update (Lua) <109-148> scripts/update.lua:218 in () ? (Lua) <149-228>

 

EDIT: We fixed it. Had to use inst instead of owner.

Edited by Silentdarkness1
Link to comment
Share on other sites

well one way would be to add the listener onequip and remove it on unequip try putting the listener inside onequip. its due to the fact that you are trying to listen for the owner event before the inventory item has owner and thats why its crashing. your way works as well but the error you get then is from the fact that 

owner.Transform 

does not exist as in that event owner is not passed directly it passes the armor component instance instead 

inst.components.inventoryitem.owner:PushEvent("armorbroke", { armor = inst })

you could try changing 

 local x,y,z = owner.Transform:GetWorldPosition()

 

to this 

 local x,y,z = inst.components.inventoryitem.owner.Transform:GetWorldPosition()

 

PS: using 

inst:DoPeriodicTask

is kinda bad as even the smallest task when done in loop will eat up conciderable amount of resources. I suggest looking into setting instance variable as eventlister onequip and removing it onunequip

Edited by Ricoom
Link to comment
Share on other sites

I cannot give much help in terms of code, but maybe you would like to go into Bernie and bone armor's files; both do what you are looking for (have health, but stay after it reaches 0), and the bone armor is even an armor (the prefab name is "armorskeleton" BTW).

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...