Erquint Posted June 8, 2014 Share Posted June 8, 2014 (edited) I have some experience with coding but always sucked at modding.Would appreciate any help very much. So the ultimate goal of the simple mod I wanna make as a first one to take a grasp on DS modding is:1. Make trees drop branches when chopped down.2. Remove fake saplings from the game completely. (I say "fake" because they never grow into trees)3. Have the mod only affect the things mentioned so that it is somewhat version-independent and non-conflicting with other mods. So far I achieved the first goal and with evergreens only. modinfo.luaname = "BranchTwigs"description = "Lets you harvest branches from Evergreens as Twigs"author = "Erquint"version = "0.1"-- forumthread = ""api_version = 6-- icon_atlas = ""-- icon = ""-- priority = dont_starve_compatible = truereign_of_giants_compatible = true scripts\prefabs\evergreens.lualocal assets ={ Asset("ANIM", "anim/evergreen_new.zip"), --build Asset("ANIM", "anim/evergreen_new_2.zip"), --build Asset("ANIM", "anim/evergreen_tall_old.zip"), Asset("ANIM", "anim/evergreen_short_normal.zip"), Asset("ANIM", "anim/dust_fx.zip"), Asset("SOUND", "sound/forest.fsb"),}local prefabs ={ "log", "twigs", "pinecone", "charcoal", "leif", "leif_sparse", "pine_needles"}local builds = { normal = { file="evergreen_new", prefab_name="evergreen", normal_loot = {"log", "log", "pinecone", "twigs", "twigs"}, short_loot = {"log", "twigs"}, tall_loot = {"log", "log", "log", "pinecone", "pinecone", "twigs", "twigs", "twigs"}, drop_pinecones=true, leif="leif", }, sparse = { file="evergreen_new_2", prefab_name="evergreen_sparse", normal_loot = {"log","log", "twigs", "twigs"}, short_loot = {"log", "twigs"}, tall_loot = {"log", "log","log", "twigs", "twigs", "twigs"}, drop_pinecones=false, leif="leif_sparse", },}local function makeanims(stage) return { idle="idle_"..stage, sway1="sway1_loop_"..stage, sway2="sway2_loop_"..stage, chop="chop_"..stage, fallleft="fallleft_"..stage, fallright="fallright_"..stage, stump="stump_"..stage, burning="burning_loop_"..stage, burnt="burnt_"..stage, chop_burnt="chop_burnt_"..stage, idle_chop_burnt="idle_chop_burnt_"..stage }endlocal short_anims = makeanims("short")local tall_anims = makeanims("tall")local normal_anims = makeanims("normal")local old_anims ={ idle="idle_old", sway1="idle_old", sway2="idle_old", chop="chop_old", fallleft="chop_old", fallright="chop_old", stump="stump_old", burning="idle_olds", burnt="burnt_tall", chop_burnt="chop_burnt_tall", idle_chop_burnt="idle_chop_burnt_tall",}local function dig_up_stump(inst, chopper) inst:Remove() inst.components.lootdropper:SpawnLootPrefab("log")endlocal function chop_down_burnt_tree(inst, chopper) inst:RemoveComponent("workable") inst.SoundEmitter:PlaySound("dontstarve/forest/treeCrumble") inst.SoundEmitter:PlaySound("dontstarve/wilson/use_axe_tree") inst.AnimState:PlayAnimation(inst.anims.chop_burnt) RemovePhysicsColliders(inst) inst:ListenForEvent("animover", function() inst:Remove() end) inst.components.lootdropper:SpawnLootPrefab("charcoal") inst.components.lootdropper:DropLoot() if inst.pineconetask then inst.pineconetask:Cancel() inst.pineconetask = nil endendlocal function GetBuild(inst) local build = builds[inst.build] if build == nil then return builds["normal"] end return buildendlocal burnt_highlight_override = {.5,.5,.5}local function OnBurnt(inst, imm) local function changes() if inst.components.burnable then inst.components.burnable:Extinguish() end inst:RemoveComponent("burnable") inst:RemoveComponent("propagator") inst:RemoveComponent("growable") inst.components.lootdropper:SetLoot({}) if GetBuild(inst).drop_pinecones then inst.components.lootdropper:AddChanceLoot("pinecone", 0.1) end if inst.components.workable then inst.components.workable:SetWorkLeft(1) inst.components.workable:SetOnWorkCallback(nil) inst.components.workable:SetOnFinishCallback(chop_down_burnt_tree) end end if imm then changes() else inst:DoTaskInTime( 0.5, changes) end inst.AnimState:PlayAnimation(inst.anims.burnt, true) inst.AnimState:SetRayTestOnBB(true); inst:AddTag("burnt") inst.highlight_override = burnt_highlight_overrideendlocal function PushSway(inst) if math.random() > .5 then inst.AnimState:PushAnimation(inst.anims.sway1, true) else inst.AnimState:PushAnimation(inst.anims.sway2, true) endendlocal function Sway(inst) if math.random() > .5 then inst.AnimState:PlayAnimation(inst.anims.sway1, true) else inst.AnimState:PlayAnimation(inst.anims.sway2, true) endendlocal function SetShort(inst) inst.anims = short_anims if inst.components.workable then inst.components.workable:SetWorkLeft(TUNING.EVERGREEN_CHOPS_SMALL) end inst.components.lootdropper:SetLoot(GetBuild(inst).short_loot) Sway(inst)endlocal function GrowShort(inst) inst.AnimState:PlayAnimation("grow_old_to_short") inst.SoundEmitter:PlaySound("dontstarve/forest/treeGrowFromWilt") PushSway(inst)endlocal function SetNormal(inst) inst.anims = normal_anims if inst.components.workable then inst.components.workable:SetWorkLeft(TUNING.EVERGREEN_CHOPS_NORMAL) end inst.components.lootdropper:SetLoot(GetBuild(inst).normal_loot) Sway(inst)endlocal function GrowNormal(inst) inst.AnimState:PlayAnimation("grow_short_to_normal") inst.SoundEmitter:PlaySound("dontstarve/forest/treeGrow") PushSway(inst)endlocal function SetTall(inst) inst.anims = tall_anims if inst.components.workable then inst.components.workable:SetWorkLeft(TUNING.EVERGREEN_CHOPS_TALL) end inst.components.lootdropper:SetLoot(GetBuild(inst).tall_loot) Sway(inst)endlocal function GrowTall(inst) inst.AnimState:PlayAnimation("grow_normal_to_tall") inst.SoundEmitter:PlaySound("dontstarve/forest/treeGrow") PushSway(inst)endlocal function SetOld(inst) inst.anims = old_anims if inst.components.workable then inst.components.workable:SetWorkLeft(1) end if GetBuild(inst).drop_pinecones then inst.components.lootdropper:SetLoot({"pinecone"}) else inst.components.lootdropper:SetLoot({}) end Sway(inst)endlocal function GrowOld(inst) inst.AnimState:PlayAnimation("grow_tall_to_old") inst.SoundEmitter:PlaySound("dontstarve/forest/treeWilt") PushSway(inst)endlocal function inspect_tree(inst) if inst:HasTag("burnt") then return "BURNT" elseif inst:HasTag("stump") then return "CHOPPED" endendlocal growth_stages ={ {name="short", time = function(inst) return GetRandomWithVariance(TUNING.EVERGREEN_GROW_TIME[1].base, TUNING.EVERGREEN_GROW_TIME[1].random) end, fn = function(inst) SetShort(inst) end, growfn = function(inst) GrowShort(inst) end , leifscale=.7 }, {name="normal", time = function(inst) return GetRandomWithVariance(TUNING.EVERGREEN_GROW_TIME[2].base, TUNING.EVERGREEN_GROW_TIME[2].random) end, fn = function(inst) SetNormal(inst) end, growfn = function(inst) GrowNormal(inst) end, leifscale=1 }, {name="tall", time = function(inst) return GetRandomWithVariance(TUNING.EVERGREEN_GROW_TIME[3].base, TUNING.EVERGREEN_GROW_TIME[3].random) end, fn = function(inst) SetTall(inst) end, growfn = function(inst) GrowTall(inst) end, leifscale=1.25 }, {name="old", time = function(inst) return GetRandomWithVariance(TUNING.EVERGREEN_GROW_TIME[4].base, TUNING.EVERGREEN_GROW_TIME[4].random) end, fn = function(inst) SetOld(inst) end, growfn = function(inst) GrowOld(inst) end },}local function chop_tree(inst, chopper, chops) if chopper and chopper.components.beaverness and chopper.components.beaverness:IsBeaver() then inst.SoundEmitter:PlaySound("dontstarve/characters/woodie/beaver_chop_tree") else inst.SoundEmitter:PlaySound("dontstarve/wilson/use_axe_tree") end local fx = SpawnPrefab("pine_needles") local x, y, z= inst.Transform:GetWorldPosition() fx.Transform:SetPosition(x,y + math.random()*2,z) inst.AnimState:PlayAnimation(inst.anims.chop) inst.AnimState:PushAnimation(inst.anims.sway1, true) --tell any nearby leifs to wake up local pt = Vector3(inst.Transform:GetWorldPosition()) local ents = TheSim:FindEntities(pt.x,pt.y,pt.z, TUNING.LEIF_REAWAKEN_RADIUS, {"leif"}) for k,v in pairs(ents) do if v.components.sleeper and v.components.sleeper:IsAsleep() then v:DoTaskInTime(math.random(), function() v.components.sleeper:WakeUp() end) end v.components.combat:SuggestTarget(chopper) endendlocal function chop_down_tree(inst, chopper) inst:RemoveComponent("burnable") MakeSmallBurnable(inst) inst:RemoveComponent("propagator") MakeSmallPropagator(inst) inst:RemoveComponent("workable") inst.SoundEmitter:PlaySound("dontstarve/forest/treefall") local pt = Vector3(inst.Transform:GetWorldPosition()) local hispos = Vector3(chopper.Transform:GetWorldPosition()) local he_right = (hispos - pt):Dot(TheCamera:GetRightVec()) > 0 if he_right then inst.AnimState:PlayAnimation(inst.anims.fallleft) inst.components.lootdropper:DropLoot(pt - TheCamera:GetRightVec()) else inst.AnimState:PlayAnimation(inst.anims.fallright) inst.components.lootdropper:DropLoot(pt + TheCamera:GetRightVec()) end inst:DoTaskInTime(.4, function() local sz = (inst.components.growable and inst.components.growable.stage > 2) and .5 or .25 GetPlayer().components.playercontroller:ShakeCamera(inst, "FULL", 0.25, 0.03, sz, 6) end) RemovePhysicsColliders(inst) inst.AnimState:PushAnimation(inst.anims.stump) inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.DIG) inst.components.workable:SetOnFinishCallback(dig_up_stump) inst.components.workable:SetWorkLeft(1) inst:AddTag("stump") if inst.components.growable then inst.components.growable:StopGrowing() end inst:AddTag("NOCLICK") inst:DoTaskInTime(2, function() inst:RemoveTag("NOCLICK") end) local days_survived = GetClock().numcycles if days_survived >= TUNING.LEIF_MIN_DAY then if math.random() <= TUNING.LEIF_PERCENT_CHANCE then local numleifs = 1 if days_survived > 30 then numleifs = math.random(2) elseif days_survived > 80 then numleifs = math.random(3) end for k = 1,numleifs do local target = FindEntity(inst, TUNING.LEIF_MAXSPAWNDIST, function(item) if item.components.growable and item.components.growable.stage <= 3 then return item:HasTag("tree") and (not item:HasTag("stump")) and (not item:HasTag("burnt")) and not item.noleif end return false end) if target then target.noleif = true target.leifscale = growth_stages[target.components.growable.stage].leifscale or 1 target:DoTaskInTime(1 + math.random()*3, function() if target then local target = target local leif = SpawnPrefab(builds[target.build].leif) local scale = target.leifscale local r,g,b,a = target.AnimState:GetMultColour() leif.AnimState:SetMultColour(r,g,b,a) --we should serialize this? leif.components.locomotor.walkspeed = leif.components.locomotor.walkspeed*scale leif.components.combat.defaultdamage = leif.components.combat.defaultdamage*scale leif.components.health.maxhealth = leif.components.health.maxhealth*scale leif.components.health.currenthealth = leif.components.health.currenthealth*scale leif.components.combat.hitrange = leif.components.combat.hitrange*scale leif.components.combat.attackrange = leif.components.combat.attackrange*scale leif.Transform:SetScale(scale,scale,scale) leif.components.combat:SuggestTarget(chopper) leif.sg:GoToState("spawn") target:Remove() leif.Transform:SetPosition(target.Transform:GetWorldPosition()) end end) end end end endendlocal function tree_burnt(inst) OnBurnt(inst) inst.pineconetask = inst:DoTaskInTime(10, function() local pt = Vector3(inst.Transform:GetWorldPosition()) if math.random(0, 1) == 1 then pt = pt + TheCamera:GetRightVec() else pt = pt - TheCamera:GetRightVec() end inst.components.lootdropper:DropLoot(pt) inst.pineconetask = nil end)endlocal function handler_growfromseed (inst) inst.components.growable:SetStage(1) inst.AnimState:PlayAnimation("grow_seed_to_short") inst.SoundEmitter:PlaySound("dontstarve/forest/treeGrow") PushSway(inst)endlocal function onsave(inst, data) if inst:HasTag("burnt") or inst:HasTag("fire") then data.burnt = true end if inst:HasTag("stump") then data.stump = true end if inst.build ~= "normal" then data.build = inst.build endend local function onload(inst, data) if data then if not data.build or builds[data.build] == nil then inst.build = "normal" else inst.build = data.build end if data.burnt then OnBurnt(inst, true) elseif data.stump then inst:RemoveComponent("burnable") MakeSmallBurnable(inst) inst:RemoveComponent("workable") inst:RemoveComponent("propagator") MakeSmallPropagator(inst) inst:RemoveComponent("growable") RemovePhysicsColliders(inst) inst.AnimState:PlayAnimation(inst.anims.stump) inst:AddTag("stump") inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.DIG) inst.components.workable:SetOnFinishCallback(dig_up_stump) inst.components.workable:SetWorkLeft(1) end endend local function OnEntitySleep(inst) inst:RemoveComponent("burnable") inst:RemoveComponent("propagator") inst:RemoveComponent("inspectable")endlocal function OnEntityWake(inst) if not inst:HasTag("burnt") and not inst:HasTag("fire") then if not inst.components.burnable then if inst:HasTag("stump") then MakeSmallBurnable(inst) else MakeLargeBurnable(inst) inst.components.burnable:SetFXLevel(5) inst.components.burnable:SetOnBurntFn(tree_burnt) end end if not inst.components.propagator then if inst:HasTag("stump") then MakeSmallPropagator(inst) else MakeLargePropagator(inst) end end end if not inst.components.inspectable then inst:AddComponent("inspectable") inst.components.inspectable.getstatus = inspect_tree endendlocal function makefn(build, stage, data) local function fn(Sim) local l_stage = stage if l_stage == 0 then l_stage = math.random(1,3) end local inst = CreateEntity() local trans = inst.entity:AddTransform() local anim = inst.entity:AddAnimState() local sound = inst.entity:AddSoundEmitter() MakeObstaclePhysics(inst, .25) local minimap = inst.entity:AddMiniMapEntity() if build == "normal" then minimap:SetIcon("evergreen.png") elseif build == "sparse" then minimap:SetIcon("evergreen_lumpy.png") end minimap:SetPriority(-1) inst:AddTag("tree") inst:AddTag("workable") inst.build = build anim:SetBuild(GetBuild(inst).file) anim:SetBank("evergreen_short") local color = 0.5 + math.random() * 0.5 anim:SetMultColour(color, color, color, 1) ------------------- MakeLargeBurnable(inst) inst.components.burnable:SetFXLevel(5) inst.components.burnable:SetOnBurntFn(tree_burnt) MakeLargePropagator(inst) ------------------- inst:AddComponent("inspectable") inst.components.inspectable.getstatus = inspect_tree ------------------- inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.CHOP) inst.components.workable:SetOnWorkCallback(chop_tree) inst.components.workable:SetOnFinishCallback(chop_down_tree) ------------------- inst:AddComponent("lootdropper") --------------------- --------------------- inst:AddComponent("growable") inst.components.growable.stages = growth_stages inst.components.growable:SetStage(l_stage) inst.components.growable.loopstages = true inst.components.growable:StartGrowing() inst.growfromseed = handler_growfromseed --------------------- --PushSway(inst) inst.AnimState:SetTime(math.random()*2) --------------------- inst.OnSave = onsave inst.OnLoad = onload MakeSnowCovered(inst, .01) --------------------- inst:SetPrefabName( GetBuild(inst).prefab_name ) if data =="burnt" then OnBurnt(inst) end if data =="stump" then inst:RemoveComponent("burnable") MakeSmallBurnable(inst) inst:RemoveComponent("workable") inst:RemoveComponent("propagator") MakeSmallPropagator(inst) inst:RemoveComponent("growable") RemovePhysicsColliders(inst) inst.AnimState:PlayAnimation(inst.anims.stump) inst:AddTag("stump") inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.DIG) inst.components.workable:SetOnFinishCallback(dig_up_stump) inst.components.workable:SetWorkLeft(1) end inst.OnEntitySleep = OnEntitySleep inst.OnEntityWake = OnEntityWake return inst end return fnend local function tree(name, build, stage, data) return Prefab("forest/objects/trees/"..name, makefn(build, stage, data), assets, prefabs)endreturn tree("evergreen", "normal", 0), tree("evergreen_normal", "normal", 2), tree("evergreen_tall", "normal", 3), tree("evergreen_short", "normal", 1), tree("evergreen_sparse", "sparse", 0), tree("evergreen_sparse_normal", "sparse", 2), tree("evergreen_sparse_tall", "sparse", 3), tree("evergreen_sparse_short", "sparse", 1), tree("evergreen_burnt", "normal", 0, "burnt"), tree("evergreen_stump", "normal", 0, "stump") I'd like to somehow make it all work through modmain.lua without overriding any existing files.But how do I get and set variables from different parts of the game logics?I've dozens of tabs open in my browser of all the forum pages and stuff but can't find a sensible documentation.It's always either a specific example that is creating something new or, even worse, art guides.....tons of them... Now how do I get rid of saplings? (Sorry for multipost. The editing function wasn't forking for some reason. Now that it does, I will not multipost anymore.) Edited June 8, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/ Share on other sites More sharing options...
Erquint Posted June 8, 2014 Author Share Posted June 8, 2014 (edited) del Edited June 8, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496294 Share on other sites More sharing options...
Erquint Posted June 8, 2014 Author Share Posted June 8, 2014 (edited) del Edited June 8, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496296 Share on other sites More sharing options...
Erquint Posted June 8, 2014 Author Share Posted June 8, 2014 (edited) del Edited June 8, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496298 Share on other sites More sharing options...
Erquint Posted June 8, 2014 Author Share Posted June 8, 2014 (edited) del Edited June 8, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496304 Share on other sites More sharing options...
orian34 Posted June 8, 2014 Share Posted June 8, 2014 i think the world gen has to be modified Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496319 Share on other sites More sharing options...
Erquint Posted June 8, 2014 Author Share Posted June 8, 2014 (edited) i think the world gen has to be modifiedHow?If You know of any competent documentation — kick a link to it in my general direction. Managed to make the sapling be unpickable for starters:entity.components.pickable.canbepicked = falseThe topology of the fields and functions seems opaque as there is no documentation. The simplest things take ages to figure out blindly by poking around.How do people make mods for the engine that has no class reference? There should be one Klei released somewhere...Why do I have to reverse-engineer the game to get this list of AnimState functions for example?SetLayerSetRayTestOnBBSetFinalOffsetSetManualBBSetOrientationGetSymbolPositionHideSetSortOrderClearOverrideSymbolSetBloomEffectHandleSetDepthWriteEnabledSetDepthTestEnabledShowPlayAnimationSetTimePauseResumeSetDeltaTimeMultiplierPushAnimationGetMultColourOverrideSymbolSetPercentSetAddColourClearBloomEffectHandleSetScaleSetBankPutOnGroundSetBuildGetCurrentFacingSetErosionParamsGetAddColourLoadAnimationSetLightOverrideSetDepthBiasAnimDoneSetMultColourThis and all the functions, classes, fields and tables should be in the documentation, especially the C++ part which is at the footstone of the whole game yet is closed. How do I make all saplings invisible?Is there a blank animation I can make it play?If I nil out the animations straight ahead — the engine cries for an animation to play and crashes.Tried different things, none seemed to work as I don't even know what are the fields a variable has. Edited June 8, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496331 Share on other sites More sharing options...
DevilXD Posted June 8, 2014 Share Posted June 8, 2014 If you want to make something invisible, use inst:Hide() and inst:Show() respectively... Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496637 Share on other sites More sharing options...
Erquint Posted June 9, 2014 Author Share Posted June 9, 2014 (edited) Not much people answered and fiddling with hooks was too much of a hassle to take after 2 days of banging my head against it.With the current state of documentation which I have already ranted enough about I decided to make it the old gritty way of overriding files.Made a working RoG mod that way but will look into converting it into a modmain.lua API hook-based mod later. Also why isn't there a way to make a mod that supports both modes by having the mod be split up into 2-in-1 kinda thing?For example, even when I have the mod API set to 6 and compatible with both modes arranged like thisModName -modinfo.lua -DLC001 -scripts -... -scripts -... The DLC001 part gets completely ignored by game and the mod menu gets freaked out for no reason. (Where There's a Wilson... rev.102572) API 6 also gives a "Crashed" and then "To be disabled" messages without actually crashing and disabling. API 5 works great but shows out-of-date message. I'd like to make it compatible with both vanilla and RoG even if I'd have to include twice the files with one set loading for vanilla and another one for RoG. Will test and hotfix the mod for some time and post it then. Also tried both Matt's Klei tool and Github tools to make modicon.tex but none proved working, whatever then, who needs an icon(sarcasm?). Edited June 9, 2014 by Erquint Link to comment https://forums.kleientertainment.com/forums/topic/37251-newbie-questions/#findComment-496811 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