Update translation templates
[oweals/minetest_game.git] / mods / spawn / init.lua
1 -- spawn/init.lua
2
3 -- Disable by mapgen, setting or if 'static_spawnpoint' is set
4 --------------------------------------------------------------
5
6 local mg_name = minetest.get_mapgen_setting("mg_name")
7 if mg_name == "v6" or mg_name == "singlenode" or
8                 minetest.settings:get("static_spawnpoint") or
9                 minetest.settings:get_bool("engine_spawn") then
10         return
11 end
12
13
14 -- Parameters
15 -------------
16
17 -- Resolution of search grid in nodes.
18 local res = 64
19 -- Number of points checked in the square search grid (edge * edge).
20 local checks = 128 * 128
21 -- Starting point for biome checks. This also sets the y co-ordinate for all
22 -- points checked, so the suitable biomes must be active at this y.
23 local pos = {x = 0, y = 8, z = 0}
24
25
26 -- Table of suitable biomes
27
28 local biome_ids = {
29         minetest.get_biome_id("taiga"),
30         minetest.get_biome_id("coniferous_forest"),
31         minetest.get_biome_id("deciduous_forest"),
32         minetest.get_biome_id("grassland"),
33         minetest.get_biome_id("savanna"),
34 }
35
36 -- End of parameters
37 --------------------
38
39
40 -- Direction table
41
42 local dirs = {
43         {x = 0, y = 0, z = 1},
44         {x = -1, y = 0, z = 0},
45         {x = 0, y = 0, z = -1},
46         {x = 1, y = 0, z = 0},
47 }
48
49
50 -- Initial variables
51
52 local edge_len = 1
53 local edge_dist = 0
54 local dir_step = 0
55 local dir_ind = 1
56 local searched = false
57 local success = false
58 local spawn_pos = {}
59
60
61 -- Get world 'mapgen_limit' and 'chunksize' to calculate 'spawn_limit'.
62 -- This accounts for how mapchunks are not generated if they or their shell exceed
63 -- 'mapgen_limit'.
64
65 local mapgen_limit = tonumber(minetest.get_mapgen_setting("mapgen_limit"))
66 local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
67 local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
68
69
70 --Functions
71 -----------
72
73 -- Get next position on square search spiral
74
75 local function next_pos()
76         if edge_dist == edge_len then
77                 edge_dist = 0
78                 dir_ind = dir_ind + 1
79                 if dir_ind == 5 then
80                         dir_ind = 1
81                 end
82                 dir_step = dir_step + 1
83                 edge_len = math.floor(dir_step / 2) + 1
84         end
85
86         local dir = dirs[dir_ind]
87         local move = vector.multiply(dir, res)
88
89         edge_dist = edge_dist + 1
90
91         return vector.add(pos, move)
92 end
93
94
95 -- Spawn position search
96
97 local function search()
98         for iter = 1, checks do
99                 local biome_data = minetest.get_biome_data(pos)
100                 -- Sometimes biome_data is nil
101                 local biome = biome_data and biome_data.biome
102                 for id_ind = 1, #biome_ids do
103                         local biome_id = biome_ids[id_ind]
104                         if biome == biome_id then
105                                 local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
106                                 if spawn_y then
107                                         spawn_pos = {x = pos.x, y = spawn_y, z = pos.z}
108                                         return true
109                                 end
110                         end
111                 end
112
113                 pos = next_pos()
114                 -- Check for position being outside world edge
115                 if math.abs(pos.x) > spawn_limit or math.abs(pos.z) > spawn_limit then
116                         return false
117                 end
118         end
119
120         return false
121 end
122
123
124 -- On new player spawn and player respawn
125
126 -- Search for spawn position once per server session. If successful, store
127 -- position and reposition players, otherwise leave them at engine spawn
128 -- position.
129
130 local function on_spawn(player)
131         if not searched then
132                 success = search()
133                 searched = true
134         end
135         if success then
136                 player:set_pos(spawn_pos)
137         end
138         return success
139 end
140
141 minetest.register_on_newplayer(function(player)
142         on_spawn(player)
143 end)
144
145 local enable_bed_respawn = minetest.settings:get_bool("enable_bed_respawn")
146 if enable_bed_respawn == nil then
147         enable_bed_respawn = true
148 end
149
150 minetest.register_on_respawnplayer(function(player)
151         -- Avoid respawn conflict with beds mod
152         if beds and enable_bed_respawn and
153                         beds.spawn[player:get_player_name()] then
154                 return
155         end
156
157         return on_spawn(player)
158 end)