diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua index 10cab225bc4d874be00031bbbd2a0fe4e9f7590e..0b48bda81a324d9eebeb97455491b585413f9d86 100644 --- a/game/modules/tome/class/GameState.lua +++ b/game/modules/tome/class/GameState.lua @@ -1665,89 +1665,8 @@ function _M:createRandomZone(zbase) return zone, boss end -function _M:createRandomBoss(base, data) - local b = base:clone() - data = data or {level=1} - - ------------------------------------------------------------ - -- Basic stuff, name, rank, ... - ------------------------------------------------------------ - local ngd, name - if base.random_name_def then - ngd = NameGenerator2.new("/data/languages/names/"..base.random_name_def:gsub("#sex#", base.female and "female" or "male")..".txt") - name = ngd:generate(nil, base.random_name_min_syllables, base.random_name_max_syllables) - else - ngd = NameGenerator.new(randart_name_rules.default) - name = ngd:generate() - end - if data.name_scheme then - b.name = data.name_scheme:gsub("#rng#", name):gsub("#base#", b.name) - else - b.name = name.." the "..b.name - end - b.unique = b.name - b.randboss = true - local boss_id = "RND_BOSS_"..b.name:upper():gsub("[^A-Z]", "_") - b.define_as = boss_id - b.color = colors.VIOLET - b.rank = data.rank or (rng.percent(30) and 4 or 3.5) - b.level_range[1] = data.level - b.fixed_rating = true - if data.life_rating then - b.life_rating = data.life_rating(b.life_rating) - else - b.life_rating = b.life_rating * 1.7 + rng.range(4, 9) - end - b.max_life = b.max_life or 150 - - if b.can_multiply or b.clone_on_hit then - b.clone_base = base:clone() - b.clone_base:resolve() - b.clone_base:resolve(nil, true) - end - - -- Force resolving some stuff - if type(b.max_life) == "table" and b.max_life.__resolver then b.max_life = resolvers.calc[b.max_life.__resolver](b.max_life, b, b, b, "max_life", {}) end - - -- All bosses have alll body parts .. yes snake bosses can use archery and so on .. - -- This is to prevent them from having unusable talents - b.inven = {} - b.body = { INVEN = 1000, QS_MAINHAND = 1, QS_OFFHAND = 1, MAINHAND = 1, OFFHAND = 1, FINGER = 2, NECK = 1, LITE = 1, BODY = 1, HEAD = 1, CLOAK = 1, HANDS = 1, BELT = 1, FEET = 1, TOOL = 1, QUIVER = 1 } - b:initBody() - - b:resolve() - - -- Start with sustains sustained - b[#b+1] = resolvers.sustains_at_birth() - - -- Leveling stats - b.autolevel = "random_boss" - b.auto_stats = {} - - -- Always smart - if data.ai then b.ai = data.ai - else b.ai = (b.rank > 3) and "tactical" or b.ai - end - b.ai_state = { talent_in=1, ai_move=data.ai_move or "move_astar" } - - -- Remove default equipment, if any - local todel = {} - for k, resolver in pairs(b) do if type(resolver) == "table" and resolver.__resolver and (resolver.__resolver == "equip" or resolver.__resolver == "drops") then todel[#todel+1] = k end end - for _, k in ipairs(todel) do b[k] = nil end - - -- Boss worthy drops - b[#b+1] = resolvers.drops{chance=100, nb=data.loot_quantity or 3, {tome_drops=data.loot_quality or "boss"} } - if not data.no_loot_randart then b[#b+1] = resolvers.drop_randart{} end - - -- On die - if data.on_die then - b.rng_boss_on_die = b.on_die - b.rng_boss_on_die_custom = data.on_die - b.on_die = function(self, src) - self:check("rng_boss_on_die_custom", src) - self:check("rng_boss_on_die", src) - end - end +function _M:applyRandomClass(b, data, instant) + if not data.level then data.level = b.level end ------------------------------------------------------------ -- Apply talents from classes @@ -1768,10 +1687,12 @@ function _M:createRandomBoss(base, data) if config.settings.cheat then b.desc = (b.desc or "").."\nClass: "..class.name end -- Add stats - b.stats = b.stats or {} - for stat, v in pairs(class.stats or {}) do - b.stats[stat] = (b.stats[stat] or 10) + v - for i = 1, v do b.auto_stats[#b.auto_stats+1] = b.stats_def[stat].id end + if b.auto_stats then + b.stats = b.stats or {} + for stat, v in pairs(class.stats or {}) do + b.stats[stat] = (b.stats[stat] or 10) + v + for i = 1, v do b.auto_stats[#b.auto_stats+1] = b.stats_def[stat].id end + end end -- Add talent categories @@ -1783,19 +1704,11 @@ function _M:createRandomBoss(base, data) -- Add starting equipment local apply_resolvers = function(k, resolver) if type(resolver) == "table" and resolver.__resolver and resolver.__resolver == "equip" then - resolver[1].id = nil - -- Make sure we equip some nifty stuff instead of player's starting iron stuff - for i, d in ipairs(resolver[1]) do - d.name = nil - d.ego_chance = nil - d.tome_drops = data.loot_quality or "boss" - d.force_drop = (data.drop_equipment == nil) and true or data.drop_equipment - end - b[#b+1] = resolver elseif k == "innate_alchemy_golem" then b.innate_alchemy_golem = true elseif k == "birth_create_alchemist_golem" then b.birth_create_alchemist_golem = resolver + if instant then b:check("birth_create_alchemist_golem") end elseif k == "soul" then b.soul = util.bound(1 + math.ceil(data.level / 10), 1, 10) -- Does this need to scale? end @@ -1845,7 +1758,13 @@ function _M:createRandomBoss(base, data) print(" * talent", tid) local max = (t.points == 1) and 1 or math.ceil(t.points * 1.2) local step = max / 50 - b.learn_tids[tid] = math.ceil(step * data.level) + local lev = math.ceil(step * data.level) + if instant then + if b:getTalentLevelRaw(tid) < lev then b:learnTalent(tid, true, lev - b:getTalentLevelRaw(tid)) end + if t.mode == "sustained" and data.auto_sustain then b:forceUseTalent(tid, {ignore_energy=true}) end + else + b.learn_tids[tid] = lev + end end end end @@ -1864,6 +1783,96 @@ function _M:createRandomBoss(base, data) if not c then break end apply_class(table.clone(c, true)) end +end + +function _M:createRandomBoss(base, data) + local b = base:clone() + data = data or {level=1} + + ------------------------------------------------------------ + -- Basic stuff, name, rank, ... + ------------------------------------------------------------ + local ngd, name + if base.random_name_def then + ngd = NameGenerator2.new("/data/languages/names/"..base.random_name_def:gsub("#sex#", base.female and "female" or "male")..".txt") + name = ngd:generate(nil, base.random_name_min_syllables, base.random_name_max_syllables) + else + ngd = NameGenerator.new(randart_name_rules.default) + name = ngd:generate() + end + if data.name_scheme then + b.name = data.name_scheme:gsub("#rng#", name):gsub("#base#", b.name) + else + b.name = name.." the "..b.name + end + b.unique = b.name + b.randboss = true + local boss_id = "RND_BOSS_"..b.name:upper():gsub("[^A-Z]", "_") + b.define_as = boss_id + b.color = colors.VIOLET + b.rank = data.rank or (rng.percent(30) and 4 or 3.5) + b.level_range[1] = data.level + b.fixed_rating = true + if data.life_rating then + b.life_rating = data.life_rating(b.life_rating) + else + b.life_rating = b.life_rating * 1.7 + rng.range(4, 9) + end + b.max_life = b.max_life or 150 + + if b.can_multiply or b.clone_on_hit then + b.clone_base = base:clone() + b.clone_base:resolve() + b.clone_base:resolve(nil, true) + end + + -- Force resolving some stuff + if type(b.max_life) == "table" and b.max_life.__resolver then b.max_life = resolvers.calc[b.max_life.__resolver](b.max_life, b, b, b, "max_life", {}) end + + -- All bosses have alll body parts .. yes snake bosses can use archery and so on .. + -- This is to prevent them from having unusable talents + b.inven = {} + b.body = { INVEN = 1000, QS_MAINHAND = 1, QS_OFFHAND = 1, MAINHAND = 1, OFFHAND = 1, FINGER = 2, NECK = 1, LITE = 1, BODY = 1, HEAD = 1, CLOAK = 1, HANDS = 1, BELT = 1, FEET = 1, TOOL = 1, QUIVER = 1 } + b:initBody() + + b:resolve() + + -- Start with sustains sustained + b[#b+1] = resolvers.sustains_at_birth() + + -- Leveling stats + b.autolevel = "random_boss" + b.auto_stats = {} + + -- Always smart + if data.ai then b.ai = data.ai + else b.ai = (b.rank > 3) and "tactical" or b.ai + end + b.ai_state = { talent_in=1, ai_move=data.ai_move or "move_astar" } + + -- Remove default equipment, if any + local todel = {} + for k, resolver in pairs(b) do if type(resolver) == "table" and resolver.__resolver and (resolver.__resolver == "equip" or resolver.__resolver == "drops") then todel[#todel+1] = k end end + for _, k in ipairs(todel) do b[k] = nil end + + -- Boss worthy drops + b[#b+1] = resolvers.drops{chance=100, nb=data.loot_quantity or 3, {tome_drops=data.loot_quality or "boss"} } + if not data.no_loot_randart then b[#b+1] = resolvers.drop_randart{} end + + -- On die + if data.on_die then + b.rng_boss_on_die = b.on_die + b.rng_boss_on_die_custom = data.on_die + b.on_die = function(self, src) + self:check("rng_boss_on_die_custom", src) + self:check("rng_boss_on_die", src) + end + end + + ------------------------------------------------------------ + -- Apply talents from classes + ------------------------------------------------------------ + self:applyRandomClass(b, data) b.rnd_boss_on_added_to_level = b.on_added_to_level b._rndboss_resources_boost = data.resources_boost diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua index 0c72a87d7f600550352249d10421e588e96220b1..88b6f350bdd8dfd090171891b3a7b170e15085d9 100644 --- a/game/modules/tome/class/NPC.lua +++ b/game/modules/tome/class/NPC.lua @@ -435,12 +435,30 @@ function _M:addedToLevel(level, x, y) for tid, lev in pairs(self.talents) do self:learnTalent(tid, true, lev) end + if not self.randboss and self.rank >= 3.5 then + local data = {auto_sustain=true} + if self.rank == 3.5 then data = {auto_sustain=true, nb_classes=1} + elseif self.rank == 4 then data = {auto_sustain=true, nb_classes=1} + elseif self.rank == 5 then data = {auto_sustain=true, nb_classes=2} + elseif self.rank >= 10 then data = {auto_sustain=true, nb_classes=3} + end + game.state:applyRandomClass(self, data, true) + end self:attr("difficulty_boosted", 1) elseif game.difficulty == game.DIFFICULTY_MADNESS and not game.party:hasMember(self) then -- Increase talent level for tid, lev in pairs(self.talents) do self:learnTalent(tid, true, math.ceil(lev * 1.7)) end + if not self.randboss and self.rank >= 3.5 then + local data = {auto_sustain=true} + if self.rank == 3.5 then data = {auto_sustain=true, nb_classes=1} + elseif self.rank == 4 then data = {auto_sustain=true, nb_classes=2} + elseif self.rank == 5 then data = {auto_sustain=true, nb_classes=3} + elseif self.rank >= 10 then data = {auto_sustain=true, nb_classes=5} + end + game.state:applyRandomClass(self, data, true) + end self:attr("difficulty_boosted", 1) end end diff --git a/game/modules/tome/data/birth/descriptors.lua b/game/modules/tome/data/birth/descriptors.lua index f6bcb27a36d72ba63b01d97bb2019a1cc1dde3b6..0c3f31b6d4096cadd9e272f78640f35e8faa048d 100644 --- a/game/modules/tome/data/birth/descriptors.lua +++ b/game/modules/tome/data/birth/descriptors.lua @@ -214,6 +214,7 @@ newBirthDescriptor{ "Absolutely unfair game setting. You are really mentally ill to play this mode!", "All zone levels increased by 120% + 5", "All creature talent levels increased by 100%", + "Bosses will have randomly selected talents", "Player rank is normal instead of elite", "Player can earn Insane version of achievements if also playing in Roguelike or Adventure permadeath mode.", }, @@ -239,6 +240,7 @@ newBirthDescriptor{ "All zone levels increased by 150% + 10", "All creature talent levels increased by 170%", "Rare creatures are far more frequent and random bosses start to appear", + "Bosses will have randomly selected talents", "Player is being hunted! Randomly all foes in a radius will get a feeling of where she/he is", "Player rank is normal instead of elite", "Player can earn Madness version of achievements if also playing in Roguelike or Adventure permadeath mode.", diff --git a/game/modules/tome/data/texts/unlock-difficulty_insane.lua b/game/modules/tome/data/texts/unlock-difficulty_insane.lua index 746d77d476c4118033b9fee9c190ce4015439e65..aa0d60e6bc85339c53594e732f34fac39d3ba70e 100644 --- a/game/modules/tome/data/texts/unlock-difficulty_insane.lua +++ b/game/modules/tome/data/texts/unlock-difficulty_insane.lua @@ -26,6 +26,7 @@ But no! If nightmare mode couldn't bring you down, Insane mode will! Insane features:#YELLOW# - All zone levels increased by 120% + 5 - All creature talent levels increased by 100% +- Bosses will have randomly selected talents - Player rank is normal instead of elite - Player can earn Insane version of achievements if also playing in Roguelike permadeath mode. diff --git a/game/modules/tome/data/texts/unlock-difficulty_madness.lua b/game/modules/tome/data/texts/unlock-difficulty_madness.lua index 063dc1433ddd09b890a07876e630f4b734e78810..0a6c5547399778e306af551e1e60b98004afade3 100644 --- a/game/modules/tome/data/texts/unlock-difficulty_madness.lua +++ b/game/modules/tome/data/texts/unlock-difficulty_madness.lua @@ -27,6 +27,7 @@ Madness features:#YELLOW# - All zone levels increased by 150% + 10 - All creature talent levels increased by 170% - Rare creatures are far more frequent and random bosses start to appear +- Bosses will have randomly selected talents - Player is being hunted! Randomly all foes in a radius will get a feeling of where she/he is - Player rank is normal instead of elite - Player can earn Madness version of achievements if also playing in Roguelike or Adventure permadeath mode.