Jump to content

[HELP]How to pick a ramdom coordinate that is valid to spawn


Recommended Posts

@DarkXero

 

Since the topic has posted for a long time and no one posted, I come to you for help. I want to spawn rocks when they are mined. But I don't know how to pick a random coordinate on rocky ground in DS and DST, Especially DS.

Link to comment
Share on other sites

@Jupiters,

there are many checks that can be done.

 

For example, in shadowmeteor.lua:

        for i, v in ipairs(inst.loot) do            if math.random() <= v.chance then                local canspawn = true                if v.radius ~= nil then                    --Check if there's space to deploy rocks                    --Similar to CanDeployAtPoint check in map.lua                    local ents = TheSim:FindEntities(x, y, z, v.radius, nil, { "NOBLOCK", "FX" })                    for k, v in pairs(ents) do                        if v ~= inst and                            not launched[v] and                            v.entity:IsValid() and                            v.entity:IsVisible() and                            v.components.placer == nil and                            v.entity:GetParent() == nil then                            canspawn = false                            break                        end                    end                end                if canspawn then                    local drop = SpawnPrefab(v.prefab)                    if drop ~= nil then                        drop.Transform:SetPosition(x, y, z)                        if drop.components.inventoryitem ~= nil then                            drop.components.inventoryitem:OnDropped(true)                        end                    end                end            end        end

Here you have checks for valid placement.

 

Or in the component, lootdropper.lua:

            if loot.Physics ~= nil then                local angle = math.random() * 2 * PI                local speed = math.random() * 2                if loot:IsAsleep() then                    local radius = .5 * speed + (self.inst ~= nil and self.inst.Physics ~= nil and (loot.Physics:GetRadius() or 1) + (self.inst.Physics:GetRadius() or 1) or 0)                    loot.Transform:SetPosition(                        pt.x + math.cos(angle) * radius,                        0,                        pt.z + math.sin(angle) * radius                    )                    SplashOceanLoot(loot)                else                    loot.Physics:SetVel(speed * math.cos(angle), GetRandomWithVariance(8, 4), speed * math.sin(angle))                    if self.inst ~= nil and self.inst.Physics ~= nil then                        local radius = (loot.Physics:GetRadius() or 1) + (self.inst.Physics:GetRadius() or 1)                        loot.Transform:SetPosition(                            pt.x + math.cos(angle) * radius,                            pt.y,                            pt.z + math.sin(angle) * radius                        )                    end                    loot:DoTaskInTime(1, SplashOceanLoot)                end            end

Here you have the stuff being tossed and then checked later in SplashOceanLoot to see if it fell to the ocean.

 

You can even use the checks with inst:GetCurrentTileType() to check if the place you want to spawn stuff is GROUND.IMPASSABLE, or use any of the function in components map.lua, like TheWorld.Map:CanPlacePrefabFilteredAtPoint(x, y, z, prefab).

 

 

 

 

However, for what you want to do, this is not necessary.

All you have to do is edited the SharedLootTables of the prefabs in rocks.lua.

Your typical nitre giving rock is rock1.

Your typical gold giving rock is rock2.

 

So what we do is this:

-- We run this after the sim started so LootTables got globally declared in any lootdropperAddSimPostInit(function()	-- We get the global loot tables created via SetSharedLootTable	local _LT = GLOBAL.LootTables	-- Now we follow the format inside those tables	-- Each element of the table is another table, that consists of a prefab, and the probability to drop	-- We add to the shared loot table of rock1, a 1 chance of dropping a blue gem, and 0.5 chance of dropping a red gem	table.insert(_LT["rock1"], {"bluegem", 1.00})	table.insert(_LT["rock1"], {"redgem", 0.50})	-- We add to the shared loot table of rock2, a 0.5 chance of dropping a blue gem, and 1 chance of dropping a red gem	table.insert(_LT["rock2"], {"bluegem", 0.50})	table.insert(_LT["rock2"], {"redgem", 1.00})	-- In rocks.lua you have the rest of the shared loot tables for the other rocks	-- The rock_moon table has moon rock nuggets	-- The others just have rocks and more rocksend)
Link to comment
Share on other sites

Thank you, @DarkXero

I'm so sorry I didn't make myself clear. What I meant was that the boulder will respawn into the world after it was mined. I try to do it in madmain.lua like this:

 

 

math.randomseed(GLOBAL.os.time())
AddPrefabPostInit("rock1", function( inst )
    inst.components.workable:SetOnWorkCallback(
        function(inst, worker, workleft)
        local pt = Point(inst.Transform:GetWorldPosition())
        if workleft <= 0 then
            inst.SoundEmitter:PlaySound("dontstarve/wilson/rock_break")
            inst.components.lootdropper:DropLoot(pt)
            inst:Remove()
            local pt = GLOBAL.Vector3(math.random(-1000,1000), 0, math.random(-1000,1000))
            GLOBAL.SpawnPrefab("rock1").Transform:SetPosition(pt:Get())
        else
            if workleft < TUNING.ROCKS_MINE*(1/3) then
                inst.AnimState:PlayAnimation("low")
            elseif workleft < TUNING.ROCKS_MINE*(2/3) then
                inst.AnimState:PlayAnimation("med")
            else
                inst.AnimState:PlayAnimation("full")
            end
        end
    end)
end)
 
The lines in red is what what I added and the line in blue already existed in rocks.lua.
As you can see, I want to override inst.components.workable:SetOnWorkCallback() .
The lines in red is what I added to pick a random coordinate and spawn a rock1. But it will spawn on the see. How do I filter the coordinate that is ground(the tile is rocky or dirt, etc).
 
Is there a better to excute these function other than override inst.components.workable:SetOnWorkCallback() ?
 
By the way, this is for DS.
Link to comment
Share on other sites

@Jupiters:

local function TrySpawn()    local pt = GLOBAL.Vector3(math.random(-1000, 1000), 0, math.random(-1000, 1000))    local tile = GLOBAL.GetWorld().Map:GetTileAtPoint(pt.x, pt.y, pt.z)    local canspawn = tile ~= GLOBAL.GROUND.IMPASSABLE and tile ~= GLOBAL.GROUND.INVALID    if canspawn then        print("Rock respawned!")        GLOBAL.SpawnPrefab("rock1").Transform:SetPosition(pt:Get())    else        print("Position invalid. Trying again...")        TrySpawn()    endend--math.randomseed(GLOBAL.os.time())AddPrefabPostInit("rock1", function( inst )    local _onwork = inst.components.workable.onwork    inst.components.workable.onwork = function(inst, worker, workleft)        if workleft <= 0 then            TrySpawn()        end        _onwork(inst, worker, workleft)    endend)

You can attach your function to onwork, like this.

Link to comment
Share on other sites

@DarkXero

 

You are such a genius!!!!!! Thank you. :-)

 

But with one problem, the boulder will respawn out of the map, on the black zone.

 

I reduce the number 1000 to 650, and it works. But is there any other solution that I dont need to reduce the number of math.random? Because I need it covers all the area of map when the map size is different.

 

Plus, why there is no components map.lua in DS.

Edited by Jupiters
Link to comment
Share on other sites

Apparently that's the code for the black squares out of bounds.
 

 

Thank you, it works now.

I want to use inst:DoTaskInTime() to delay the rock spawn so that the rock will not spawn immediately. But DoTaskInTime will be interrupted when I reload the game. Are there other funtions?

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...