• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[TFS 1.x] Procedural Cave Generation

leomarques

Active Member
Joined
Sep 6, 2020
Messages
6
Reaction score
38
Hello Everyone!

This is the first time I'm contributing to this community. i've been here for a long time just getting all sorts of resource and useful stuff and it's time to return something.

gifExemple.gif

I recently followed the Sebastian Lague's tutorial for a procedural cave generation based on cellular automata algorithim, and decides to convert to an Open Tibia project.

To made this work:
  1. Put the 2 scripts files on the script folder
  2. Chose some place on your map to use for the map generation.
    from: (x=1500,y=300,z=7) to (x=1620,y=420,z=7)
    img1.png
  3. Create the space where the player will appear
    from: (x=1555,y=355,z=7) to (x=1565,y=365,z=7)
    img2.JPG
  4. Configure the levers aid (2301, 2302, 2303, 2304, 2305)
  5. Configure the script
    Lua:
    local MAPS = {
        [1] = {
            startX = 1500, startY = 300, startZ = 7,
            width = 120, height = 120,
            randonFillPercent = 50,
            roomTheresholdSize = 50,
            wallTheresholdSize = 100,
            playerSpawn ={x=55, y=55, size=10}, --start point x=1555, y=355
            map = {},
            remover_primeira_camada = true,
            style = Styles["Earth"]
        },
        [2] = {
            startX = 1500, startY = 300, startZ = 7,
            width = 120, height = 120,
            randonFillPercent = 52,
            roomTheresholdSize = 50,
            wallTheresholdSize = 100,
            playerSpawn ={x=55, y=55, size=10},
            map = {},
            remover_primeira_camada = true,
            style = Styles["Earth (stone border)"]
        },
        [3] = {
            startX = 1500, startY = 300, startZ = 7,
            width = 120, height = 120,
            randonFillPercent = 55,
            roomTheresholdSize = 20,
            wallTheresholdSize = 50,
            playerSpawn ={x=55, y=55, size=10},
            map = {},
            remover_primeira_camada = true,
            style = Styles["Rock Mountain"]
        },
        [4] = {
            startX = 1500, startY = 300, startZ = 7,
            width = 120, height = 120,
            randonFillPercent = 51,
            roomTheresholdSize = 20,
            wallTheresholdSize = 50,
            playerSpawn ={x=55, y=55, size=10},
            map = {},
    
            remover_primeira_camada = true,
            style = Styles["Earth Mountain"]
        },
        [5] = {
            startX = 1500, startY = 300, startZ = 7,
            width = 120, height = 120,
            randonFillPercent = 52,
            roomTheresholdSize = 50,
            wallTheresholdSize = 100,
            playerSpawn ={x=55, y=55, size=10},
            map = {},
            remover_primeira_camada = true,
            style = Styles["Darkest Mud (lava)"]
        },
    }

Github Repository: (updated)

Todo List:
  1. Monster spawn script [Done] - See the changes here
  2. Beautify the cave floor (diferent tiles, itens and etc..)
  3. Improve the randomness of tiles
Improvements:
  1. Possibility of multiple floors
  2. More complex generations (islands and etc.)
Credtis:
  • Sebastian Langue: For the amazing tutorial
  • Inconcessus: For the logic I used to create the auto border
  • OtLand Communit: For all these years of dedication
 

Attachments

Last edited by a moderator:
what happen if you use the lever when a another player is inside the cave?
Figure lol. In real world scenario, you have to handle who you let in.

@topic
Wow, one of the most remarkable contributions I've seen for some time
 
what happen if you use the lever when a another player is inside the cave?
The player will be teleported to the temple.
This is more like a base to work in. its simple to check if there is a player inside of the cave before the generation.
and actually I don't know if the lever is the best approach in a real world scenario. the best way is probably putting the trigger on the teleport, and made all the necessaries checks.

Figure lol. In real world scenario, you have to handle who you let in.

@topic
Wow, one of the most remarkable contributions I've seen for some time
Thank you, I'm happy and I hope to contribute more actively from now on :)

amazing! If you would like to join our discussion and share your insights, feel free to come to our thread: Generating maps? (https://otland.net/threads/generating-maps.200487/)

btw, did you have any issues with dead cells (unreachable caves)?
This topic was one that I researched before I started working on this project. however as I did not find the complete code, so I decided to work on one. I would love to know how you approached the autoborder issue and how you made the cave so beautiful.

About the unreachable caves: on the tutorial that I followed, the Part06 and Part07 talk specifically about the connection between cells and the certainty that they are all connected. so in this case that's not a problem, all cells are connected.
And to make the autoborder I made sure and removed a wall layer (function RemoverPrimeiraCamadaDeWall) so that there is no possibility of the border blocking some passage.
 
This topic was one that I researched before I started working on this project. however as I did not find the complete code, so I decided to work on one. I would love to know how you approached the autoborder issue and how you made the cave so beautiful.
I coded it to be 2x2 and attached some scripts to it to fix weird interactions or add irregularities (eg. small debris near mountain walls)

bordering code starts here if you're interested (just uploaded this repo)
keep in mind that I wrote that 7 years ago and there might be better ways to code it

edit: 9 years ago actually*
 
Last edited:
Hello Again!

I created the creature spawn part. and decided to create a git repository to better organize development.

gifExemple2.gif

how does it work ?
As I haven't found any way to create a spawn. I used the "ondeath" creature event.
Whenever the creature dies I add a respawn event, and update a local list. if the creature is not in the list the spawn is not created.

you can see all the changes here: MonsterSpawner Commit

Basically you just need to add the creatures, the amount and respawn time as you can see in the example below:
Lua:
local MAPS = {
    [1] = {
        startX = 1500, startY = 300, startZ = 7,
        width = 120, height = 120,
        randonFillPercent = 50,
        roomTheresholdSize = 50,
        wallTheresholdSize = 100,
        playerSpawn ={x=55, y=55, size=10},
        map = {},
        remover_primeira_camada = true,
        style = Styles["Earth"],
        spawnId = 1,
        monsters = {
            {name = "Rotworm", amount = 200, time = 1000},
            {name = "Carrion Worm", amount = 100, time = 10000},
            {name = "Rotworm Queen", amount = 1, time = 60000},
        }
    }
}

it's important to differentiate the "spawnId" between the maps.

The github repository: GitHub - LeoMarques101/ProceduralCaveGeneration: Open Tibia Procedural Cave Generation (Cellular Automata) (https://github.com/LeoMarques101/ProceduralCaveGeneration)
 
I'll be honest, idk how the entire server doesn't lag when you flop those switches. xD

Looks cool.
 
I'll be honest, idk how the entire server doesn't lag when you flop those switches. xD

Looks cool.

area is small, one floor tall and the generation process isn't very complex yet
lags start roughly at sizes such as 512x512x3 or when caves get several layers of many details
 
area is small, one floor tall and the generation process isn't very complex yet
lags start roughly at sizes such as 512x512x3 or when caves get several layers of many details
and even then we can split it into chunks, right?
 
This is awesome!

You could now run dijkstra's map or some wave function that finds distances to the teleporter and to the walls.
With this information you can create rules such as: only place difficult monsters at X distance from the teleporter,
or only place certain objects X, Y distance from the wall etc.
 
It would be interesting to add a boss room, to create daily or weekly dungeons, in a procedural way :) thanks for your contribution, I have several ideas to realize
 
This is insanely cool, been waiting for someone to push this as far as you have. Really neat and I'll prolly start a side-project including this to see what the possibilities are.
 
Hello Again!

I created the creature spawn part. and decided to create a git repository to better organize development.

View attachment 69558

how does it work ?
As I haven't found any way to create a spawn. I used the "ondeath" creature event.
Whenever the creature dies I add a respawn event, and update a local list. if the creature is not in the list the spawn is not created.

you can see all the changes here: MonsterSpawner Commit

Basically you just need to add the creatures, the amount and respawn time as you can see in the example below:
Lua:
local MAPS = {
    [1] = {
        startX = 1500, startY = 300, startZ = 7,
        width = 120, height = 120,
        randonFillPercent = 50,
        roomTheresholdSize = 50,
        wallTheresholdSize = 100,
        playerSpawn ={x=55, y=55, size=10},
        map = {},
        remover_primeira_camada = true,
        style = Styles["Earth"],
        spawnId = 1,
        monsters = {
            {name = "Rotworm", amount = 200, time = 1000},
            {name = "Carrion Worm", amount = 100, time = 10000},
            {name = "Rotworm Queen", amount = 1, time = 60000},
        }
    }
}

it's important to differentiate the "spawnId" between the maps.

The github repository: GitHub - LeoMarques101/ProceduralCaveGeneration: Open Tibia Procedural Cave Generation (Cellular Automata) (https://github.com/LeoMarques101/ProceduralCaveGeneration)
super cool and everything but if I use version 772 the floors of some areas would not load, how do I know which ones I should put exactly? Or could you post one here for lower distribution, though I'm still trying to do it myself.
 
Lua Script Error: [Scripts Interface]
E:\sssssssssssssssssssssssss\data\scripts\Procedural_Map.lua:callback
...ssssssssssssssssssssssss\data\scripts\Procedural_Map.lua:736: attempt to index local 't' (a nil value)
stack traceback:
[C]: in function '__index'
...ssssssssssssssssssssssss\data\scripts\Procedural_Map.lua:736: in function 'RemoveOlderSpawns'
...ssssssssssssssssssssssss\data\scripts\Procedural_Map.lua:831: in function <...ssssssssssssssssssssssss\data\scripts\Procedural_Map.lua:825>
Post automatically merged:

TFS 1.3
 
Back
Top