Amalleus Posted June 25, 2015 Share Posted June 25, 2015 Hello. I have issue with the custom food which i ported to DST. The issue is that spell doesn't work properly.DS code:local assets={Asset("ANIM", "anim/geralt_swallowpot.zip"),Asset("ATLAS", "images/inventoryimages/geralt_swallowpot.xml"), } local prefabs={ } local function item_oneaten(inst, eater) if eater.geralt_swallowpot then eater.geralt_swallowpot.components.spell.lifetime = 0 eater.geralt_swallowpot.components.spell:ResumeSpell() else local regen = SpawnPrefab("geralt_swallowpot_regen") regen.components.spell:SetTarget(eater) if not regen.components.spell.target then regen:Remove() end regen.components.spell:StartSpell() endend local function fn()local inst = CreateEntity()inst.entity:AddTransform()inst.entity:AddAnimState() inst.AnimState:SetBank("geralt_swallowpot") inst.AnimState:SetBuild("geralt_swallowpot") inst.AnimState:PlayAnimation("idle") MakeInventoryPhysics(inst) inst:AddComponent("inspectable") inst:AddComponent("stackable")inst.components.stackable.maxsize = TUNING.STACK_SIZE_LARGEITEM inst:AddComponent("inventoryitem")inst.components.inventoryitem.atlasname = "images/inventoryimages/geralt_swallowpot.xml" --inst:AddComponent("tradable") inst:AddComponent("edible") inst.components.edible.foodtype = "POTION" --inst.components.edible.healthvalue = 0 inst.components.edible.hungervalue = -TUNING.CALORIES_SMALL inst.components.edible.sanityvalue = 0 inst.components.edible:SetOnEatenFn(item_oneaten) return instend local function regen_resume(inst, time) local percent = time/inst.components.spell.duration local var = inst.components.spell.variablesGetPlayer().components.hunger.hungerrate = GetPlayer().components.hunger.hungerrate + GERALT_SWALLOWPOT_HUNGERRATE end local function regen_onsave(inst, data) data.timealive = inst:GetTimeAlive()end local function regen_onload(inst, data) if data and data.timealive then regen_resume(inst, data.timealive) endend local function regen_spellfn(inst, target)local player=GetPlayer()if target==playerthen player.components.health:DoDelta(GERALT_SWALLOWPOT_REGENRATE, false, "geralt_swallowpot", true) end;end local function regen_start(inst) GetPlayer().components.hunger.hungerrate = GetPlayer().components.hunger.hungerrate + GERALT_SWALLOWPOT_HUNGERRATE end local function regen_ontarget(inst, target) if not target then return end target.geralt_swallowpot = inst target:AddTag(inst.components.spell.spellname)end local function regen_onfinish(inst) if not inst.components.spell.target then return end inst.components.spell.target.geralt_swallowpot = nilGetPlayer().components.hunger.hungerrate = GetPlayer().components.hunger.hungerrate - GERALT_SWALLOWPOT_HUNGERRATE end local function regenfn() local inst = CreateEntity() inst.entity:AddTransform() inst:AddTag("FX") inst:AddTag("NOCLICK") local spell = inst:AddComponent("spell") inst.components.spell.spellname = "geralt_swallowpot"inst.components.spell.period = 1 inst.components.spell.duration = (30 * 2) inst.components.spell.ontargetfn = regen_ontarget inst.components.spell.onstartfn = regen_start inst.components.spell.onfinishfn = regen_onfinish inst.components.spell.fn = regen_spellfn inst.components.spell.resumefn = regen_resume inst.components.spell.removeonfinish = true return instend return Prefab( "common/inventory/geralt_swallowpot", fn, assets, prefabs),Prefab("common/inventory/geralt_swallowpot_regen", regenfn)DST code:local assets={ Asset("ANIM", "anim/geralt_swallowpot.zip"), Asset("ATLAS", "images/inventoryimages/geralt_swallowpot.xml"),}local prefabs={}local function item_oneaten(inst, eater) eater = ThePlayer if eater.geralt_swallowpot then eater.geralt_swallowpot.components.spell.lifetime = 0 eater.geralt_swallowpot.components.spell:ResumeSpell() else local regen = SpawnPrefab("geralt_swallowpot_regen") regen.components.spell:SetTarget(eater) if not regen.components.spell.target then regen:Remove() end regen.components.spell:StartSpell() endendlocal function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.AnimState:SetBank("geralt_swallowpot") inst.AnimState:SetBuild("geralt_swallowpot") inst.AnimState:PlayAnimation("idle") MakeInventoryPhysics(inst) inst:AddComponent("inspectable") inst:AddComponent("stackable") inst.components.stackable.maxsize = TUNING.STACK_SIZE_LARGEITEM inst:AddComponent("inventoryitem") inst.components.inventoryitem.atlasname = "images/inventoryimages/geralt_swallowpot.xml" --inst:AddComponent("tradable") inst:AddComponent("edible") inst.components.edible.foodtype = FOODTYPE.POTION --inst.components.edible.healthvalue = 0 inst.components.edible.hungervalue = -TUNING.CALORIES_SMALL inst.components.edible.sanityvalue = 0 inst.components.edible:SetOnEatenFn(item_oneaten) return instendlocal function regen_resume(inst, time) local percent = time/inst.components.spell.duration local var = inst.components.spell.variables inst:DoTaskInTime(0.2, function() ThePlayer.components.hunger.hungerrate = ThePlayer.components.hunger.hungerrate + GERALT_SWALLOWPOT_HUNGERRATE end)endlocal function regen_onsave(inst, data) data.timealive = inst:GetTimeAlive()endlocal function regen_onload(inst, data) if data and data.timealive then regen_resume(inst, data.timealive) endendlocal function regen_spellfn(inst, target) local player=ThePlayer if target==player then player.components.health:DoDelta(GERALT_SWALLOWPOT_REGENRATE, false, "geralt_swallowpot", true) end;end local function regen_start(inst) ThePlayer.components.hunger.hungerrate = ThePlayer.components.hunger.hungerrate + GERALT_SWALLOWPOT_HUNGERRATE endlocal function regen_ontarget(inst, target) if not target then return end target.geralt_swallowpot = inst target:AddTag(inst.components.spell.spellname) --target.AnimState:SetBloomEffectHandle("shaders/anim.ksh")endlocal function regen_onfinish(inst) if not inst.components.spell.target then return end inst.components.spell.target.geralt_swallowpot = nil ThePlayer.components.hunger.hungerrate = ThePlayer.components.hunger.hungerrate - GERALT_SWALLOWPOT_HUNGERRATE endlocal function regenfn() local inst = CreateEntity() inst.entity:AddTransform() inst:AddTag("FX") inst:AddTag("NOCLICK") local spell = inst:AddComponent("spell") inst.components.spell.spellname = "geralt_swallowpot" inst.components.spell.period = 1 inst.components.spell.duration = 60 inst.components.spell.ontargetfn = regen_ontarget inst.components.spell.onstartfn = regen_start inst.components.spell.onfinishfn = regen_onfinish inst.components.spell.fn = regen_spellfn inst.components.spell.resumefn = regen_resume inst.components.spell.removeonfinish = true return instendreturn Prefab( "common/inventory/geralt_swallowpot", fn, assets, prefabs),Prefab("common/inventory/geralt_swallowpot_regen", regenfn)So, what issue? look, food cast spell after i eat it. If i didn't go off game (DS or DST) during spell duration, issue will not appear - works correctly. But if i came off game during its duration in DST then after come online i get next thing : spell doesn't work (if it even had duration) at all. I found out that only one function worked - "regen_resume" after i came online. How to fix that issue, so spell will continue work after i came online again?P.S.: If you ask me why I did dotaskintime in regen_resume - this is because function starts before character was initialized (so i get nil on ThePlayer) Link to comment Share on other sites More sharing options...
rezecib Posted June 25, 2015 Share Posted June 25, 2015 eater = ThePlayer This isn't your problem while testing, but you shouldn't do this. It will always execute on the server and refer to the host player. Leave eater as is, it's already referring to a player (or maybe a mob that ate it off the ground). As for where the actual problem is, it's hard to tell. You're using a pretty strange setup-- making a prefab for the regen, and attaching components to a weird place on the player... If you're making the prefab for it, loading the regen back up on rejoining should be handled by that prefab, I guess, in an onsave/onload. Link to comment Share on other sites More sharing options...
Amalleus Posted June 25, 2015 Author Share Posted June 25, 2015 This isn't your problem while testing, but you shouldn't do this. It will always execute on the server and refer to the host player. Leave eater as is, it's already referring to a player (or maybe a mob that ate it off the ground). As for where the actual problem is, it's hard to tell. You're using a pretty strange setup-- making a prefab for the regen, and attaching components to a weird place on the player... If you're making the prefab for it, loading the regen back up on rejoining should be handled by that prefab, I guess, in an onsave/onload.i am using setup from wormlight.lua - i took everything from it and just modifiedcan you give a little more information about loading/saving? This really hard to read spell.lua about how it works Link to comment Share on other sites More sharing options...
Amalleus Posted June 26, 2015 Author Share Posted June 26, 2015 I know that i can try to repeat spell on loading but with lower time. so i need to repeat again function oneat. ofcourse i will need to add local variable which will have remaining time of spell. is it possible? Link to comment Share on other sites More sharing options...
Amalleus Posted June 26, 2015 Author Share Posted June 26, 2015 I found out that spell function is casted. But after re-logging to the game spell doesn't see the target of the spelllocal function regen_spellfn(inst, target) print("working!") if target then print("even with target") target.components.health:DoDelta(GERALT_SWALLOWPOT_REGENRATE, false, "geralt_swallowpot", true) endendbefore reloading it was: "working! even with target working! even with target..." after reloading: "working! working! ...." How to not lose target after reloading? Link to comment Share on other sites More sharing options...
DarkXero Posted June 26, 2015 Share Posted June 26, 2015 I'm not sure you should be using the spell component.Wormlight is the only prefab that uses it and it's not available on DST. You shouldn't be losing the target, on the LoadPostPass the target should be reassigned. In the meantime, maybe this could work?local assets = { Asset("ANIM", "anim/geralt_swallowpot.zip"), Asset("ATLAS", "images/inventoryimages/geralt_swallowpot.xml"),}local function item_oneaten(inst, eater) local regen = SpawnPrefab("geralt_swallowpot_regen") regen.components.spell:SetTarget(eater) regen.components.spell:StartSpell()end local function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddNetwork() MakeInventoryPhysics(inst) inst.AnimState:SetBank("geralt_swallowpot") inst.AnimState:SetBuild("geralt_swallowpot") inst.AnimState:PlayAnimation("idle") inst.entity:SetPristine() if not TheWorld.ismastersim then return inst end inst:AddComponent("edible") inst.components.edible.foodtype = FOODTYPE.POTION inst.components.edible.healthvalue = 0 inst.components.edible.hungervalue = -TUNING.CALORIES_SMALL inst.components.edible.sanityvalue = 0 inst.components.edible:SetOnEatenFn(item_oneaten) inst:AddComponent("inspectable") inst:AddComponent("inventoryitem") inst.components.inventoryitem.atlasname = "images/inventoryimages/geralt_swallowpot.xml" inst:AddComponent("stackable") inst.components.stackable.maxsize = TUNING.STACK_SIZE_LARGEITEM return instendlocal function regen_ontargetfn(spell, user) if not user:HasTag("playerghost") then user.components.hunger.hungerrate = user.components.hunger.hungerrate + GERALT_SWALLOWPOT_HUNGERRATE spell.components.spell.onfinishfn = function() user.components.hunger.hungerrate = user.components.hunger.hungerrate - GERALT_SWALLOWPOT_HUNGERRATE end endendlocal function regen_spellfn(spell, user) if not user.components.health:IsDead() then user.components.health:DoDelta(GERALT_SWALLOWPOT_REGENRATE, true, "geralt_swallowpot", true) else spell.components.spell:OnFinish() endendlocal function regenfn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddNetwork() inst:AddTag("FX") inst:AddTag("NOCLICK") inst.entity:SetPristine() if not TheWorld.ismastersim then return inst end inst:AddComponent("spell") inst.components.spell.spellname = "geralt_swallowpot" inst.components.spell.period = 1 inst.components.spell.duration = 60 inst.components.spell.ontargetfn = regen_ontargetfn inst.components.spell.removeonfinish = true inst.components.spell.fn = regen_spellfn return instend return Prefab("common/inventory/geralt_swallowpot", fn, assets), Prefab("common/inventory/geralt_swallowpot_regen", regenfn)I suggest that you look into something else, like directly applying the task into the eater or something. Link to comment Share on other sites More sharing options...
Amalleus Posted June 27, 2015 Author Share Posted June 27, 2015 (edited) Wormlight is the only prefab that uses it and it's not available on DST.yes, you are right. but i have several items (not only this item) which using "spell" - i don't want to lose effect after reloading. also i need functions OnStart OnFinish and SpellFunction to make some manipulationsAs i can see, OnStart and OnFinish is in the OnTarget function. Hm... you have pretty nice algorithmical thinking. I think this code will work. I will checkEDIT: there is no resume function. so after reloading spell just dissapears and that's it Edited June 27, 2015 by Amalleus Link to comment Share on other sites More sharing options...
Amalleus Posted June 27, 2015 Author Share Posted June 27, 2015 (edited) eater = ThePlayer This isn't your problem while testing, but you shouldn't do this. It will always execute on the server and refer to the host player. Leave eater as is, it's already referring to a player (or maybe a mob that ate it off the ground).Am i right that ThePlayer - is always the host player and not the current? But what about choose somebody else? And sorry, I just started to understand DST programming =/ Edited June 27, 2015 by Amalleus Link to comment Share on other sites More sharing options...
rezecib Posted June 27, 2015 Share Posted June 27, 2015 Am i right that ThePlayer - is always the host player and not the current? Not always-- it depends on where the code is running. Some places where it will always be the host player (or nil on a dedicated server-- watch out for that):Most components (especially ones that are game logic, like health, as opposed to display-related, like transparentonsanity)Any code that comes after a "if not TheWorld.ismastersim then return end" block-- this includes master_postinitFunctions for character traits that manipulate game logic (they're usually attached to components)Places where it code will run on all computers and ThePlayer will refer to the local one:Display elements-- HUD widgets, etcreplicas (these are copies of certain game logic components that also need to handle some display, like health needs to be accessed on clients to show how much health players have)anything before "if not TheWorld.ismastersim then return end" block -- this includes common_postinitHowever, in virtually all cases there's a better way to get the relevant player. For example, almost all component functions have the player or entity that's interacting with something as one of the arguments (e.g. "eater" in several edible component functions, or self.inst/self.owner in most components that are attached to players, and self.owner in widgets). Link to comment Share on other sites More sharing options...
DarkXero Posted June 28, 2015 Share Posted June 28, 2015 @Amalleus, The spell component is a challenge, I think. I don't know how Klei will make it work. My solution to make the spell component work is the following: a) Put this in modmain.luaAddPrefabPostInitAny(function(inst) local target = inst local old3 = target.OnLoad target.OnLoad = function(inst, data) if old3 then old3(inst, data) end if data then for k, v in pairs(data) do if string.match(k, "Spell_..") then local s = string.gsub(k, "Spell_", "") local spell = GLOBAL.SpawnSaveRecord(data[s]) local spellcomp = spell.components.spell spellcomp:SetTarget(inst) if spellcomp.active then spellcomp:ResumeSpell() end end end end endend)b) Use my attached spell component This should make the target stay.Up to you to continue editing your potion based on wormlight.spell.lua Link to comment Share on other sites More sharing options...
Amalleus Posted June 28, 2015 Author Share Posted June 28, 2015 (edited) @Amalleus, The spell component is a challenge, I think. I don't know how Klei will make it work. My solution to make the spell component work is the following: a) Put this in modmain.luaAddPrefabPostInitAny(function(inst) local target = inst local old3 = target.OnLoad target.OnLoad = function(inst, data) if old3 then old3(inst, data) end if data then for k, v in pairs(data) do if string.match(k, "Spell_..") then local s = string.gsub(k, "Spell_", "") local spell = GLOBAL.SpawnSaveRecord(data[s]) local spellcomp = spell.components.spell spellcomp:SetTarget(inst) if spellcomp.active then spellcomp:ResumeSpell() end end end end endend)b) Use my attached spell component This should make the target stay.Up to you to continue editing your potion based on wormlight.Thank you for help. Yesterday i thought about save/load functions, and i found solution without spells.First of all, the potion is possible to use by certain character. So, oneat function of potion i added eater.potionresttime = 60--+ more hunger lossand in character inst i added:inst:DoPeriodicTask...... --every 1 second restores health and decreases inst.potionresttime by 1 --when inst.potionresttime == 0 then return previous hungerrate and stop decreasing of variablesave/load functions loading and saving potionresttime Edited June 28, 2015 by Amalleus Link to comment 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