diff --git a/game/engines/default/engine/Quest.lua b/game/engines/default/engine/Quest.lua index b74b3ef6ac680ea769486e8df02c8ebf1c47ee1c..194878bb6487a54648560c07b22d411192f45f8b 100644 --- a/game/engines/default/engine/Quest.lua +++ b/game/engines/default/engine/Quest.lua @@ -55,6 +55,17 @@ function _M:isCompleted(sub) if self.status == COMPLETED then return true else return false end end +--- Checks if the quest (or sub-objective) is failed +-- @param sub a subobjective id or nil for the whole quest +-- @return[1] false if objective is not failed +-- @return[2] true if objective failed +function _M:isFailed(sub) + if sub then + if self.objectives[sub] and self.objectives[sub] == FAILED then return true else return false end + end + if self.status == FAILED then return true else return false end +end + --- Checks if the quest is ended (DONE or FAILED) -- @return[1] false if quest didn't end -- @return[2] true if quest ended diff --git a/game/engines/default/engine/generator/map/Maze.lua b/game/engines/default/engine/generator/map/Maze.lua index d72efadd095186af604cd64a5ec0bb32fd0ddd8e..f086a69c9328ef493eedebeb2c62fff3e1e4523e 100644 --- a/game/engines/default/engine/generator/map/Maze.lua +++ b/game/engines/default/engine/generator/map/Maze.lua @@ -35,11 +35,17 @@ function _M:init(zone, map, grid_list, data) end function _M:generate(lev, old_lev) + local lastx, lasty = 0, 0 + local do_tile = function(i, j, wall) for ii = 0, self.data.widen_w-1 do for jj = 0, self.data.widen_h-1 do self.map(i*self.data.widen_w+ii, j*self.data.widen_h+jj, Map.TERRAIN, self:resolve(wall and "wall" or "floor")) end end self.map.room_map[i][j].maze_wall = wall + if not wall then + lastx = math.max(lastx, i) + lasty = math.max(lasty, j) + end end for i = 0, self.data.w - 1 do for j = 0, self.data.h - 1 do @@ -94,7 +100,8 @@ function _M:generate(lev, old_lev) end -- Always starts at 1, 1 local ux, uy = 1 * self.data.widen_w, 1 * self.data.widen_h - local dx, dy = math.floor(self.map.w/2)*2-1-2*(1-math.mod(self.map.w,2)), math.floor(self.map.h/2)*2-1-2*(1-math.mod(self.map.h,2)) + local dx, dy = lastx * self.data.widen_w, lasty * self.data.widen_h + -- local dx, dy = math.floor(self.map.w/2)*2-1-2*(1-math.mod(self.map.w,2)), math.floor(self.map.h/2)*2-1-2*(1-math.mod(self.map.h,2)) self.map(ux, uy, Map.TERRAIN, self:resolve("up")) self.map.room_map[ux][uy].special = "exit" if lev < self.zone.max_level or self.data.force_last_stair then diff --git a/game/engines/default/engine/generator/map/Static.lua b/game/engines/default/engine/generator/map/Static.lua index 929d1153b77948de88587d4fe25fdb36b96a4ba6..873a714f945b3baf2dbffaad394a7f5baefa4647 100644 --- a/game/engines/default/engine/generator/map/Static.lua +++ b/game/engines/default/engine/generator/map/Static.lua @@ -75,20 +75,24 @@ function _M:getLoader(t) trap_class = self.zone.trap_class, npc_class = self.zone.npc_class, object_class = self.zone.object_class, - specialList = function(kind, files, add_zone_lists) -- specify entity lists to use (add_zone_lists == add to current list) + specialList = function(kind, files, add_zone_lists) -- specify entity lists to use (add_zone_lists == include current list) local elist if kind == "terrain" then if add_zone_lists then elist = table.clone(self.zone.grid_list) end - self.grid_list = self.zone.grid_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) + self.grid_list = self.zone.grid_class:loadList(files, nil, elist, nil, elist and table.clone(elist.__loaded_files)) +-- self.grid_list = self.zone.grid_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) elseif kind == "trap" then if add_zone_lists then elist = table.clone(self.zone.trap_list) end - self.trap_list = self.zone.trap_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) + self.trap_list = self.zone.trap_class:loadList(files, nil, elist, nil, elist and table.clone(elist.__loaded_files)) +-- self.trap_list = self.zone.trap_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) elseif kind == "object" then if add_zone_lists then elist = table.clone(self.zone.object_list) end - self.object_list = self.zone.object_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) + self.object_list = self.zone.object_class:loadList(files, nil, elist, nil, elist and table.clone(elist.__loaded_files)) +-- self.object_list = self.zone.object_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) elseif kind == "actor" then if add_zone_lists then elist = table.clone(self.zone.npc_list) end - self.npc_list = self.zone.npc_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) + self.npc_list = self.zone.npc_class:loadList(files, nil, elist, nil, elist and table.clone(elist.__loaded_files)) +-- self.npc_list = self.zone.npc_class:loadList(files, nil, elist, nil, elist and elist.__loaded_files) else error("kind unsupported") end @@ -196,24 +200,23 @@ function _M:tmxLoad(file) end for _, tileset in ipairs(map:findAll("tileset")) do if tileset:findOne("properties") then for name, value in pairs(tileset:findOne("properties"):findAllAttrs("property", "name", "value")) do - -- setting .add_zone_lists = true in the file table causes the specified entity lists to be merged into a clone of the zone list local elist if name == "load_terrains" then local list = self:loadLuaInEnv(g, nil, "return "..value) or {} - if list.add_zone_lists then elist = table.clone(self.zone.grid_list) end - self.grid_list = self.zone.grid_class:loadList(list, nil, elist, nil, elist and elist.__loaded_files) + elist = table.clone(self.zone.grid_list, false) + self.grid_list = self.zone.grid_class:loadList(list, nil, elist, nil, elist and table.clone(elist.__loaded_files)) elseif name == "load_traps" then local list = self:loadLuaInEnv(g, nil, "return "..value) or {} - if list.add_zone_lists then elist = table.clone(self.zone.trap_list) end - self.trap_list = self.zone.trap_class:loadList(list, nil, elist, nil, elist and elist.__loaded_files) + elist = table.clone(self.zone.trap_list, false) + self.trap_list = self.zone.trap_class:loadList(list, nil, elist, nil, elist and table.clone(elist.__loaded_files)) elseif name == "load_objects" then local list = self:loadLuaInEnv(g, nil, "return "..value) or {} - if list.add_zone_lists then elist = table.clone(self.zone.object_list) end - self.object_list = self.zone.object_class:loadList(list, nil, elist, nil, elist and elist.__loaded_files) + elist = table.clone(self.zone.object_list, false) + self.object_list = self.zone.object_class:loadList(list, nil, elist, nil, elist and table.clone(elist.__loaded_files)) elseif name == "load_actors" then local list = self:loadLuaInEnv(g, nil, "return "..value) or {} - if list.add_zone_lists then elist = table.clone(self.zone.npc_list) end - self.npc_list = self.zone.npc_class:loadList(list, nil, elist, nil, elist and elist.__loaded_files) + elist = table.clone(self.zone.npc_list, false) + self.npc_list = self.zone.npc_class:loadList(list, nil, elist, nil, elist and table.clone(elist.__loaded_files)) end end end diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua index 8f20b253ef1599b423689d5d33970479d4a9ae4a..1ff80c6541d381f8b391dd98f5136f881071d3de 100644 --- a/game/engines/default/engine/utils.lua +++ b/game/engines/default/engine/utils.lua @@ -65,6 +65,16 @@ function table.concatNice(t, sep, endsep) return table.concat(t, sep, 1, #t - 1)..endsep..t[#t] end +function ripairs(t) + local i = #t + return function() + if i == 0 then return nil end + local oi = i + i = i - 1 + return oi, t[oi] + end +end + function table.count(t) local i = 0 for k, v in pairs(t) do @@ -2247,6 +2257,20 @@ function rng.poissonProcess(k, turn_scale, rate) return math.exp(-rate*turn_scale) * ((rate*turn_scale) ^ k)/ util.factorial(k) end +function rng.rarityTable(t, rarity_field) + if #t == 0 then return end + + rarity_field = rarity_field or "rarity" + local max = 0 + for _, e in ipairs(t) do max = max + e[rarity_field] end + local rt = {} + for _, e in ipairs(t) do + local nb = math.floor(max / e[rarity_field]) + for i = 1, nb do rt[#rt+1] = e end + end + return rng.table(rt) +end + function util.show_function_calls() debug.sethook(function(event, line) local t = debug.getinfo(2) diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 3e2722f453b40747c519d3c52e0e0848adfe0504..aa212831af370166c82020e8abb0930b67510fcd 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -2529,7 +2529,7 @@ function _M:onTakeHit(value, src, death_note) if self.clone_base then a = self.clone_base:clone() else a = self:clone() end a.life = math.max(1, self.life - value / 2) a.clone_on_hit.chance = math.ceil(self.clone_on_hit.chance / 2) - a.energy.val = 0 + a.energy.value = 0 a.exp_worth = 0.1 a.inven = {} a:removeAllMOs() @@ -3148,6 +3148,10 @@ function _M:die(src, death_note) elseif self.rank >= 3.2 and self.rank < 3.5 then p.all_kills_kind.rare = (p.all_kills_kind.rare or 0) + 1 elseif self.rank >= 3.5 then p.all_kills_kind.boss = (p.all_kills_kind.boss or 0) + 1 end + + if game.level and game.level.data.record_player_kills then + game.level.data.record_player_kills = game.level.data.record_player_kills + 1 + end end -- Ingredients diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 9975a8bd9293175930d298de1b13b9b95e089b76..8386e58940f1c015063f8ec0b9f512adc3f274f0 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -1780,7 +1780,7 @@ function _M:setupCommands() print("===============") end end, [{"_g","ctrl"}] = function() if config.settings.cheat then - self:changeLevel(1, "orcs+steam-quarry") + self:changeLevel(game.level.level + 1) do return end local o = game.zone:makeEntity(game.level, "object", {subtype="sling", random_object=true}, nil, true) if o then diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua index 9e0158042ababe868f55d331588ad51921f03912..e299eb8b9f14ade9c3951eea646048bd6df356f6 100644 --- a/game/modules/tome/class/GameState.lua +++ b/game/modules/tome/class/GameState.lua @@ -389,6 +389,7 @@ end -- @param data.lev = character level to generate for (affects point budget, #themes and #powers) <12-50> -- @param data.power_points_factor = lev based power points multiplier <1> -- @param data.nb_points_add = #extra budget points to spend on random powers <0> +-- @param data.nb_powers_add = #extra random powers to add <0> -- @param data.powers_special = function(p) that must return true on each random power to add (from base.randart_able) -- @param data.nb_themes = #power themes (power groups) for random powers to use <scales to 5 with lev> -- @param data.force_themes = additional power theme(s) to use for random powers = {"attack", "arcane", ...} @@ -1524,7 +1525,7 @@ function _M:entityFilterPost(zone, level, type, e, filter) return (not e.unique and e.randart_able) and (not e.material_level or e.material_level >= 1) and true or false end} } - local o = game.state:generateRandart(fil,nil, true) + local o = game.state:generateRandart(fil, nil, true) if o then -- print("[entityFilterPost]: Generated random object for", tostring(b.name)) o.unique, o.randart, o.rare = nil, nil, true @@ -1544,21 +1545,25 @@ function _M:entityFilterPost(zone, level, type, e, filter) e = self:createRandomBoss(e, table.merge(base, filter.random_elite, true)) end elseif type == "object" then - if filter.random_object and not e.unique and e.randart_able then - local data = _G.type(filter.random_object) == "table" and filter.random_object or {} - local lev = math.max(1, game.zone:level_adjust_level(game.level, game.zone, "object")) - print("[entityFilterPost]: Generating obsolete random_object") - print(debug.traceback()) - e = game.state:generateRandart{ - lev = lev, - egos = 0, - nb_powers_add = data.nb_powers_add or 2, - nb_points_add = data.nb_points_add or 4, -- ~1 ego Note: resolvers conflicts prevent specifying egos here - force_themes = data.force_themes or nil, - base = e, - post = function(o) o.rare = true o.unique = nil o.randart = nil end, - namescheme = 3 + if filter.random_object and not e.unique and e.randart_able then -- convert the object to a (weak) Randart + local f_data = _G.type(filter.random_object) == "table" and filter.random_object or {} + -- default parameters + local data = {base = e, egos = 1, nb_powers_add = 1, nb_points_add = 2, + lev = math.max(1, game.zone:level_adjust_level(game.level, game.zone, "object")), + post = function(o) + if f_data.post then f_data.post(o) end + o.rare = true o.unique = nil o.randart = nil + end, + namescheme = 3, } + -- update with filter specifications + table.merge(data, f_data, false, {base=true, post=true, base_filter=true}) + print("[entityFilterPost]: filter.random_object forcing conversion to Randart:", e.name) table.print(data) + e = game.state:generateRandart(data) + if not e then + print("[GameState:entityFilterPost] failed to generate random object, data:") table.print(data) + print("traceback:") print(debug.traceback()) + end end end return e @@ -2251,8 +2256,8 @@ function _M:locationRevealAround(x, y) game.level.map.lites(x, y, true) game.level.map.remembers(x, y, true) for _, c in pairs(util.adjacentCoords(x, y)) do - game.level.map.lites(x+c[1], y+c[2], true) - game.level.map.remembers(x+c[1], y+c[2], true) + game.level.map.lites(c[1], c[2], true) + game.level.map.remembers(c[1], c[2], true) end end @@ -2461,3 +2466,182 @@ function _M:allowOnlineEvent() if self.birth.grab_online_event_forbid then return end return true end + +function _M:infiniteDungeonChallenge(zone, lev, data, id_layout_name, id_grids_name) + if lev < 3 then return end + -- if not rng.percent(30 + lev) then return end + + local challenges = { + { id = "pacifist", rarity = 3 }, + { id = "exterminator", rarity = 1 }, + { id = "dream-horror", rarity = 10, min_lev = 15 }, + { id = "fast-exit", rarity = 3, min_lev = 8 }, + } + self:triggerHook{"InfiniteDungeon:getChallenges", challenges=challenges} + + for i, c in ripairs(challenges) do + if c.min_lev and lev < c.min_lev then table.remove(challenges, i) end + end + + local challenge = rng.rarityTable(challenges) + data.id_challenge = challenge.id + data.id_layout_name = id_layout_name + data.id_grids_name = id_grids_name + print("[INFINITE DUNGEON] Selected challenge", data.id_challenge) +end + +function _M:makeChallengeQuest(level, name, desc, data) + local q = { + id = "id-challenge-"..level.level, + name = "Level "..level.level.." Challenge: "..name, + challenge_desc = desc, + desc = function(self, who) + local desc = {} + desc[#desc+1] = self.challenge_desc + return table.concat(desc, "\n") + end, + on_status_change = function(self, who, status, sub) + if self:isCompleted() then + who:setQuestStatus(self.id, engine.Quest.DONE) + game:getPlayer(true):removeEffect(who.EFF_ZONE_AURA_CHALLENGE, true, true) + self:check("on_challenge_success", who) + elseif self:isFailed() then + game:getPlayer(true):removeEffect(who.EFF_ZONE_AURA_CHALLENGE, true, true) + self:check("on_challenge_failed", who) + end + end, + on_exit_level = function(self, who) + self:check("on_exit_check", who) + if self.status ~= self.DONE then + who:setQuestStatus(self.id, self.FAILED) + end + end, + on_challenge_success = function(self, who) + game.state:infiniteDungeonChallengeReward(self, who) + end, + popup_text = {}, + } + table.merge(q, data) + local p = game:getPlayer(true) + p:grantQuest(q) + game:onTickEnd(function() p:setEffect(p.EFF_ZONE_AURA_CHALLENGE, 1, {id_challenge_quest = q.id}) end) + return q +end + + +function _M:infiniteDungeonChallengeFinish(zone, level) + local id_challenge = level.data.id_challenge + if not id_challenge then return end + + if id_challenge == "pacifist" then + level.data.record_player_kills = 0 + self:makeChallengeQuest(level, "Pacifist", "Get to the end of the level without killing a single creature.", { + on_exit_check = function(self, who) + if not self.check_level then return end + if self.check_level.data.record_player_kills == 0 then who:setQuestStatus(self.id, self.COMPLETED) end + self.check_level = nil + end, + on_kill_foe = function(self, who, target) + who:setQuestStatus(self.id, self.FAILED) + end, + check_level = level, + }) + elseif id_challenge == "exterminator" then + self:makeChallengeQuest(level, "Exterminator", "Exit the level with no single foes left alive.", { + on_exit_check = function(self, who) + if not self.check_level then return end + local nb = 0 + for uid, e in pairs(self.check_level.entities) do + if who:reactionToward(e) < 0 then nb = nb + 1 break end + end + if nb == 0 then who:setQuestStatus(self.id, self.COMPLETED) end + self.check_level = nil + end, + on_kill_foe = function(self, who, target) + if not self.check_level then return end + local nb = 0 + for uid, e in pairs(self.check_level.entities) do + if who:reactionToward(e) < 0 then nb = nb + 1 break end + end + if nb == 0 then who:setQuestStatus(self.id, self.COMPLETED) end + end, + check_level = level, + }) + elseif id_challenge == "fast-exit" then + local a = require("engine.Astar").new(level.map, game:getPlayer(true)) + local path = a:calc(level.default_up.x, level.default_up.y, level.default_down.x, level.default_down.y) + if path and #path > 5 then + local turns = #path * 3 + self:makeChallengeQuest(level, "Rush Hour ("..turns..")", "Leave the level in less than "..turns.." turns (exit is revealed on your map).", { + turns_left = turns, + desc = function(self, who) + local desc = {} + desc[#desc+1] = self.challenge_desc + desc[#desc+1] = "" + desc[#desc+1] = "Turns left: #LIGHT_GREEN#"..self.turns_left + return table.concat(desc, "\n") + end, + on_exit_check = function(self, who) + if self.turns_left >= 0 then who:setQuestStatus(self.id, self.COMPLETED) end + end, + on_act_base = function(self, who) + self.turns_left = self.turns_left - 1 + if self.turns_left < 0 then + who:setQuestStatus(self.id, self.FAILED) + end + end, + }) + self:locationRevealAround(level.default_down.x, level.default_down.y) + end + elseif id_challenge == "dream-horror" then + local m = zone:makeEntity(level, "actor", {name="dreaming horror", random_boss=true}, nil, true) + if m then + local x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2) + local tries = 0 + while not m:canMove(x, y) and tries < 100 do + x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2) + tries = tries + 1 + end + if tries < 100 then + local q = self:makeChallengeQuest(level, "Dream Hunter", "Wake up and kill the dreaming horror boss '"..m.name.."'.", {}) + m.id_challenge_quest = q.id + m.on_die = function(self, who) + who:setQuestStatus(self.id_challenge_quest, engine.Quest.COMPLETED) + end + zone:addEntity(level, m, "actor", x, y) + end + end + else + self:triggerHook{"InfiniteDungeon:setupChallenge", id_challenge=id_challenge, zone=zone, level=level} + end +end + +function _M:infiniteDungeonChallengeReward(quest, who) + local rewards = { + {name = "Random Artifact", rarity=1, give=function(who) + local tries = 100 + while tries > 0 do + local o = game.zone:makeEntity(game.level, "object", {random_object={egos=rng.range(2,3), nb_powers_add=rng.range(10,30)}, properties={"randart_able"}}, nil, true) + if o then + o:identify(true) + who:addObject(who.INVEN_INVEN, o) + who:sortInven() + return "Random Artifact: "..o:getName{do_color=true} + end + end + -- Fallback + who.unused_stats = who.unused_stats + 3 + return "+3 Stat Points" + end}, + {name = "+3 Stat Points", rarity=3, give=function(who) who.unused_stats = who.unused_stats + 3 end}, + {name = "+1 Class Point", rarity=5, give=function(who) who.unused_talents = who.unused_talents + 1 end}, + {name = "+1 Generic Point", rarity=4, give=function(who) who.unused_generics = who.unused_generics + 1 end}, + {name = "+1 Category Point", rarity=30, give=function(who) who.unused_talents_types = who.unused_talents_types + 1 end}, + {name = "+1 Prodigy Point", rarity=60, give=function(who) who.unused_prodigies = who.unused_prodigies + 1 end}, + } + self:triggerHook{"InfiniteDungeon:getRewards", rewards=rewards} + + local reward = rng.rarityTable(rewards) + reward.name = reward.give(who) or reward.name + quest.popup_text[engine.Quest.DONE] = "#OLIVE_DRAB#Reward: "..reward.name +end diff --git a/game/modules/tome/data/gfx/effects/zone_aura_challenge.png b/game/modules/tome/data/gfx/effects/zone_aura_challenge.png new file mode 100644 index 0000000000000000000000000000000000000000..fbe56c3cbda0e5bf317782a12d51ffae7e679188 Binary files /dev/null and b/game/modules/tome/data/gfx/effects/zone_aura_challenge.png differ diff --git a/game/modules/tome/data/maps/vaults/test2.tmx b/game/modules/tome/data/maps/vaults/test2.tmx index 8002a4e0245b4d8e6a6fe73538022b7ee724bc6f..fe72626aef0e5c41b2256e21db59f105deafc5cd 100644 --- a/game/modules/tome/data/maps/vaults/test2.tmx +++ b/game/modules/tome/data/maps/vaults/test2.tmx @@ -125,7 +125,7 @@ <tileset firstgid="101" name="Trees" tilewidth="64" tileheight="64" tilecount="100"> <properties> <property name="load_terrains" value="{"/data/general/grids/forest.lua", "/data/general/grids/autumn_forest.lua", "/data/general/grids/snowy_forest.lua", "/data/general/grids/lava.lua", add_zone_lists=true}"/> - <property name="load_actors" value="{"/data/general/npcs/cold-drake.lua", "/data/general/npcs/vampire.lua", add_zone_lists=false}"/> + <property name="load_actors" value="{"/data/general/npcs/cold-drake.lua", "/data/general/npcs/vampire.lua"}"/> </properties> <image source="../../../../../../tiled-maps/gfx/vault_trees.png" width="640" height="640"/> <tile id="0"> diff --git a/game/modules/tome/data/talents/celestial/hymns.lua b/game/modules/tome/data/talents/celestial/hymns.lua index 28de24d7c15ff79578478ae2f0c248f34b1b3de8..a9bd8e19bf902ed1d3b41c438b6aa61d74fa37dc 100644 --- a/game/modules/tome/data/talents/celestial/hymns.lua +++ b/game/modules/tome/data/talents/celestial/hymns.lua @@ -172,7 +172,7 @@ newTalent{ if self:getNegative() < t.getNegativeDrain(self, t) then return end local tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, 5, true) + local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do local a = game.level.map(x, y, Map.ACTOR) if a and self:reactionToward(a) < 0 then diff --git a/game/modules/tome/data/talents/misc/npcs.lua b/game/modules/tome/data/talents/misc/npcs.lua index 31de27cb0a8c01c1ca8323a2bdd2770375d5bae3..da99a95ce0c53c5e9036bda91b205b9b4d1263a9 100644 --- a/game/modules/tome/data/talents/misc/npcs.lua +++ b/game/modules/tome/data/talents/misc/npcs.lua @@ -68,7 +68,7 @@ newTalent{ local a if self.clone_base then a = self.clone_base:clone() else a = self:clone() end a.can_multiply = a.can_multiply - 1 - a.energy.val = 0 + a.energy.value = 0 a.exp_worth = 0.1 a.inven = {} a.x, a.y = nil, nil diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua index 2426a14f2c1cb5fe0cb1f30e40a62b22cfc1870c..1dd999ba5000b23adcc34e0735313209e5de1654 100644 --- a/game/modules/tome/data/timed_effects/other.lua +++ b/game/modules/tome/data/timed_effects/other.lua @@ -3042,6 +3042,33 @@ newEffect{ end, } +newEffect{ + name = "ZONE_AURA_CHALLENGE", + desc = "Challenge", + no_stop_enter_worlmap = true, + long_desc = function(self, eff) if not eff.id_challenge_quest or not self:hasQuest(eff.id_challenge_quest) then return "???" else return self:hasQuest(eff.id_challenge_quest).name end end, + decrease = 0, no_remove = true, + type = "other", + subtype = { aura=true }, + status = "neutral", + zone_wide_effect = true, + parameters = {}, + activate = function(self, eff) + end, + deactivate = function(self, eff) + if not eff.id_challenge_quest or not self:hasQuest(eff.id_challenge_quest) then return end + self:hasQuest(eff.id_challenge_quest):check("on_exit_level", self) + end, + callbackOnKill = function(self, eff, who, death_note) + if not eff.id_challenge_quest or not self:hasQuest(eff.id_challenge_quest) then return end + self:hasQuest(eff.id_challenge_quest):check("on_kill_foe", self) + end, + callbackOnActBase = function(self, eff) + if not eff.id_challenge_quest or not self:hasQuest(eff.id_challenge_quest) then return end + self:hasQuest(eff.id_challenge_quest):check("on_act_base", self) + end, +} + newEffect{ name = "THROWING_KNIVES", image = "talents/throwing_knives.png", desc = "Throwing Knives", decrease = 0, diff --git a/game/modules/tome/data/zones/infinite-dungeon/grids.lua b/game/modules/tome/data/zones/infinite-dungeon/grids.lua index 09827e217f3b1f79ff8dff9458a24ddc22aaa230..f551229ce3707ec258157d8b4e338af7b40b1588 100644 --- a/game/modules/tome/data/zones/infinite-dungeon/grids.lua +++ b/game/modules/tome/data/zones/infinite-dungeon/grids.lua @@ -22,21 +22,279 @@ load("/data/general/grids/water.lua") load("/data/general/grids/forest.lua") load("/data/general/grids/lava.lua") load("/data/general/grids/sand.lua") +load("/data/general/grids/underground.lua") +load("/data/general/grids/slime.lua") +load("/data/general/grids/jungle.lua") +load("/data/general/grids/cave.lua") +load("/data/general/grids/burntland.lua") +load("/data/general/grids/mountain.lua") +load("/data/general/grids/void.lua") +load("/data/general/grids/autumn_forest.lua") +load("/data/general/grids/snowy_forest.lua") -newEntity{base = "FLOOR", define_as = "ITEMS_VAULT"} -load("/data-items-vault/entities/fortress-grids.lua", function(e) if e.image == "terrain/solidwall/solid_floor1.png" then e.image = "terrain/marble_floor.png" end end) +newEntity{ + define_as = "GRASS_ROCK", + type = "wall", subtype = "grass", + name = "huge loose rock", image = "terrain/grass.png", add_mos = {{image="terrain/huge_rock.png"}}, + display = '+', color=colors.GREY, back_color={r=44,g=95,b=43}, + notice = true, + always_remember = true, + block_sight = true, + is_door = true, + door_opened = "GRASS", + dig = "GRASS", + nice_editer = { method="borders_def", def="grass"}, +} + +newEntity{ + define_as = "UNDERGROUND_ROCK", + type = "wall", subtype = "underground", + name = "huge loose rock", image = "terrain/underground_floor.png", add_mos = {{image="terrain/huge_rock.png"}}, + display = '+', color=colors.GREY, back_color={r=44,g=95,b=43}, + notice = true, + always_remember = true, + block_sight = true, + is_door = true, + door_opened = "UNDERGROUND_FLOOR", + dig = "UNDERGROUND_FLOOR", +} + +newEntity{ + define_as = "CRYSTAL_ROCK", + type = "wall", subtype = "crystal", + name = "huge loose rock", image = "terrain/crystal_floor1.png", add_mos = {{image="terrain/huge_rock.png"}}, + display = '+', color=colors.GREY, back_color={r=44,g=95,b=43}, + notice = true, + always_remember = true, + block_sight = true, + is_door = true, + door_opened = "CRYSTAL_FLOOR", + dig = "CRYSTAL_FLOOR", +} + +newEntity{ + define_as = "DESERT_ROCK", + type = "wall", subtype = "sand", + name = "huge loose rock", image = "terrain/sandfloor.png", add_mos = {{image="terrain/huge_rock.png"}}, + display = '+', color=colors.GREY, back_color={r=44,g=95,b=43}, + notice = true, + always_remember = true, + block_sight = true, + is_door = true, + door_opened = "SAND", + dig = "SAND", +} -for id, i in ipairs{1, 10, 20, 30, 40} do newEntity{ - define_as = "ID_HISTORY"..i, - name = "The Hunter and the Hunted", lore="infinite-dungeon-history-"..id, - desc = [[The infinite hunt.]], - image = "terrain/marble_floor.png", - display = '_', color=colors.GREEN, back_color=colors.DARK_GREY, - add_displays = {class.new{image="terrain/signpost.png"}}, + define_as = "CAVE_ROCK", + type = "wall", subtype = "grass", + name = "huge loose rock", image = "terrain/cave/cave_floor_1_01.png", add_mos = {{image="terrain/huge_rock.png"}}, + display = '+', color=colors.GREY, back_color={r=44,g=95,b=43}, + notice = true, always_remember = true, - on_move = function(self, x, y, who) - if who.player then game.party:learnLore(self.lore) end - end, + block_sight = true, + is_door = true, + door_opened = "CAVEFLOOR", + dig = "CAVEFLOOR", } + +newEntity{ + define_as = "JUNGLE_ROCK", + type = "wall", subtype = "grass", + name = "huge loose rock", image = "terrain/jungle/jungle_grass_floor_01.png", add_mos = {{image="terrain/huge_rock.png"}}, + display = '+', color=colors.GREY, back_color={r=44,g=95,b=43}, + notice = true, + always_remember = true, + block_sight = true, + is_door = true, + door_opened = "JUNGLE_GRASS", + dig = "JUNGLE_GRASS", +} + +-- add snowy door +newEntity{ + define_as = "SNOWY_GRASS_2", + type = "floor", subtype = "snowy_grass", + name = "snowy grass", image = "terrain/grass/snowy_grass_main_01.png", + display = '.', color=colors.LIGHT_GREEN, back_color={r=44,g=95,b=43}, + grow = "SNOWY_TREE_2", + nice_tiler = { method="replace", base={"SNOWY_PATCH_2", 100, 1, 14}}, + nice_editer = snowy_editer, +} +for i = 1, 14 do newEntity{ base = "SNOWY_GRASS_2", define_as = "SNOWY_PATCH_2"..i, image = ("terrain/grass/snowy_grass_main_%02d.png"):format(i) } end + +local snowy_treesdef = { + {"small_elm", {"shadow", "trunk", "foliage_winter"}}, + {"elm", {tall=-1, "shadow", "trunk", "foliage_winter"}}, +} + +newEntity{ + define_as = "SNOWY_TREE_2", + type = "wall", subtype = "snowy_grass", + name = "winter tree", + image = "terrain/snowy_tree.png", + display = '#', color=colors.LIGHT_GREEN, back_color={r=44,g=95,b=43}, + always_remember = true, + can_pass = {pass_tree=1}, + does_block_move = true, + block_sight = true, + dig = "SNOWY_GRASS_2", + nice_tiler = { method="replace", base={"SNOWY_TREE_2", 100, 1, 30}}, + nice_editer = snowy_editer, +} +for i = 1, 30 do + newEntity(class:makeNewTrees({base="SNOWY_TREE_2", define_as = "SNOWY_TREE_2"..i, image = "terrain/grass/snowy_grass_main_01.png"}, snowy_treesdef)) end + +newEntity{ + define_as = "RIFT2", + name = "Temporal Rift", add_mos={{image="terrain/demon_portal2.png"}}, + display = '&', color_r=255, color_g=0, color_b=220, back_color=colors.VIOLET, + notice = true, + always_remember = true, + show_tooltip = true, + desc = [[The rift leads to another floor of the dungeon.]], + change_level = 1, +} + +local rift_editer = { method="sandWalls_def", def="rift"} + +newEntity{ + define_as = "SPACETIME_RIFT2", + type = "wall", subtype = "rift", + name = "crack in spacetime", + display = '#', color=colors.YELLOW, image="terrain/rift/rift_inner_05_01.png", + always_remember = true, + does_block_move = true, + _noalpha = false, + dig = "VOID", + block_sight = true, + nice_editer = rift_editer, +} + +------------------------------------------------------------ +-- To fake people out. +------------------------------------------------------------ + +newEntity{ + define_as = "WATER_FLOOR_FAKE", + type = "floor", subtype = "underwater", + name = "underwater", image = "terrain/underwater/subsea_floor_02.png", + display = '.', color=colors.LIGHT_BLUE, back_color=colors.DARK_BLUE, + nice_tiler = { method="replace", base={"WATER_FLOOR_FAKE", 10, 1, 5}}, +} +for i = 1, 5 do newEntity{ base="WATER_FLOOR_FAKE", define_as = "WATER_FLOOR_FAKE"..i, image = "terrain/underwater/subsea_floor_02"..string.char(string.byte('a')+i-1)..".png" } end + +newEntity{ + define_as = "WATER_WALL_FAKE", + type = "wall", subtype = "underwater", + name = "coral wall", image = "terrain/underwater/subsea_granite_wall1.png", + display = '#', color=colors.AQUAMARINE, back_color=colors.DARK_BLUE, + always_remember = true, + can_pass = {pass_wall=1}, + does_block_move = true, + block_sight = true, + z = 3, + nice_tiler = { method="wall3d", inner={"WATER_WALL_FAKE", 100, 1, 5}, north={"WATER_WALL_NORTH_FAKE", 100, 1, 5}, south={"WATER_WALL_SOUTH_FAKE", 10, 1, 14}, north_south="WATER_WALL_NORTH_SOUTH_FAKE", small_pillar="WATER_WALL_SMALL_PILLAR_FAKE", pillar_2="WATER_WALL_PILLAR_2_FAKE", pillar_8={"WATER_WALL_PILLAR_8_FAKE", 100, 1, 5}, pillar_4="WATER_WALL_PILLAR_4_FAKE", pillar_6="WATER_WALL_PILLAR_6_FAKE" }, + always_remember = true, + does_block_move = true, + can_pass = {pass_wall=1}, + block_sight = true, + dig = "WATER_FLOOR_FAKE", +} + +for i = 1, 5 do + newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_FAKE"..i, image = "terrain/underwater/subsea_granite_wall1_"..i..".png", z = 3} + newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_NORTH_FAKE"..i, image = "terrain/underwater/subsea_granite_wall1_"..i..".png", z = 3, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall3.png", z=18, display_y=-1}}} + newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_PILLAR_8_FAKE"..i, image = "terrain/underwater/subsea_granite_wall1_"..i..".png", z = 3, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall_pillar_8.png", z=18, display_y=-1}}} +end +newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_NORTH_SOUTH_FAKE", image = "terrain/underwater/subsea_granite_wall2.png", z = 3, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall3.png", z=18, display_y=-1}}} +newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_SOUTH_FAKE", image = "terrain/underwater/subsea_granite_wall2.png", z = 3} +for i = 1, 14 do newEntity{ base = "WATER_WALL", define_as = "WATER_WALL_SOUTH_FAKE"..i, image = "terrain/underwater/subsea_granite_wall2_"..i..".png", z = 3} end +newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_SMALL_PILLAR_FAKE", image = "terrain/underwater/subsea_floor_02.png", z=1, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall_pillar_small.png",z=3}, class.new{image="terrain/underwater/subsea_granite_wall_pillar_small_top.png", z=18, display_y=-1}}} +newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_PILLAR_6_FAKE", image = "terrain/underwater/subsea_floor_02.png", z=1, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall_pillar_3.png",z=3}, class.new{image="terrain/underwater/subsea_granite_wall_pillar_9.png", z=18, display_y=-1}}} +newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_PILLAR_4_FAKE", image = "terrain/underwater/subsea_floor_02.png", z=1, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall_pillar_1.png",z=3}, class.new{image="terrain/underwater/subsea_granite_wall_pillar_7.png", z=18, display_y=-1}}} +newEntity{ base = "WATER_WALL_FAKE", define_as = "WATER_WALL_PILLAR_2_FAKE", image = "terrain/underwater/subsea_floor_02.png", z=1, add_displays = {class.new{image="terrain/underwater/subsea_granite_wall_pillar_2.png",z=3}}} + + +newEntity{ + define_as = "WATER_DOOR_FAKE", + type = "wall", subtype = "underwater", + name = "door", image = "terrain/underwater/subsea_stone_wall_door_closed.png", + display = '+', color_r=238, color_g=154, color_b=77, back_color=colors.DARK_UMBER, + nice_tiler = { method="door3d", north_south="WATER_DOOR_VERT_FAKE", west_east="WATER_DOOR_HORIZ_FAKE" }, + notice = true, + always_remember = true, + block_sight = true, + is_door = true, + door_opened = "WATER_DOOR_OPEN_FAKE", + dig = "WATER_FLOOR_FAKE", +} +newEntity{ + define_as = "WATER_DOOR_OPEN_FAKE", + type = "wall", subtype = "underwater", + name = "open door", image="terrain/underwater/subsea_granite_door1_open.png", + display = "'", color_r=238, color_g=154, color_b=77, back_color=colors.DARK_GREY, + always_remember = true, + is_door = true, + door_closed = "WATER_DOOR_FAKE", +} +newEntity{ base = "WATER_DOOR_FAKE", define_as = "WATER_DOOR_HORIZ_FAKE", image = "terrain/underwater/subsea_stone_wall_door_closed.png", add_displays = {class.new{image="terrain/underwater/subsea_granite_wall3.png", z=18, display_y=-1}}, door_opened = "WATER_DOOR_HORIZ_OPEN_FAKE"} +newEntity{ base = "WATER_DOOR_OPEN_FAKE", define_as = "WATER_DOOR_HORIZ_OPEN_FAKE", image = "terrain/underwater/subsea_floor_02.png", add_displays = {class.new{image="terrain/underwater/subsea_stone_store_open.png", z=17}, class.new{image="terrain/underwater/subsea_granite_wall3.png", z=18, display_y=-1}}, door_closed = "WATER_DOOR_HORIZ_FAKE"} +newEntity{ base = "WATER_DOOR_FAKE", define_as = "WATER_DOOR_VERT_FAKE", image = "terrain/underwater/subsea_floor_02.png", add_displays = {class.new{image="terrain/underwater/subsea_granite_door1_vert.png", z=17}, class.new{image="terrain/underwater/subsea_granite_door1_vert_north.png", z=18, display_y=-1}}, door_opened = "WATER_DOOR_OPEN_VERT_FAKE", dig = "WATER_DOOR_OPEN_VERT_FAKE"} +newEntity{ base = "WATER_DOOR_OPEN_FAKE", define_as = "WATER_DOOR_OPEN_VERT_FAKE", image = "terrain/underwater/subsea_floor_02.png", add_displays = {class.new{image="terrain/underwater/subsea_granite_door1_open_vert.png", z=17}, class.new{image="terrain/underwater/subsea_granite_door1_open_vert_north.png", z=18, display_y=-1}}, door_closed = "WATER_DOOR_VERT_FAKE"} + +newEntity{ + define_as = "WATER_DOWN_FAKE", + image = "terrain/underwater/subsea_floor_02.png", add_mos = {{image="terrain/underwater/subsea_stair_down_03_64.png"}}, + name = "next level", + display = '>', color_r=255, color_g=255, color_b=0, + notice = true, + always_remember = true, + change_level = 1, +} + +local molten_lava_editer = {method="borders_def", def="molten_lava"} +local lava_editer = {method="borders_def", def="lava"} +local lava_mountain_editer = {method="borders_def", def="lava_mountain"} + +newEntity{ + define_as = "LAVA_FLOOR_FAKE", + type = "floor", subtype = "lava", + name = "lava floor", image = "terrain/lava_floor.png", + display = '.', color=colors.RED, back_color=colors.DARK_GREY, + shader = "lava", + nice_tiler = { method="replace", base={"LAVA_FLOOR_FAKE", 100, 1, 16}}, + nice_editer = lava_editer, +} +for i = 1, 16 do newEntity{ base = "LAVA_FLOOR_FAKE", define_as = "LAVA_FLOOR_FAKE"..i, image = "terrain/lava/lava_floor"..i..".png" } end + +newEntity{ + define_as = "LAVA_WALL_FAKE", + type = "wall", subtype = "lava", + name = "lava wall", image = "terrain/lava/lava_mountain5.png", + display = '#', color=colors.RED, back_color=colors.DARK_GREY, + always_remember = true, + does_block_move = true, + block_sight = true, + nice_editer = lava_mountain_editer, + nice_tiler = { method="replace", base={"LAVA_WALL_FAKE", 70, 1, 6} }, + dig = "LAVA_FLOOR_FAKE", +} +for i = 1, 6 do newEntity{ base="LAVA_WALL_FAKE", define_as = "LAVA_WALL_FAKE"..i, image = "terrain/lava/lava_mountain5_"..i..".png"} end + +newEntity{ + define_as = "LAVA_DOWN_FAKE", + type = "floor", subtype = "lava", + name = "next level", image = "terrain/lava_floor.png", add_mos = {{image="terrain/stair_down.png"}}, + display = '.', color=colors.RED, back_color=colors.DARK_GREY, + shader = "lava", + nice_tiler = { method="replace", base={"LAVA_FLOOR_FAKE", 100, 1, 16}}, + nice_editer = lava_editer, + notice = true, + always_remember = true, + change_level = 1, +} + +newEntity{base = "FLOOR", define_as = "ITEMS_VAULT"} +load("/data-items-vault/entities/fortress-grids.lua", function(e) if e.image == "terrain/solidwall/solid_floor1.png" then e.image = "terrain/marble_floor.png" end end) diff --git a/game/modules/tome/data/zones/infinite-dungeon/objects.lua b/game/modules/tome/data/zones/infinite-dungeon/objects.lua index 2db5eaafa68549c97c4ddb6bd054e89063a936fb..fa570ece0be64d02349d06abf3f02208d3d64ff9 100644 --- a/game/modules/tome/data/zones/infinite-dungeon/objects.lua +++ b/game/modules/tome/data/zones/infinite-dungeon/objects.lua @@ -20,6 +20,17 @@ load("/data/general/objects/objects-maj-eyal.lua") load("/data/general/objects/objects-far-east.lua") +for id, i in ipairs{1, 10, 20, 30, 40} do +newEntity{ base = "BASE_LORE", + define_as = "ID_HISTORY"..i, + name = "The Hunter and the Hunted", lore="infinite-dungeon-history-"..id, + desc = [[The infinite hunt.]], + image = "terrain/signpost.png", + rarity = false, + encumberance = 0, +} +end + newEntity{ power_source = {technique=true}, unique = true, diff --git a/game/modules/tome/data/zones/infinite-dungeon/zone.lua b/game/modules/tome/data/zones/infinite-dungeon/zone.lua index 62dac442bc4a3bb2d5e4d413685a39613f8ec976..0474b67fb28b354b8d12fc4b34157a2226a97bd7 100644 --- a/game/modules/tome/data/zones/infinite-dungeon/zone.lua +++ b/game/modules/tome/data/zones/infinite-dungeon/zone.lua @@ -95,6 +95,135 @@ return { nb_trap = {0, 0}, }, }, + alter_level_data = function(zone, lev, data) + if lev < 3 or rng.percent(30) then game.state:infiniteDungeonChallenge(zone, lev, data, "default", "default") return end + + -- Randomize the size of the dungeon, increasing it slightly as the game progresses. + -- Also change enemy count to fit with the new size. + local size = 50 + local vx = math.ceil(math.random(0.75, 1.25) * size) + local vy = math.ceil(math.random(0.75, 1.25) * size) + + -- Takent from random zone generation, modified slightly for use here. + -- Grab a random layout for the floor. + local layouts = { + { + id_layout_name = "forest", + class = "engine.generator.map.Forest", + edge_entrances = rng.table{{2,8}, {4,6}, {6,4}, {8,2}}, + zoom = rng.range(2,6), + sqrt_percent = rng.range(30, 50), + sqrt_percent = rng.range(5, 10), + noise = "fbm_perlin", + }, + { + id_layout_name = "cavern", + class = "engine.generator.map.Cavern", + zoom = math.random(10, 20), + min_floor = math.floor(rng.range(vx * vy * 0.4 / 2, vx * vy * 0.4)), + }, + { + id_layout_name = "default", + class = "engine.generator.map.Roomer", + nb_rooms = 14, + rooms = {"random_room", {"pit",3}, {"greater_vault",7}}, + rooms_config = {pit={filters={}}}, + lite_room_chance = 50, + }, + { + id_layout_name = "maze", + class = "engine.generator.map.Maze", + widen_w = math.random(1,7), widen_h = math.random(1,7), + }, + { + id_layout_name = "town", + class = "engine.generator.map.Town", + building_chance = math.random(50,90), + max_building_w = math.random(5,11), max_building_h = math.random(5,11), + edge_entrances = {6,4}, + nb_rooms = math.random(1,2), + rooms = {{"greater_vault",2}}, + }, + { + id_layout_name = "building", + class = "engine.generator.map.Building", + lite_room_chance = rng.range(0, 100), + max_block_w = rng.range(7, 20), max_block_h = rng.range(7, 20), + max_building_w = rng.range(2, 8), max_building_h = rng.range(2, 8), + }, + { + id_layout_name = "octopus", + class = "engine.generator.map.Octopus", + main_radius = {0.3, 0.4}, + arms_radius = {0.1, 0.2}, + arms_range = {0.7, 0.8}, + nb_rooms = {3, 9}, + }, + { + id_layout_name = "hexa", + class = "engine.generator.map.Hexacle", + segment_wide_chance = 70, + nb_segments = 8, + nb_layers = 6, + segment_miss_percent = 10, + force_square_size = true, + }, + } + zone:triggerHook{"InfiniteDungeon:getLayouts", layouts=layouts} + + local layout = rng.table(layouts) + data.generator.map = layout + + local vgrids = { + {id_grids_name="tree", floor="GRASS", wall="TREE", door="GRASS_ROCK", down="GRASS_DOWN2"}, + {id_grids_name="wall", floor="FLOOR", wall="WALL", door="DOOR", down="DOWN"}, + {id_grids_name="underground", floor="UNDERGROUND_FLOOR", wall="UNDERGROUND_TREE", door="UNDERGROUND_ROCK", down="UNDERGROUND_LADDER_DOWN"}, + {id_grids_name="crystals", floor="CRYSTAL_FLOOR", wall={"CRYSTAL_WALL","CRYSTAL_WALL2","CRYSTAL_WALL3","CRYSTAL_WALL4","CRYSTAL_WALL5","CRYSTAL_WALL6","CRYSTAL_WALL7","CRYSTAL_WALL8","CRYSTAL_WALL9","CRYSTAL_WALL10","CRYSTAL_WALL11","CRYSTAL_WALL12","CRYSTAL_WALL13","CRYSTAL_WALL14","CRYSTAL_WALL15","CRYSTAL_WALL16","CRYSTAL_WALL17","CRYSTAL_WALL18","CRYSTAL_WALL19","CRYSTAL_WALL20",}, door="CRYSTAL_ROCK", down="CRYSTAL_LADDER_DOWN"}, + {id_grids_name="sand", floor="UNDERGROUND_SAND", wall="SANDWALL", door="UNDERGROUND_SAND", down="SAND_LADDER_DOWN"}, + {id_grids_name="desert", floor="SAND", wall="PALMTREE", door="DESERT_ROCK", down="SAND_DOWN2"}, + {id_grids_name="slime", floor="SLIME_FLOOR", wall="SLIME_WALL", door="SLIME_DOOR", down="SLIME_DOWN"}, + {id_grids_name="jungle", floor="JUNGLE_GRASS", wall="JUNGLE_TREE", door="JUNGLE_ROCK", down="JUNGLE_GRASS_DOWN2"}, + {id_grids_name="cave", floor="CAVEFLOOR", wall="CAVEWALL", door="CAVE_ROCK", down="CAVE_LADDER_DOWN"}, + {id_grids_name="burntland", floor="BURNT_GROUND", wall="BURNT_TREE", door="BURNT_GROUND", down="BURNT_DOWN6"}, + {id_grids_name="mountain", floor="ROCKY_GROUND", wall="MOUNTAIN_WALL", door="ROCKY_GROUND", down="ROCKY_DOWN2"}, + {id_grids_name="mountain_forest", floor="ROCKY_GROUND", wall="ROCKY_SNOWY_TREE", door="ROCKY_GROUND", down="ROCKY_DOWN2"}, + {id_grids_name="snowy_forest", floor="SNOWY_GRASS_2", wall="SNOWY_TREE_2", door="SNOWY_GRASS_2", down="snowy_DOWN2"}, + {id_grids_name="temporal_void", floor="VOID", wall="SPACETIME_RIFT2", door="VOID", down="RIFT2"}, + {id_grids_name="water", floor="WATER_FLOOR_FAKE", wall="WATER_WALL_FAKE", door="WATER_DOOR_FAKE", down="WATER_DOWN_FAKE"}, + {id_grids_name="lava", floor="LAVA_FLOOR_FAKE", wall="LAVA_WALL_FAKE", door="LAVA_FLOOR_FAKE", down="LAVA_DOWN_FAKE"}, + {id_grids_name="autumn_forest", floor="AUTUMN_GRASS", wall="AUTUMN_TREE", door="AUTUMN_GRASS", down="AUTUMN_GRASS_DOWN2"}, + } + zone:triggerHook{"InfiniteDungeon:getGrids", grids=vgrids} + local vgrid = rng.table(vgrids) + + data.generator.map.floor = vgrid.floor + data.generator.map['.'] = vgrid.floor + data.generator.map.external_floor = vgrid.floor + data.generator.map.wall = vgrid.wall + data.generator.map['#'] = vgrid.wall + data.generator.map.up = vgrid.floor + data.generator.map.down = vgrid.down + data.generator.map.door = vgrid.door + data.generator.map["'"] = vgrid.door + + data.width = vx + data.height = vy + if data.generator.map.widen_w then + -- Special sanity check. Maze generation tends to... mess up if their height/width values aren't multiplies of the tunnel sizes. + while data.width % data.generator.map.widen_w ~= 0 do data.width = data.width + 1 end + while data.height % data.generator.map.widen_h ~= 0 do data.height = data.height + 1 end + end + + if layout.force_square_size then + data.width = math.max(vx, vy) + data.height = data.width + end + + local enemy_count = math.ceil((vx + vy) * 0.35) + data.generator.actor.nb_npc = {enemy_count-5, enemy_count+5} + + game.state:infiniteDungeonChallenge(zone, lev, data, data.generator.map.id_layout_name, vgrid.id_grids_name) + end, post_process = function(level) -- Provide some achievements if level.level == 10 then world:gainAchievement("INFINITE_X10", game.player) @@ -119,15 +248,17 @@ return { -- Some lore if level.level == 1 or level.level == 10 or level.level == 20 or level.level == 30 or level.level == 40 then - local l = game.zone:makeEntityByName(level, "terrain", "ID_HISTORY"..level.level) + local l = game.zone:makeEntityByName(level, "object", "ID_HISTORY"..level.level) if not l then return end for _, coord in pairs(util.adjacentCoords(level.default_up.x, level.default_up.y)) do if game.level.map:isBound(coord[1], coord[2]) and (i ~= 0 or j ~= 0) and not game.level.map:checkEntity(coord[1], coord[2], engine.Map.TERRAIN, "block_move") then - game.zone:addEntity(level, l, "terrain", coord[1], coord[2]) + game.zone:addEntity(level, l, "object", coord[1], coord[2]) return end end end + + game.state:infiniteDungeonChallengeFinish(game.zone, level) end, } diff --git a/game/modules/tome/data/zones/test/zone.lua b/game/modules/tome/data/zones/test/zone.lua index 285fa1b5ddb950fbbcfe10abf255344d93ba9dab..85a813776e270f02c12d8c0ede597357dc733e0e 100644 --- a/game/modules/tome/data/zones/test/zone.lua +++ b/game/modules/tome/data/zones/test/zone.lua @@ -80,8 +80,9 @@ return { nb_rooms = 10, edge_entrances = {4,6}, rooms = {"forest_clearing"}, --- required_rooms = {"greater_vault"}, -- triggers level generation failure - greater_vaults_list = {"portal-vault"}, + required_rooms = {"greater_vault", "greater_vault", "greater_vault"}, -- triggers level generation failure +-- greater_vaults_list = {"portal-vault"}, + greater_vaults_list = {"test2", "test"}, ['.'] = {"GRASS"}, ['#'] = "TREE", up = "GRASS_UP4", diff --git a/game/modules/tome/dialogs/Birther.lua b/game/modules/tome/dialogs/Birther.lua index 1e72ff009d981ab978e4a5160aa75a37eaaffcaa..9aa40c94e5e50be2e77260c1cb95766551c1e250 100644 --- a/game/modules/tome/dialogs/Birther.lua +++ b/game/modules/tome/dialogs/Birther.lua @@ -330,7 +330,8 @@ end --- Make a default character when using cheat mode, for easier testing function _M:makeDefault() self:setDescriptor("sex", "Female") - self:setDescriptor("world", "Maj'Eyal") + -- self:setDescriptor("world", "Maj'Eyal") + self:setDescriptor("world", "Infinite") self:setDescriptor("difficulty", "Normal") self:setDescriptor("permadeath", "Adventure") self:setDescriptor("race", "Human") diff --git a/game/modules/tome/dialogs/GameOptions.lua b/game/modules/tome/dialogs/GameOptions.lua index 453bc9aeb32764fd612b0283adc0abd815dcc6cf..835fed26fb8d1c76e49e55502a8cdd9b99654204 100644 --- a/game/modules/tome/dialogs/GameOptions.lua +++ b/game/modules/tome/dialogs/GameOptions.lua @@ -538,7 +538,7 @@ function _M:generateListGameplay() return tostring(config.settings.tome.tinker_auto_switch and "enabled" or "disabled") end, fct=function(item) config.settings.tome.tinker_auto_switch = not config.settings.tome.tinker_auto_switch - game:saveSettings("tome.tinker_auto_switch", ("tome.tinker_auto_switch = %s\n"):format(tostring(config.settings.tome.rest_before_explore))) + game:saveSettings("tome.tinker_auto_switch", ("tome.tinker_auto_switch = %s\n"):format(tostring(config.settings.tome.tinker_auto_switch))) self.c_list:drawItem(item) end,} diff --git a/game/modules/tome/dialogs/QuestPopup.lua b/game/modules/tome/dialogs/QuestPopup.lua index bb8b95916c6ac0cd4802a8427374322686d1f371..6a77b5c59a67c7d4f48389cc3aa81b0b7708f5e0 100644 --- a/game/modules/tome/dialogs/QuestPopup.lua +++ b/game/modules/tome/dialogs/QuestPopup.lua @@ -39,6 +39,9 @@ function _M:init(quest, status) self.ui = "quest" Dialog.init(self, "", 666, 150) + local add = '' + if quest.popup_text and quest.popup_text[status] then add = quest.popup_text[status].."\n" end + self.blight = self:getUITexture("ui/dialogframe_backglow.png") local f, fs = FontPackage:getFont("bold") @@ -46,7 +49,7 @@ function _M:init(quest, status) quest:setTextShadow(3) quest:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 2) - local info = Textzone.new{auto_width=true, auto_height=true, text='#ANTIQUE_WHITE#(See your Journal for further details or click here)', font={f, math.ceil(fs)}} + local info = Textzone.new{auto_width=true, auto_height=true, text=add..'#ANTIQUE_WHITE#(See your Journal for further details or click here)', font={f, math.ceil(fs)}} info:setTextShadow(3) info:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 2)