Skip to content
Snippets Groups Projects
Commit 4ede8943 authored by dg's avatar dg
Browse files

Forest level generator, using noise

git-svn-id: http://svn.net-core.org/repos/t-engine4@668 51575b47-30f0-44d4-a5cc-537603b46e54
parent d9c633fd
No related branches found
No related tags found
No related merge requests found
......@@ -20,10 +20,11 @@
require "engine.class"
module(..., package.seeall, class.make)
function _M:init(zone, map, level)
function _M:init(zone, map, level, spots)
self.zone = zone
self.map = map
self.level = level
self.spots = spots
-- Setup the map's room-map
if not map.room_map then
......
......@@ -20,6 +20,7 @@
require "engine.class"
local Savefile = require "engine.Savefile"
local Map = require "engine.Map"
local Astar = require "engine.Astar"
--- Defines a zone: a set of levels, with depth, nps, objects, level generator, ...
module(..., package.seeall, class.make)
......@@ -450,7 +451,7 @@ function _M:newLevel(level_data, lev, old_lev, game)
level.ups = {{x=ux, y=uy}}
level.downs = {{x=dx, y=dy}}
level.spots = spots
level.spots = spots or {}
-- Generate objects
if level_data.generator.object then
......@@ -482,5 +483,29 @@ function _M:newLevel(level_data, lev, old_lev, game)
-- Delete the room_map, now useless
map.room_map = nil
-- Check for connectivity from entrance to exit
local a = Astar.new(map, game:getPlayer())
if ux and uy and dx and dy and not a:calc(ux, uy, dx, dy) then
print("Level unconnected, no way from entrance to exit")
level:removed()
return self:newLevel(level_data, lev, old_lev, game)
end
for i = 1, #spots do
local spot = spots[i]
if spot.check_connectivity then
local cx, cy
if type(spot.check_connectivity) == "string" and spot.check_connectivity == "entrance" then cx, cy = ux, uy
elseif type(spot.check_connectivity) == "string" and spot.check_connectivity == "exit" then cx, cy = dx, dy
else cx, cy = spot.check_connectivity.x, spot.check_connectivity.y
end
if not a:calc(spot.x, spot.y, cx, cy) then
print("Level unconnected, no way from", spot.x, spot.y, "to", cx, cy)
level:removed()
return self:newLevel(level_data, lev, old_lev, game)
end
end
end
return level
end
......@@ -22,8 +22,8 @@ local Map = require "engine.Map"
require "engine.Generator"
module(..., package.seeall, class.inherit(engine.Generator))
function _M:init(zone, map, level)
engine.Generator.init(self, zone, map, level)
function _M:init(zone, map, level, spots)
engine.Generator.init(self, zone, map, level, spots)
local data = level.data.generator.actor
if data.adjust_level then
......@@ -52,6 +52,7 @@ function _M:generate()
tries = tries + 1
end
if tries < 100 then
self.spots[#self.spots+1] = {x=x, y=y, gardian=true, check_connectivity="entrance"}
self.zone:addEntity(self.level, m, "actor", x, y)
print("Guardian allocated: ", self.guardian, m.uid, m.name)
end
......
-- TE4 - T-Engine 4
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
require "engine.class"
local Map = require "engine.Map"
require "engine.Generator"
module(..., package.seeall, class.inherit(engine.Generator))
function _M:init(zone, map, level, data)
engine.Generator.init(self, zone, map, level)
self.data = data
self.grid_list = self.zone.grid_list
self.noise = data.noise or "fbm_perlin"
self.zoom = data.zoom or 5
self.max_percent = data.max_percent or 80
self.sqrt_percent = data.sqrt_percent or 30
self.hurst = data.hurst or nil
self.lacunarity = data.lacunarity or nil
self.octave = data.octave or 4
end
function _M:resolve(c)
local res = self.data[c]
if type(res) == "function" then
return res()
elseif type(res) == "table" then
return res[rng.range(1, #res)]
else
return res
end
end
function _M:generate(lev, old_lev)
for i = 0, self.map.w - 1 do for j = 0, self.map.h - 1 do
self.map(i, j, Map.TERRAIN, self.grid_list[self.floor])
end end
-- make the noise
local noise = core.noise.new(2, self.hurst, self.lacunarity)
for i = 1, self.map.w do
for j = 1, self.map.h do
local v = math.floor((noise[self.noise](noise, self.zoom * i / self.map.w, self.zoom * j / self.map.h, self.octave) / 2 + 0.5) * self.max_percent)
if (v >= self.sqrt_percent and rng.percent(v)) or (v < self.sqrt_percent and rng.percent(math.sqrt(v))) then
self.map(i-1, j-1, Map.TERRAIN, self.grid_list[self:resolve("wall")])
else
self.map(i-1, j-1, Map.TERRAIN, self.grid_list[self:resolve("floor")])
end
end
end
local ux, uy, dx, dy, spots
if self.data.edge_entrances then
ux, uy, dx, dy, spots = self:makeStairsSides(lev, old_lev, self.data.edge_entrances, spots)
else
ux, uy, dx, dy, spots = self:makeStairsInside(lev, old_lev, spots)
end
return ux, uy, dx, dy, spots
end
--- Create the stairs inside the level
function _M:makeStairsInside(lev, old_lev, spots)
-- Put down stairs
local dx, dy
if lev < self.zone.max_level or self.data.force_last_stair then
while true do
dx, dy = rng.range(1, self.map.w - 1), rng.range(1, self.map.h - 1)
if not self.map:checkEntity(dx, dy, Map.TERRAIN, "block_move") and not self.map.room_map[dx][dy].special then
self.map(dx, dy, Map.TERRAIN, self.grid_list[self:resolve("down")])
self.map.room_map[dx][dy].special = "exit"
break
end
end
end
-- Put up stairs
local ux, uy
while true do
ux, uy = rng.range(1, self.map.w - 1), rng.range(1, self.map.h - 1)
if not self.map:checkEntity(ux, uy, Map.TERRAIN, "block_move") and not self.map.room_map[ux][uy].special then
self.map(ux, uy, Map.TERRAIN, self.grid_list[self:resolve("up")])
self.map.room_map[ux][uy].special = "exit"
break
end
end
return ux, uy, dx, dy, spots
end
--- Create the stairs on the sides
function _M:makeStairsSides(lev, old_lev, sides, spots)
-- Put down stairs
local dx, dy
if lev < self.zone.max_level or self.data.force_last_stair then
while true do
if sides[2] == 4 then dx, dy = 0, rng.range(0, self.map.h - 1)
elseif sides[2] == 6 then dx, dy = self.map.w - 1, rng.range(0, self.map.h - 1)
elseif sides[2] == 8 then dx, dy = rng.range(0, self.map.w - 1), 0
elseif sides[2] == 2 then dx, dy = rng.range(0, self.map.w - 1), self.map.h - 1
end
if not self.map.room_map[dx][dy].special then
self.map(dx, dy, Map.TERRAIN, self.grid_list[self:resolve("down")])
self.map.room_map[dx][dy].special = "exit"
break
end
end
end
-- Put up stairs
local ux, uy
while true do
if sides[1] == 4 then ux, uy = 0, rng.range(0, self.map.h - 1)
elseif sides[1] == 6 then ux, uy = self.map.w - 1, rng.range(0, self.map.h - 1)
elseif sides[1] == 8 then ux, uy = rng.range(0, self.map.w - 1), 0
elseif sides[1] == 2 then ux, uy = rng.range(0, self.map.w - 1), self.map.h - 1
end
if not self.map.room_map[ux][uy].special then
self.map(ux, uy, Map.TERRAIN, self.grid_list[self:resolve("up")])
self.map.room_map[ux][uy].special = "exit"
break
end
end
return ux, uy, dx, dy, spots
end
......@@ -503,8 +503,7 @@ function _M:setupCommands()
self.key:addCommands{
[{"_d","ctrl"}] = function()
if config.settings.tome.cheat then self:changeLevel(3, "moria") end
-- if config.settings.tome.cheat then self:changeLevel(1, "wilderness-arda-fareast") end
if config.settings.tome.cheat then self:changeLevel(1, "test") end
end,
}
self.key:addBinds
......
-- ToME - Tales of Middle-Earth
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
load("/data/general/grids/basic.lua")
load("/data/general/grids/forest.lua")
-- ToME - Tales of Middle-Earth
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
load("/data/general/npcs/orc.lua")
load("/data/general/npcs/troll.lua")
local Talents = require("engine.interface.ActorTalents")
-- The boss of Moria, no "rarity" field means it will not be randomly generated
newEntity{ define_as = "GOLBUG",
type = "humanoid", subtype = "orc", unique = true,
name = "Golbug the Destroyer",
display = "o", color=colors.VIOLET,
desc = [[A huge and muscular orc of unknown breed. He looks both menacing and cunning...]],
level_range = {28, 45}, exp_worth = 2,
max_life = 350, life_rating = 16, fixed_rating = true,
max_stamina = 245,
rank = 4,
size_category = 3,
stats = { str=22, dex=19, cun=34, mag=10, con=16 },
body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1, NECK=1, HEAD=1, },
equipment = resolvers.equip{
{type="weapon", subtype="mace", ego_chance=100, autoreq=true},
{type="armor", subtype="shield", ego_chance=100, autoreq=true},
{type="armor", subtype="head", autoreq=true},
{type="armor", subtype="massive", ego_chance=50, autoreq=true},
},
resolvers.drops{chance=100, nb=5, {ego_chance=100} },
resolvers.drops{chance=100, nb=1, {type="jewelry", subtype="orb", defined="ORB_MANY_WAYS"} },
stun_immune = 1,
see_invisible = 5,
resolvers.talents{
[Talents.T_HEAVY_ARMOUR_TRAINING]=1,
[Talents.T_MASSIVE_ARMOUR_TRAINING]=3,
[Talents.T_WEAPON_COMBAT]=6,
[Talents.T_MACE_MASTERY]=6,
[Talents.T_SHIELD_PUMMEL]=4,
[Talents.T_RUSH]=4,
[Talents.T_RIPOSTE]=4,
[Talents.T_BLINDING_SPEED]=4,
[Talents.T_OVERPOWER]=3,
[Talents.T_ASSAULT]=3,
[Talents.T_SHIELD_WALL]=3,
[Talents.T_SHIELD_EXPERTISE]=2,
[Talents.T_BELLOWING_ROAR]=3,
[Talents.T_WING_BUFFET]=2,
[Talents.T_FIRE_BREATH]=4,
[Talents.T_ICE_CLAW]=3,
[Talents.T_ICY_SKIN]=4,
[Talents.T_ICE_BREATH]=4,
},
autolevel = "warrior",
ai = "dumb_talented_simple", ai_state = { talent_in=2, },
on_die = function(self, who)
-- who:resolveSource():grantQuest("tol-falas")
-- who:resolveSource():setQuestStatus("tol-falas", engine.Quest.DONE)
end,
}
-- ToME - Tales of Middle-Earth
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
load("/data/general/objects/objects.lua")
-- ToME - Tales of Middle-Earth
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
load("/data/general/traps/elemental.lua")
load("/data/general/traps/alarm.lua")
-- ToME - Tales of Middle-Earth
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
return {
name = "Mines of Moria",
level_range = {20, 30},
level_scheme = "player",
max_level = 4,
decay = {300, 800},
actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
width = 50, height = 50,
-- all_remembered = true,
all_lited = true,
-- persistant = "zone",
generator = {
map = {
class = "engine.generator.map.Forest",
edge_entrances = {4,6},
floor = "GRASS",
wall = "TREE",
up = "UP",
down = "DOWN",
},
--[[
actor = {
class = "engine.generator.actor.Random",
nb_npc = {40, 50},
},
object = {
class = "engine.generator.object.Random",
nb_object = {12, 16},
},
trap = {
class = "engine.generator.trap.Random",
nb_trap = {20, 30},
},
]]
},
levels =
{
[1] = {
generator = { map = {
up = "UP_WILDERNESS",
}, },
},
},
}
......@@ -31,15 +31,14 @@ return {
ambiant_music = "elven_town.ogg",
generator = {
map = {
class = "engine.generator.map.Roomer",
nb_rooms = 10,
class = "engine.generator.map.Forest",
edge_entrances = {4,6},
rooms = {"forest_clearing"},
['.'] = function() if rng.chance(20) then return "FLOWER" else return "GRASS" end end,
['#'] = "TREE",
zoom = 5,
noise = "fbm_perlin",
floor = function() if rng.chance(20) then return "FLOWER" else return "GRASS" end end,,
wall = "TREE",
up = "UP",
down = "DOWN",
door = "GRASS",
},
actor = {
class = "engine.generator.actor.Random",
......
......@@ -73,10 +73,10 @@ static int noise_simplex(lua_State *L)
static int noise_fbm_simplex(lua_State *L)
{
noise_t *n = (noise_t*)auxiliar_checkclass(L, "noise{core}", 1);
float octave = luaL_checknumber(L, 2);
float p[4];
int i;
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 3 + i);
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 2 + i);
float octave = luaL_checknumber(L, 2 + i);
lua_pushnumber(L, TCOD_noise_fbm_simplex(n->noise, p, octave));
return 1;
......@@ -85,10 +85,10 @@ static int noise_fbm_simplex(lua_State *L)
static int noise_turbulence_simplex(lua_State *L)
{
noise_t *n = (noise_t*)auxiliar_checkclass(L, "noise{core}", 1);
float octave = luaL_checknumber(L, 2);
float p[4];
int i;
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 3 + i);
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 2 + i);
float octave = luaL_checknumber(L, 2 + i);
lua_pushnumber(L, TCOD_noise_turbulence_simplex(n->noise, p, octave));
return 1;
......@@ -108,10 +108,10 @@ static int noise_perlin(lua_State *L)
static int noise_fbm_perlin(lua_State *L)
{
noise_t *n = (noise_t*)auxiliar_checkclass(L, "noise{core}", 1);
float octave = luaL_checknumber(L, 2);
float p[4];
int i;
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 3 + i);
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 2 + i);
float octave = luaL_checknumber(L, 2 + i);
lua_pushnumber(L, TCOD_noise_fbm_perlin(n->noise, p, octave));
return 1;
......@@ -120,10 +120,10 @@ static int noise_fbm_perlin(lua_State *L)
static int noise_turbulence_perlin(lua_State *L)
{
noise_t *n = (noise_t*)auxiliar_checkclass(L, "noise{core}", 1);
float octave = luaL_checknumber(L, 2);
float p[4];
int i;
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 3 + i);
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 2 + i);
float octave = luaL_checknumber(L, 2 + i);
lua_pushnumber(L, TCOD_noise_turbulence_perlin(n->noise, p, octave));
return 1;
......@@ -143,10 +143,10 @@ static int noise_wavelet(lua_State *L)
static int noise_fbm_wavelet(lua_State *L)
{
noise_t *n = (noise_t*)auxiliar_checkclass(L, "noise{core}", 1);
float octave = luaL_checknumber(L, 2);
float p[4];
int i;
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 3 + i);
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 2 + i);
float octave = luaL_checknumber(L, 2 + i);
lua_pushnumber(L, TCOD_noise_fbm_wavelet(n->noise, p, octave));
return 1;
......@@ -155,10 +155,10 @@ static int noise_fbm_wavelet(lua_State *L)
static int noise_turbulence_wavelet(lua_State *L)
{
noise_t *n = (noise_t*)auxiliar_checkclass(L, "noise{core}", 1);
float octave = luaL_checknumber(L, 2);
float p[4];
int i;
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 3 + i);
for (i = 0; i < n->ndim; i++) p[i] = luaL_checknumber(L, 2 + i);
float octave = luaL_checknumber(L, 2 + i);
lua_pushnumber(L, TCOD_noise_turbulence_wavelet(n->noise, p, octave));
return 1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment