Archived

This topic is now archived and is closed to further replies.

Ipsquiggle

Aug 20Th Update Modding Discussion / Workshop Beta

66 posts in this topic

There are two big updates to mods this release: Steam Workshop support, and filling out the modding API.


Workshop Support

Modders will be able to upload their mods to Steam Workshop using our custom tool, and then other players can get the mod installed with one click! Instructions for getting the tool are available in this post!

API Additions and Improvements

The API version has been updated to 3! Please test your mods with the preview. When you mod has been updated to work with this version (or if it already works!), then set api_version = 3 in your modinfo.

The Modding API has a bunch of new additions. You can check out the API Examples mod for documentation and examples, but here are the new functions:
 

    [*]AddLevel [*]AddLevelPreInit [*]AddLevelPreInitAny [*]AddTask [*]AddTaskPreInit [*]AddRoom [*]AddRoomPreInit [*]AddRecipe (for crafting recipes) [*]Ingredient (for crafting recipes) [*]AddIngredientValues (for cookpot recipes) [*]AddCookerRecipe (for cookpot recipes) [*]AddAction [*]AddStategraphActionHandler [*]AddStategraphState [*]AddStategraphEvent [*]AddStategraphPostInit [*]AddBrainPostInit [*]AddClassPostConstruct (for widgets, and other things) [*]AddGlobalClassPostConstruct

PostInit function can now "stack" so you can call, for example, AddSimPostInit multiple times and each function given will run when the sim starts.

SampleCharacter mod shows the correct place to add the character name string so that the throne works correctly. Also, can now specify the gender of your character so that the pronouns in the end-game sequence are correct.

A number of engine-level error messages have been improved to help with debugging.

The Sample Character mod has moved its Strings assignments and has a few small additions which allow it to work with Maxwell's Throne.


Engine Changes to be aware of

Widgets have been rearranged and changed. Any widgets that you use will have to have their "require" path updated to the widgets folder, and the class are no longer global so they must be stored to a local. So this:
 

    [*]require("image")

becomes this:
 

    [*]local Image = require("widgets/image")

Input behaviour has changed a lot in anticipation of controller support. There are two major things to look out for:
 

    [*]There are no longer "mouse" events. Now everything happens through the OnControl handler on widgets. All our widgets have been updated for this new form, please look there for examples which match your needs or ask for help if you have a specific problem. [*]Focus control is much more automatic and you shouldn't have to worry about it for now.

Share this post


Link to post
Share on other sites

Great! Workshop is a great addition, looking forward to the ruins :-) EDIT: AddLevel? So we can make custom cave levels? :o

Share this post


Link to post
Share on other sites

Great! Workshop is a great addition, looking forward to the ruins :-) EDIT: AddLevel? So we can make custom cave levels? :o

 

 

At the very least you can customize the cave levels that are generated. :) That's a good idea though, I'll have a look at what's involved in "adding" either custom caves or a variety to the generation for modders.

Share this post


Link to post
Share on other sites

Opening console now shows log.txt - great. How do I get rid of it? Ctrl-L doesn't hide it.

Share this post


Link to post
Share on other sites

Opening console now shows log.txt - great. How do I get rid of it? Ctrl-L doesn't hide it.

 

There is a keybind for it now, second last option on the Controls page. I've noticed that sometimes bindings won't get updated, you may just want to hit "reset" on the controls page to rebind all the defaults.

Share this post


Link to post
Share on other sites

I have a recipe with a placer, but the graphics for the placer do not appear unless the animation has already been loaded for an existing, placed prefab nearby the player. Suggestions? Try building the Chaotic Wormhole in this mod https://dl.dropboxusercontent.com/u/32649007/HF_Summons.rar without a wormhole nearby your start and you'll see what I mean.

 

Edit: I am also having another issue that maybe you can take a look at (new in 20th aug preview). I have an action handler that makes it so you can right-click these summons to make them stay in one place instead of following you. This is handled through a switch where the player gets the option to either "order to stay" or "order to follow" depending on its current state. This used to work, but now when I right-click the summons once both states gets flipped immediately (as if I clicked twice). If I click and hold on the summon it works as it should. Any idea why this "double click" is happening?

 

Overview of the code:

component followersitcommand.lua

 

this in modmain.lua

-- [[ SITFOLLOWERCOMMAND BEGIN ]] --STRINGS.ACTIONS.SITCOMMAND = "Order to Stay"STRINGS.ACTIONS.SITCOMMAND_CANCEL = "Order to Follow"STRINGS.CHARACTERS.GENERIC.ANNOUNCE_SITCOMMAND = "Stay there."STRINGS.CHARACTERS.GENERIC.ANNOUNCE_SITCOMMAND_CANCEL = "Come here."STRINGS.CHARACTERS.WX78.ANNOUNCE_SITCOMMAND = "STAY"STRINGS.CHARACTERS.WX78.ANNOUNCE_SITCOMMAND_CANCEL = "FOLLOW"ACTIONS = GLOBAL.ACTIONSACTIONS.SITCOMMAND = GLOBAL.Action(2, true, true)ACTIONS.SITCOMMAND.fn = function(act)    local targ = act.target    if targ and targ.components.followersitcommand then        act.doer.components.locomotor:Stop()        act.doer.components.talker:Say(GLOBAL.GetString(act.doer.prefab, "ANNOUNCE_SITCOMMAND"))        if not targ.components.unteleportable then targ:AddComponent("unteleportable") end        targ.components.followersitcommand:SetStaying(true)        targ.components.followersitcommand:RememberSitPos("currentstaylocation", GLOBAL.Point(targ.Transform:GetWorldPosition()))        return true    endendACTIONS.SITCOMMAND_CANCEL = GLOBAL.Action(2, true, true)ACTIONS.SITCOMMAND_CANCEL.fn = function(act)    local targ = act.target    if targ and targ.components.followersitcommand then        act.doer.components.locomotor:Stop()        act.doer.components.talker:Say(GLOBAL.GetString(act.doer.prefab, "ANNOUNCE_SITCOMMAND_CANCEL"))        targ:RemoveComponent("unteleportable")        targ.components.followersitcommand:SetStaying(false)        return true    endendfor k,v in pairs(ACTIONS) do    if (k == "SITCOMMAND" or k == "SITCOMMAND_CANCEL") then            v.str = STRINGS.ACTIONS[k] or "ACTION"            v.id = k     endend

 

and this in the prefabs

    if ACTIONS.SITCOMMAND ~= nil then        inst:AddComponent("followersitcommand")    end

Share this post


Link to post
Share on other sites

I've posted an updated API Examples mod! Sorry for the delay. But that should provide you with some fun... :)

Share this post


Link to post
Share on other sites

@Heavenfall I'll have a look at this later today. Nothing immediately comes to mind that would be causing these...

Share this post


Link to post
Share on other sites

I have a recipe with a placer, but the graphics for the placer do not appear unless the animation has already been loaded for an existing, placed prefab nearby the player. Suggestions? Try building the Chaotic Wormhole in this mod https://dl.dropboxusercontent.com/u/32649007/HF_Summons.rar without a wormhole nearby your start and you'll see what I mean.

 

Edit: I am also having another issue that maybe you can take a look at (new in 20th aug preview). I have an action handler that makes it so you can right-click these summons to make them stay in one place instead of following you. This is handled through a switch where the player gets the option to either "order to stay" or "order to follow" depending on its current state. This used to work, but now when I right-click the summons once both states gets flipped immediately (as if I clicked twice). If I click and hold on the summon it works as it should. Any idea why this "double click" is happening

 

The issue with the placers: The recipes are being registered too late so their assets aren't being force-loaded. Move all your recipe definitions out of GamePostInit into the global scope of modmain.

 

The issue with the "stay" command: This is a bug, apparently right now it's trying to perform actions both on click-down and click-up. I'll get in a fix for this.

Share this post


Link to post
Share on other sites

I still need to overwrite forest_map.lua to add new values to TRANSLATE_TO_PREFABS and MULTIPLY tables.

 

And did you look into prefab distribution?

It is like if count of prefab is below 1 it is not distributed at all even if its not set to never.

Share this post


Link to post
Share on other sites

The issue with the placers: The recipes are being registered too late so their assets aren't being force-loaded. Move all your recipe definitions out of GamePostInit into the global scope of modmain.

 

The issue with the "stay" command: This is a bug, apparently right now it's trying to perform actions both on click-down and click-up. I'll get in a fix for this.

 

Thank you so much for looking into this.

Share this post


Link to post
Share on other sites

Can you stick this for the next week so we can find it again?

Share this post


Link to post
Share on other sites
@Ipsquiggle

Modders can now modify the TRANSLATE_TO_PREFABS and MULTIPLY worldgen tables.

How to use that thing?

I would be able to upload it to steam workshop after removing forest_map,lua form mod folder, workshop app for mods is up now.

Share this post


Link to post
Share on other sites

@Ipsquiggle

Modders can now modify the TRANSLATE_TO_PREFABS and MULTIPLY worldgen tables.

How to use that thing?

I would be able to upload it to steam workshop after removing forest_map,lua form mod folder, workshop app for mods is up now.

 

local TRANSLATE_TO_PREFABS = GLOBAL.require("map/forest_map").TRANSLATE_TO_PREFABSlocal MULTIPLY = GLOBAL.require("map/forest_map").MULTIPLY

Will that work for you?

Share this post


Link to post
Share on other sites
local TRANSLATE_TO_PREFABS = GLOBAL.require("map/forest_map.lua").TRANSLATE_TO_PREFABSlocal MULTIPLY = GLOBAL.require("map/forest_map.lua").MULTIPLY

Will that work for you?

 

Thanks, will try that now.

local TRANSLATE_TO_PREFABS = GLOBAL.require("map/forest_map").TRANSLATE_TO_PREFABSlocal MULTIPLY = GLOBAL.require("map/forest_map").MULTIPLYMULTIPLY = {	["never"] = 0,	["rare(0.1)"] = 0.1,	["rare(0.15)"] = 0.15,	["rare(0.2)"] = 0.2,	["rare(0.3)"] = 0.3,	["rare"] = 0.5,	["default"] = 1,	["often"] = 1.5,	["mostly"] = 2.2,	["always"] = 3,		}TRANSLATE_TO_PREFABS = {	["spiders"] = 	{"spiderden"},	["tentacles"] = {"tentacle"},	["tallbirds"] = {"tallbirdnest"},	["pigs"] = 		{"pighouse"},	["rabbits"] = 	{"rabbithole"},	["beefalo"] = 	{"beefalo"},	["frogs"] = 	{"pond"},	["bees"] = 		{"killerbee", "beehive"},	["grass"] = 	{"grass"},	["rock"] = 		{"rock1", "rock2", "rock_flintless"}, 	["rocks"] = 	{"rocks"}, 	["sapling"] = 	{"sapling"},	["reeds"] = 	{"reeds"},		["trees"] = 	{"evergreen", "evergreen_sparse"},		["evergreen"] = {"evergreen"},		["carrot"] = 	{"carrot_planted"},	["berrybush"] = {"berrybush", "berrybush2"},	["maxwelllight"] = {"maxwelllight"},	["maxwelllight_area"] = {"maxwelllight_area"},	["fireflies"] = {"fireflies"},    ["mushrooms"] = {"red_mushroom", "green_mushroom", "blue_mushroom"},    ["cave_entrance"] = {"cave_entrance"},	["flowers"] = {"flower"},}

You must add them without .lua or game will crash.

Also doing this like in the code above don't have any effects on prefab count.

Using that form modmain maybe I need to put this in worldgenmain?

Share this post


Link to post
Share on other sites

Thanks, will try that now.

 

You must add them without .lua or game will crash.

Also doing this like in the code above don't have any effects on prefab count.

Using that form modmain maybe I need to put this in worldgenmain?

 

Whoops, that's for pointing that out. Edited the original post for reference.

 

And yes, because this affects world gen, it must be in a worldgenmain.

Share this post


Link to post
Share on other sites

Whoops, that's for pointing that out. Edited the original post for reference.

 

And yes, because this affects world gen, it must be in a worldgenmain.

Didn't get any effects from woldgenmain also.

Must be missing something.

Share this post


Link to post
Share on other sites

With the new preview, I get a crash every time I try to spawn a particular prefab. It worked fine before the update, so I don't know what's happening. On top of that, my log.txt tells me nothing about it. There are no errors or anything.

 

This is the entire prefab contents:

local quakelevels ={    beanstalkQuake=    {        prequake = -3,														  --the warning before the quake        quaketime = function() return GetRandomWithVariance(3,4) end,    		 --how long the quake lasts        debrispersecond = function() return GetRandomWithVariance(3,2) end,     --how much debris falls every second        nextquake = function() return TUNING.TOTAL_DAY_TIME * 100 end,    		 --how long until the next quake    },}local prefabs ={    --Vanilla prefabs.    "goldnugget",    "skeleton",    "marble",        --Mod prefabs.    "beanstalk_chunk",    "golden_egg",    "cloud_turf",    "magic_beans",}local assets ={    Asset("ANIM", "anim/beanstalk.zip"),    Asset("ANIM", "anim/beanstalk_chopped.zip" ),   	 Asset("SOUND", "sound/tentacle.fsb"),}--See whether or not the beanstalk has been chopped down.local function OnLoad(inst, data)    local anim = inst.entity:AddAnimState()   	 if data then   		 inst.isChopped = data.isChopped or false       		 if inst.isChopped == true then                        anim:SetBuild("beanstalk")		    inst.SoundEmitter:KillSound("loop")		    inst.AnimState:PlayAnimation("idle_hole","loop")   		 inst.AnimState:SetTime(math.random()*2)   			 inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_hiddenidle_LP","loop")		    inst:RemoveTag("wet")		    inst:AddTag("stone")           		 elseif inst.isChopped == false then                    anim:SetBuild("beanstalk")		    inst.SoundEmitter:KillSound("loop")		    inst.AnimState:PlayAnimation("idle","loop")   		 inst.AnimState:SetTime(math.random()*2)   			 inst:RemoveTag("stone")		    inst:AddTag("wet")           		 end       	 end    end--Save the current state of the beanstalk.local function OnSave(inst, data)    data.isChopped = inst.isChopped or false    end--Longupdate things.local function OnLongUpdate(inst, dt)    inst.isChopped = (inst.isChopped or false)end--Fixes silly string.local function GetVerb(inst)    return STRINGS.ACTIONS.ACTIVATE.CLIMBend--Makes the beanstalk climbable.local function OnActivate(inst)    --GetPlayer():DoTaskInTime(2, function()        SetHUDPause(true)        local function startadventure()                local function onsaved()       	 StartNextInstance({reset_action=RESET_ACTION.LOAD_SLOT, save_slot = SaveGameIndex:GetCurrentSaveSlot()}, true)            SaveGameIndex.data.slots[self.current_slot].modes.adventure = {world = 1}        end                --local levels = require("map/levels")                        local level = 8        local slot = SaveGameIndex:GetCurrentSaveSlot()                local customoptions = {            preset = {"SKY_LEVEL_1"},        }                --local options = CustomizationScreen.options        local character = GetPlayer().prefab                SetHUDPause(false)                    --options = {        --    preset = "SKY_LEVEL_1",        --}                --CustomizationScreen:LoadPreset("SKY_LEVEL_1")        --GetPlayer().goneUp = true        --GetPlayer().goneUpRemember = false                    SaveGameIndex:FakeAdventure(onsaved, slot, level)                    --SaveGameIndex:StartSurvivalMode(slot, character, customoptions, onsaved)    end        local function rejectadventure()        SetHUDPause(false)        inst.components.activatable.inactive = true        ProfileStatsSet("portal_rejected", true)    end                local options = {        {text="YES", cb = startadventure},        {text="NO", cb = rejectadventure},      }    TheFrontEnd:PushScreen(PopupDialogScreen(        "Up and Away",    "The land above is strange and foreign. Do you want to continue?",        options))        --end)    end--Beanstalks drop loot.local function DropLoot(inst)    if inst.isChopped == true then	    local loot = {}                        --Remove any previous (random) loot table.	    inst.components.lootdropper:SetLoot(loot)                --Beanstalk chunk drops.        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 1.0)            inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.75)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        inst.components.lootdropper:AddChanceLoot("beanstalk_chunk", 0.5)        --Skeleton drops.        inst.components.lootdropper:AddChanceLoot("skeleton", 0.6)        inst.components.lootdropper:AddChanceLoot("skeleton", 0.2)                --Gold nugget drops.        inst.components.lootdropper:AddChanceLoot("goldnugget", 0.7)        inst.components.lootdropper:AddChanceLoot("goldnugget", 0.5)                --Marble drops.        inst.components.lootdropper:AddChanceLoot("marble", 0.8)        inst.components.lootdropper:AddChanceLoot("marble", 0.8)                --Cloud turf drops.        inst.components.lootdropper:AddChanceLoot("cloud_turf", 0.5)        inst.components.lootdropper:AddChanceLoot("cloud_turf", 0.5)        inst.components.lootdropper:AddChanceLoot("cloud_turf", 0.5)                --Golden egg drops.        inst.components.lootdropper:AddChanceLoot("golden_egg", 0.3)        inst.components.lootdropper:AddChanceLoot("golden_egg", 0.3)                --Magic bean drops.        inst.components.lootdropper:AddChanceLoot("magic_beans", 0.21)        inst.components.lootdropper:AddChanceLoot("magic_beans", 0.18)        inst.components.lootdropper:AddChanceLoot("magic_beans", 0.15)        inst.components.lootdropper:AddChanceLoot("magic_beans", 0.12)            --Drop loot near the beanstalk.        inst.components.lootdropper:DropLoot()       	 end    endlocal function stalk_state(inst)    if inst.isChopped == false then   		 inst:RemoveTag("pillaremerging")	    inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_idle_LP","loop")	    inst:RemoveEventCallback("animover", stalk_state)	    inst.isChopped = false	    inst.components.health:SetMaxHealth(TUNING.TENTACLE_HEALTH)       	 elseif inst.isChopped == true then   		 inst:RemoveTag("pillarretracting")	    inst:RemoveEventCallback("animover", stalk_state)	    inst.isChopped = true	    inst.components.health:SetMaxHealth(TUNING.TENTACLE_HEALTH)       	 endendlocal function livingStalk(inst)    inst.components.health:SetMaxHealth(TUNING.TENTACLE_HEALTH)    if inst.isChopped == false then   		 inst.AnimState:PlayAnimation("emerge")	    inst.AnimState:PushAnimation("idle", "loop")	    inst:ListenForEvent("animover", stalk_state)	    inst:AddTag("pillaremerging")	    inst:RemoveTag("stone")	    inst:AddTag("wet")       		 inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_emerge")       		 -- TheCamera:Shake(shakeType, duration, speed, scale)       		 TheCamera:Shake("FULL", 5.0, 0.05, .2)    end    end--This makes it rain items.local function DoShake(inst)    local world = GetWorld()    local quaker = world.components.quaker    if quaker and math.random() > 0.3 then	    quaker:ForceQuake("beanstalkQuake")       	 else	    TheCamera:Shake("FULL", 5.0, 0.05, .2)       	 endend--This doesnt do anything.local function OnDeath(inst)    print "Slayed the beanstalk."end--This does things when the beanstalk is chopped down.local function OnChopped(inst)    print "Was chopped."    inst.isChopped = true   	 if inst.isChopped == false then   		 livingStalk(inst,true)	    return       	 end    inst:DoTaskInTime(1.0,DoShake,inst)    inst:AddTag("pillarretracting")    inst.components.health:SetMaxHealth(TUNING.TENTACLE_HEALTH)    --inst.components.health:SetMaxHealth(TUNING.TENTACLE_HEALTH)    inst.SoundEmitter:KillSound("loop")    inst.AnimState:PlayAnimation("retract",false)    inst:ListenForEvent("animover", stalk_state)    inst.AnimState:PushAnimation("idle_hole","loop")    inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_die")    inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_die_VO")    inst:RemoveTag("wet")    inst:AddTag("stone")    DropLoot(inst)    endlocal function OnEntityWake(inst)    if inst.isChopped == true then	    inst:RemoveTag("wet")	    inst:AddTag("stone")       	 else	    inst:RemoveTag("stone")	    inst:AddTag("wet")       	 end    endlocal function OnEntitySleep(inst)    inst.SoundEmitter:KillSound("loop")    end--This changes the screen some if the player is far.local function onfar(inst)    TheCamera:SetDistance(100)    if not inst.components.health:IsDead() then	    --inst.AnimState:SetMultColour(.1, .1, .1, 0.)    end    end--This changes the screen some if the player is near.local function onnear(inst)    TheCamera:SetDistance(100)    if not inst.components.health:IsDead() then	    -- inst.AnimState:SetMultColour(1, 1, 1, 1)    endendlocal function Emerge(inst)       if inst and inst.brain then	       inst.brain.followtarget = GetPlayer()    end       	 inst:PushEvent("emerge")        endlocal function OnHit(inst, attacker, damage)     	 if attacker.components.combat and attacker ~= GetPlayer() and math.random() > 0.5 then	    attacker.components.combat:SetTarget(nil)       		 if inst.components.health.currenthealth and inst.components.health.currenthealth <0 then		    inst.components.health:DoDelta(damage*.6, false, attacker)	    end       	 end       	 if not inst.components.health:IsDead() and not inst.isChopped then   		 inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_hurt_VO")	    inst.AnimState:PlayAnimation("hit")	    inst.AnimState:PushAnimation("idle", "loop")       		 -- :Shake(shakeType, duration, speed, scale)	    if attacker == GetPlayer() then       	 TheCamera:Shake("SIDE", 0.7, 0.05, .4)	    end           	 endendlocal function fn(Sim)    local inst = CreateEntity()    local trans = inst.entity:AddTransform()    local anim = inst.entity:AddAnimState()        local light = SpawnPrefab("exitcavelight")       	 inst.entity:AddSoundEmitter()    --inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentapiller_idle_LP","loop")   	 inst.OnLoad = OnLoad    inst.OnSave = OnSave    inst.isChopped = false   	 inst.OnLongUpdate = OnLongUpdate    MakeObstaclePhysics(inst, 3, 24)    inst.Physics:SetCollisionGroup(COLLISION.GROUND)    trans:SetScale(1,1,1)           inst:AddTag("beanstalk")   	 inst:AddTag("wet")    --local minimap = inst.entity:AddMiniMapEntity()    --minimap:SetIcon( "tentapillar.png" )    anim:SetBank("tentaclepillar")    anim:SetBuild("beanstalk")        inst.AnimState:PlayAnimation("emerge")    inst.AnimState:PushAnimation("idle", "loop")        light.Transform:SetPosition(inst.Transform:GetWorldPosition())       	 -- anim:SetMultColour(.2, 1, .2, 1.0)    -------------------    inst:AddComponent("health")    inst.components.health:SetMaxHealth(TUNING.TENTACLE_HEALTH)    inst.components.health:SetMinHealth(10)    -------------------   	 inst:AddComponent("playerprox")    inst.components.playerprox:SetDist(10, 30)    inst.components.playerprox:SetOnPlayerNear(onnear)    inst.components.playerprox:SetOnPlayerFar(onfar)    -------------------    inst:AddComponent("lootdropper")    inst.components.lootdropper:SetLoot({})    --------------------- 	 inst:AddComponent("combat")    inst.components.combat:SetOnHit(OnHit)    inst:ListenForEvent("death", OnDeath)    inst:ListenForEvent("minhealth", OnChopped)        inst:AddComponent("activatable")    inst.components.activatable.getverb = GetVerb    inst.components.activatable.OnActivate = OnActivate        inst.components.activatable.quickaction = true   	 inst:AddComponent("inspectable")   	 return inst        endreturn Prefab( "common/monsters/beanstalk", fn, assets, prefabs )

 

Excuse the messiness.

Share this post


Link to post
Share on other sites

Thanks, will try that now.

local TRANSLATE_TO_PREFABS = GLOBAL.require("map/forest_map").TRANSLATE_TO_PREFABSlocal MULTIPLY = GLOBAL.require("map/forest_map").MULTIPLYMULTIPLY = {	["never"] = 0,	["rare(0.1)"] = 0.1,	["rare(0.15)"] = 0.15,	["rare(0.2)"] = 0.2,	["rare(0.3)"] = 0.3,	["rare"] = 0.5,	["default"] = 1,	["often"] = 1.5,	["mostly"] = 2.2,	["always"] = 3,		}TRANSLATE_TO_PREFABS = {	["spiders"] = 	{"spiderden"},	["tentacles"] = {"tentacle"},	["tallbirds"] = {"tallbirdnest"},	["pigs"] = 		{"pighouse"},	["rabbits"] = 	{"rabbithole"},	["beefalo"] = 	{"beefalo"},	["frogs"] = 	{"pond"},	["bees"] = 		{"killerbee", "beehive"},	["grass"] = 	{"grass"},	["rock"] = 		{"rock1", "rock2", "rock_flintless"}, 	["rocks"] = 	{"rocks"}, 	["sapling"] = 	{"sapling"},	["reeds"] = 	{"reeds"},		["trees"] = 	{"evergreen", "evergreen_sparse"},		["evergreen"] = {"evergreen"},		["carrot"] = 	{"carrot_planted"},	["berrybush"] = {"berrybush", "berrybush2"},	["maxwelllight"] = {"maxwelllight"},	["maxwelllight_area"] = {"maxwelllight_area"},	["fireflies"] = {"fireflies"},    ["mushrooms"] = {"red_mushroom", "green_mushroom", "blue_mushroom"},    ["cave_entrance"] = {"cave_entrance"},	["flowers"] = {"flower"},}
You must add them without .lua or game will crash.

Also doing this like in the code above don't have any effects on prefab count.

Using that form modmain maybe I need to put this in worldgenmain?

_Q_, that code is just redefining the local variables

MULTIPLY and TRANSLATE_TO_PREFABS. To actually change the ones inside forest_map, you should do

local Forest = GLOBAL.require("map/forest_map")Forest.MULTIPLY = {	["never"] = 0,	["rare(0.1)"] = 0.1,	["rare(0.15)"] = 0.15,	["rare(0.2)"] = 0.2,	["rare(0.3)"] = 0.3,	["rare"] = 0.5,	["default"] = 1,	["often"] = 1.5,	["mostly"] = 2.2,	["always"] = 3,		}Forest.TRANSLATE_TO_PREFABS = {	["spiders"] = 	{"spiderden"},	["tentacles"] = {"tentacle"},	["tallbirds"] = {"tallbirdnest"},	["pigs"] = 		{"pighouse"},	["rabbits"] = 	{"rabbithole"},	["beefalo"] = 	{"beefalo"},	["frogs"] = 	{"pond"},	["bees"] = 		{"killerbee", "beehive"},	["grass"] = 	{"grass"},	["rock"] = 		{"rock1", "rock2", "rock_flintless"}, 	["rocks"] = 	{"rocks"}, 	["sapling"] = 	{"sapling"},	["reeds"] = 	{"reeds"},		["trees"] = 	{"evergreen", "evergreen_sparse"},		["evergreen"] = {"evergreen"},		["carrot"] = 	{"carrot_planted"},	["berrybush"] = {"berrybush", "berrybush2"},	["maxwelllight"] = {"maxwelllight"},	["maxwelllight_area"] = {"maxwelllight_area"},	["fireflies"] = {"fireflies"},    ["mushrooms"] = {"red_mushroom", "green_mushroom", "blue_mushroom"},    ["cave_entrance"] = {"cave_entrance"},	["flowers"] = {"flower"},}
Basically, your previous version was analogue to

local t = {}local a = t.xa = 2
which doesn't really change t.x, only a itself.

 

 

 

EDIT


 

Also, you shouldn't really add ".lua" to the end. They way require() works (well, actually this depends on package.loaders, but what I'll describe is the default behaviour, which the game preserves) is build the actual filepath based on package.path, which is a string composed of substrings separated by ';' and having '?' as a special character. So let's assume at the time you call require() we have (remembering that now paths are relative to the game's data/ folder, and ignoring the fact that the game is inconsistent in using forward and backward slashes):

assert(  package.path == "../mods/yourmod/scripts/?.lua;scripts/?.lua"  )
When you call require("map/forest_map"), it will take each of the substrings separated by ';' in package.path, replace the '?' by what was given to require() and check if that file exists. If it does, it will be loaded. If it doesn't, the game will proceed to the next substring in package.path (and if there aren't any more, it will throw an error). So require("map/forest_map.lua") would actually be looking for the files

../mods/yourmod/scripts/map/forest_map.lua.lua

scripts/map/forest_map.lua.lua

Share this post


Link to post
Share on other sites

_Q_, that code is just redefining the local variables

MULTIPLY and TRANSLATE_TO_PREFABS. To actually change the ones inside forest_map, you should do

local Forest = GLOBAL.require("map/forest_map")Forest.MULTIPLY = {	["never"] = 0,	["rare(0.1)"] = 0.1,	["rare(0.15)"] = 0.15,	["rare(0.2)"] = 0.2,	["rare(0.3)"] = 0.3,	["rare"] = 0.5,	["default"] = 1,	["often"] = 1.5,	["mostly"] = 2.2,	["always"] = 3,		}Forest.TRANSLATE_TO_PREFABS = {	["spiders"] = 	{"spiderden"},	["tentacles"] = {"tentacle"},	["tallbirds"] = {"tallbirdnest"},	["pigs"] = 		{"pighouse"},	["rabbits"] = 	{"rabbithole"},	["beefalo"] = 	{"beefalo"},	["frogs"] = 	{"pond"},	["bees"] = 		{"killerbee", "beehive"},	["grass"] = 	{"grass"},	["rock"] = 		{"rock1", "rock2", "rock_flintless"}, 	["rocks"] = 	{"rocks"}, 	["sapling"] = 	{"sapling"},	["reeds"] = 	{"reeds"},		["trees"] = 	{"evergreen", "evergreen_sparse"},		["evergreen"] = {"evergreen"},		["carrot"] = 	{"carrot_planted"},	["berrybush"] = {"berrybush", "berrybush2"},	["maxwelllight"] = {"maxwelllight"},	["maxwelllight_area"] = {"maxwelllight_area"},	["fireflies"] = {"fireflies"},    ["mushrooms"] = {"red_mushroom", "green_mushroom", "blue_mushroom"},    ["cave_entrance"] = {"cave_entrance"},	["flowers"] = {"flower"},}

Basically, your previous version was analogue to

local t = {}local a = t.xa = 2

which doesn't really change t.x, only a itself.

Will try tommorow. I need sleep now, can't look at the screen for long periods of time, my eyes are burning.

Share this post


Link to post
Share on other sites

Will try tommorow. I need sleep now, can't look at the screen for long periods of time, my eyes are burning.

That's why I wrote a forum reskin. : P

At the very least, I highly recommend the changes I made to syntax highlighting (which I'm currently only distributing bundled together, but I may split it on request).

Posted Image

Anyway, I edited my previous post to explain how require() searches for a file.

EDIT


Seriously? I disabled emoticons, wrote ": P" (without the space in between) and it was replaced by :razz: (without rendering the emoticon image). Now disabling emoticons somehow means they just won't appear as a picture...

Share this post


Link to post
Share on other sites

That's why I wrote a forum reskin. : P

At the very least, I highly recommend the changes I made to syntax highlighting (which I'm currently only distributing bundled together, but I may split it on request).

Posted Image

Anyway, I edited my previous post to explain how require() searches for a file.

EDIT


Seriously? I disabled emoticons, wrote ": P" (without the space in between) and it was replaced by :razz: (without rendering the emoticon image). Now disabling emoticons somehow means they just won't appear as a picture...

Doing this your way or any other way don't have any impact on prefab count.

All 3 things are returned at the end of forest_map.lua like this:

return {    Generate = GenerateVoro,    TRANSLATE_TO_PREFABS = TRANSLATE_TO_PREFABS,    MULTIPLY = MULTIPLY,}

I can edit the table if it is called MULTIPLY or using your way, but the prefab count remains at default levels.

Share this post


Link to post
Share on other sites

At the very least you can customize the cave levels that are generated. :-) That's a good idea though, I'll have a look at what's involved in "adding" either custom caves or a variety to the generation for modders.

So at the moment we can't make custom caves, as in make a custom sinkhole that leads to one custom cave?

Share this post


Link to post
Share on other sites