Inward Posted April 13, 2014 Share Posted April 13, 2014 Hi Don't Starve modders, I keep coding a mod with a friend and we have an idea for a custom character.He will be able to craft a special item (like Wigfrid with her helmet and spear). But the action of this item is a bit special and nothing similar exist in the game.I need to create something which will heal all the stats (hunger, sanity and health), just like the healing salve does. But I can't use a "healer" component because we can only set the health amount. So I decided to create my own component and my own action. First the item : item.lualocal function fn(Sim) local inst = CreateEntity() local trans = inst.entity:AddTransform() local anim = inst.entity:AddAnimState() MakeInventoryPhysics(inst) inst.AnimState:SetBank("spider_gland_salve") inst.AnimState:SetBuild("myitem") inst.AnimState:PlayAnimation("idle") inst:AddComponent("stackable") inst.components.stackable.maxsize = TUNING.STACK_SIZE_SMALLITEM inst:AddComponent("inspectable") inst:AddComponent("inventoryitem") inst.components.inventoryitem.atlasname = "images/inventoryimages/myitem.xml" inst:AddComponent("characterspecific") inst.components.characterspecific:SetOwner("mycharacter") inst:AddComponent("mycomponent") inst.components.smokable:SetAmounts(-5, -5, 2) return instendMy custom component :local MyComponent = Class(function(self, inst) self.inst = inst self.hunger = 0 self.sanity = 0 self.health = 0end)function MyComponent:SetAmounts(hunger, sanity, health) self.hunger = hunger self.sanity = sanity self.health = healthendfunction MyComponent:CollectInventoryActions(doer, actions) if doer.components.hunger and doer.components.sanity and doer.components.health then table.insert(actions, ACTIONS.USE) endendfunction MyComponent:Use(target) if target.components.hunger and target.components.sanity and target.components.health then target.components.hunger:DoDelta(self.hunger) target.components.sanity:DoDelta(self.sanity) target.components.health:DoDelta(self.health,false,self.inst.prefab) if self.inst.components.stackable and self.inst.components.stackable.stacksize > 1 then self.inst.components.stackable:Get():Remove() else self.inst:Remove() end return true endendfunction MyComponent:CollectUseActions(doer, target, actions) if target.components.health and target.components.hunger and target.components.sanity then table.insert(actions, ACTIONS.USE) endendreturn MyComponentAnd in modmain.lua I created my custom action (named "USE") :local require = GLOBAL.require--require "class"require "bufferedaction"local STRINGS = GLOBAL.STRINGSlocal ACTIONS = GLOBAL.ACTIONSlocal Action = GLOBAL.Actionlocal USE = Action()USE.id = "USE"USE.str = "Use"USE.fn = function(act) if act.invobject and act.invobject.components.mycomponent then local target = act.target or act.doer return act.invobject.components.mycomponent:Use(target) endend AddAction(USE) GLOBAL.ACTIONS.USE = USEI have my item in my stuff, i can see that a right click does the "use" action, but when i click on it, nothing happen. If I use :local USE = Action(1, true)instead, I can use my item but there is no animation like a healing salve would do. Sorry for the long post and maybe grammar errors (I'm not an english native speaker).I'm still looking for a solution but I have no more ideas... Thanks in advance, Inward Link to comment https://forums.kleientertainment.com/forums/topic/34810-creating-a-custom-action-for-a-custom-item/ Share on other sites More sharing options...
squeek Posted April 13, 2014 Share Posted April 13, 2014 (edited) You're not adding an action handler to the character's stategraph. local ActionHandler = GLOBAL.ActionHandlerAddStategraphActionHandler("wilson", ActionHandler(USE, "dolongaction"))As an aside, you're putting prefab-specific code inside a component, which makes the component much less robust (see the reason that you have to make your own component in the first place; Klei's "healer" component is not great, they should have made a generic component and used callbacks to do the healing [there is "useableitem" but it's not flexible enough either, it's written to handle variable length uses]).I'd suggest making a component something like:local GenericUseableItem = Class(function(self, inst) self.inst = inst self.onusefn = nil self.canusefn = nil self.validtargetfn = nil self.action = ACTIONS.USEend)function GenericUseableItem:Use(target, doer) if self.onusefn then self.onusefn(self.inst, target, doer) endendfunction GenericUseableItem:CanBeUsedBy(doer) if self.canusefn then self.canusefn(self.inst, doer) else return true endendfunction GenericUseableItem:CanBeUsedOn(target, doer) if not self:CanBeUsedBy(doer) then return false elseif self.validtargetfn then return self.validtargetfn(self.inst, target, doer) else return true endend-- for targeting somethingfunction GenericUseableItem:CollectUseActions(doer, target, actions) if self:CanBeUsedOn(target, doer) then table.insert(actions, self.action) endend-- for using while in an inventoryfunction GenericUseableItem:CollectInventoryActions(doer, actions) if self:CanBeUsedBy(doer) then table.insert(actions, self.action) endend return GenericUseableItemthen the prefab-specific code would all go in your prefab file and the component would be useful for more things than just healing health/sanity/hunger at once.Example usage:--in your prefab filelocal function canbeused(inst, target, doer) return target and target.components.health and target.components.hunger and target.components.sanityendlocal function onused(inst, target, doer) if canbeused(inst, target, doer) then target.components.hunger:DoDelta(-5) target.components.sanity:DoDelta(-5) target.components.health:DoDelta(2,false,inst.prefab) if inst.components.stackable and inst.components.stackable.stacksize > 1 then inst.components.stackable:Get():Remove() else inst:Remove() end return true endend-- in the prefab's fn function inst:AddComponent("genericuseableitem") inst.components.genericuseableitem.canusefn = canbeused inst.components.genericuseableitem.validtargetfn = canbeused inst.components.genericuseableitem.onusefn = onusedI'd also probably stay away from the action id "USE" because it seems extremely likely to be implemented either by the game or by other mods in the future which will cause conflicts (one overwriting the other). Could prefix it with your mod name or something like that just to make sure it won't step on anything in the future. Edited April 13, 2014 by squeek Link to comment https://forums.kleientertainment.com/forums/topic/34810-creating-a-custom-action-for-a-custom-item/#findComment-452800 Share on other sites More sharing options...
simplex Posted April 13, 2014 Share Posted April 13, 2014 (edited) awesome tips I couldn't have said it better. Edited April 13, 2014 by simplex Link to comment https://forums.kleientertainment.com/forums/topic/34810-creating-a-custom-action-for-a-custom-item/#findComment-452813 Share on other sites More sharing options...
Inward Posted April 14, 2014 Author Share Posted April 14, 2014 Thanks a lot squeek ! It really helped me to understand how Don't Starve classes work. Bye and have fun on this amazing game ! Link to comment https://forums.kleientertainment.com/forums/topic/34810-creating-a-custom-action-for-a-custom-item/#findComment-453469 Share on other sites More sharing options...
Inward Posted April 15, 2014 Author Share Posted April 15, 2014 Hi everyone,I have a last problem for my character and I just can't find a solution... I would like to increase the difficulty of the Don't Starve experience by losing health when the sanity is 0, like when the hunger is 0.I already created a function for the "sanitydelta" event :local function onsanitychange(inst, data) local sanity = inst.components.sanity.current local bonus = 100 - sanity inst.components.combat.min_attack_period = TUNING.WILSON_ATTACK_PERIOD / (1 + (bonus / 100)) inst.components.locomotor.walkspeed = (TUNING.WILSON_WALK_SPEED * (1 + ((bonus/3) / 100) )) inst.components.locomotor.runspeed = (TUNING.WILSON_RUN_SPEED * (1 + ((bonus/3) / 100))) if sanity <= 0 then --lose health per second elseif sanity > 0 then --cancel the health loss endendlocal fn = function(inst) inst:ListenForEvent("sanitydelta", onsanitychange) end I don't know how to replace the comments on this code, or if I should do it here.Maybe I could create a tag on my character, then override the Sanity:OnUpdate(dt) function and create a Sanity:IsLosingMind() (or something like this), override the HealthBadge:OnUpdate(dt) function (to display the arrow when losing health) and check with the tag with that's my character or not. I tried all day but I couldn't find a good result. If someone could help me for this, it would be awsome. Thanks in advance, Inward Link to comment https://forums.kleientertainment.com/forums/topic/34810-creating-a-custom-action-for-a-custom-item/#findComment-454534 Share on other sites More sharing options...
squeek Posted April 15, 2014 Share Posted April 15, 2014 You'll want to use inst:DoPeriodicTask. Search the Don't Starve scripts for examples of how it's used. Link to comment https://forums.kleientertainment.com/forums/topic/34810-creating-a-custom-action-for-a-custom-item/#findComment-454673 Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now