From 041958c6a286b8cfce6824f66a8337585af8c183 Mon Sep 17 00:00:00 2001 From: Bunny <glisa825@gmail.com> Date: Fri, 3 Apr 2020 01:17:04 -0400 Subject: [PATCH] Change how rare+ are generated to tree based instead of individual talent based --- game/modules/tome/class/GameState.lua | 166 +++++++++++++++++--------- 1 file changed, 111 insertions(+), 55 deletions(-) diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua index ca08d3532c..c0b8c47d5b 100644 --- a/game/modules/tome/class/GameState.lua +++ b/game/modules/tome/class/GameState.lua @@ -2096,11 +2096,14 @@ function _M:applyRandomClass(b, data, instant) end if data.autolevel ~= false then b.autolevel = data.autolevel or "random_boss" end + local tt_unlocked = {} -- unlocked categories by base + local tt_locked = {} -- locked categories by base -- Class talent categories - for tt, d in pairs(mclass.talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) end - for tt, d in pairs(mclass.unlockable_talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) end - for tt, d in pairs(class.talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) end - for tt, d in pairs(class.unlockable_talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) end + local ttypes = {} + for tt, d in pairs(mclass.talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) ttypes[tt] = table.clone(d) end + for tt, d in pairs(mclass.unlockable_talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) ttypes[tt] = table.clone(d) end + for tt, d in pairs(class.talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) ttypes[tt] = table.clone(d) end + for tt, d in pairs(class.unlockable_talents_types or {}) do b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d[2]) ttypes[tt] = table.clone(d) end -- Non-class talent categories if data.add_trees then @@ -2109,9 +2112,11 @@ function _M:applyRandomClass(b, data, instant) if type(d) ~= "number" then d = rng.range(1, 3)*0.1 end b:learnTalentType(tt, true) b:setTalentTypeMastery(tt, (b:getTalentTypeMastery(tt) or 1) + d) + ttypes[tt] = table.clone(d) end end end + -- Add starting equipment local apply_resolvers = function(k, resolver) if type(resolver) == "table" and resolver.__resolver then @@ -2158,76 +2163,127 @@ function _M:applyRandomClass(b, data, instant) local t = b:getTalentFromId(tid) if not t.no_npc_use and not t.no_npc_autolevel and (not t.random_boss_rarity or rng.chance(t.random_boss_rarity)) and not (t.rnd_boss_restrict and t.rnd_boss_restrict(b, t, data) ) then local max = (t.points == 1) and 1 or math.ceil(t.points * 1.2) - local step = max / 50 + local step = max / 70 tres[1][tid] = v + math.ceil(step * data.level) end end - -- Select additional talents from the class - local known_types = {} - for tt, d in pairs(b.talents_types) do - known_types[tt] = b:numberKnownTalent(tt) + -- learn talents based on trees: focus trees we take 3-4 talents from with a decent amount of point investment, shallow trees we only take 1 or 2 with not many points + -- ideally rares should feel different even within the same class based on what focus trees they get + local nb_focus, nb_shallow = 0, 0 + local rank = b.rank + if rank <= 3.2 then --rare + nb_focus = math.floor(0.2 + rng.float(0.25, 0.35)*(math.max(0,data.level))^0.55) -- first around 8-10, second around 25-35, third around 50-70 + nb_shallow = 2 + math.floor(0.25 + rng.float(0.1, 0.2)*(math.max(0,data.level))^0.6) -- third around 12-30, fourth 40-80 + elseif rank >= 4 then --boss/elite boss + nb_focus = 1 + math.floor(0.25 + rng.float(0.12, 0.33)*(math.max(0,data.level-4))^0.5) -- second around 10-16, third around 30-50, fourth around 60-85 uncommonly + nb_shallow = 1 + math.floor(0.33 + rng.float(0.1, 0.18)*(math.max(0,data.level-3))^0.6) -- second around 12-20, third 40-80 + else --unique + nb_focus = 1 + math.floor(0.2 + rng.float(0.1, 0.3)*(math.max(0,data.level-10))^0.5) -- second around 17-30, third around 40-80 + nb_shallow = 1 + math.floor(0.7 + rng.float(0.1, 0.2)*(math.max(0,data.level-8))^0.6) -- second around 12-14, third around 30-70, fourth around 70-90 rarely end + print("Adding "..nb_focus.." primary trees to boss") + print("Adding "..nb_shallow.." secondary trees to boss") - local list = {} - for _, t in pairs(b.talents_def) do - if b.talents_types[t.type[1]] then + local tt_choices = {} + for tt, d in pairs(ttypes) do + d.tt = tt + table.insert(tt_choices, d) + end + + local fails = 0 + local focus_trees = {} + local shallow_trees = {} + local tt, tt_idx, tt_def + local t, t_idx + while #focus_trees < nb_focus or #shallow_trees < nb_shallow do + local ok = false + while not ok do + tt = rng.tableRemove(tt_choices) + if not tt or not tt.tt then break end + if not (tt.tt=="technique/combat-training" or tt.tt=="cunning/survival") then ok=true end + end + if not ok then break end + tt = tt.tt + tt_def = tt and b:knowTalentType(tt) and b.talents_types_def[tt] + if not tt_def then break end + print("[applyRandomClass] Attempting to add tree "..tt.." to boss") + local t_choices = {} + local nb_known = b:numberKnownTalent(tt) + for i, t in ipairs(tt_def.talents) do + local ok = true if t.no_npc_use or t.not_on_random_boss then - known_types[t.type[1]] = known_types[t.type[1]] + 1 -- allows higher tier talents to be learnt - else - local ok = true - if t.rnd_boss_restrict and t.rnd_boss_restrict(b, t, data) then + nb_known = nb_known + 1 -- treat as known to allow later talents to be learned + print(" * Random boss forbade talent because talent not allowed on random bosses", t.name, t.id, data.level) + ok = false + end + if t.rnd_boss_restrict and t.rnd_boss_restrict(b, t, data) and ok then + print(" * Random boss forbade talent because of special talent restriction", t.name, t.id, data.level) + nb_known = nb_known + 1 -- treat as known to allow later talents to be learned + ok = false + end + if t.random_boss_rarity and rng.percent(t.random_boss_rarity) and ok then + print(" * Random boss forbade talent because of random boss rarity random chance", t.name, t.id, data.level) + nb_known = nb_known + 1 -- treat as known to allow later talents to be learned + ok = false + end + if data.check_talents_level and rawget(t, 'require') and ok then + local req = t.require + if type(req) == "function" then req = req(b, t) end + if req and req.level and util.getval(req.level, 1) > math.ceil(data.level) then + print(" * Random boss forbade talent because of level", t.name, t.id, data.level) ok = false - print("[applyRandomClass] Random boss forbade talent because of special talent restriction", t.name, t.id, data.level) end - if data.check_talents_level and rawget(t, 'require') then - local req = t.require - if type(req) == "function" then req = req(b, t) end - if req and req.level and util.getval(req.level, 1) > math.ceil(data.level/2) then - print("[applyRandomClass] Random boss forbade talent because of level", t.name, t.id, data.level) - ok = false + end + if ok then + table.insert(t_choices, t) + end + end + print(" Talent choices for "..tt..":") for i, t in ipairs(t_choices) do print("\t", i, t.id, t.name) end + if #t_choices <= 2 or #focus_trees >= nb_focus then + if #t_choices > 0 and #shallow_trees < nb_shallow then + table.insert(shallow_trees, tt) -- record that we added the tree as a minor tree + max_talents_from_tree = rng.percent(65) and 2 or 1 + print("Adding secondary tree "..tt.." to boss with "..max_talents_from_tree.." talents") + for i = max_talents_from_tree,1,-1 do + local t = table.remove(t_choices, 1) + if not t then break end + local max = (t.points == 1) and 1 or math.ceil(t.points * 1.2) + local step = max / 60 + local lev = math.max(1, math.round(rng.float(0.75,1.15)*math.ceil(step * data.level))) + print(#shallow_trees, " * talent:", t.id, lev) + if instant then -- affected by game difficulty settings + if b:getTalentLevelRaw(t) < lev then b:learnTalent(t.id, true, lev - b:getTalentLevelRaw(t.id)) end + if t.mode == "sustained" and data.auto_sustain then b:forceUseTalent(t, {ignore_energy=true}) end + else -- applied when added to the level (unaffected by game difficulty settings) + b.learn_tids[t.id] = lev end end - if t.type[1]:find("/other$") then - print("[applyRandomClass] Random boss forbase talent because category /other", t.name, t.id, t.type[1]) - ok = false - end - if ok then list[t.id] = true end + else + print("Tree "..tt.." rejected") end - end - end - - local nb = 4 + 0.38*data.level^.75 -- = 11 at level 50 - nb = math.max(rng.range(math.floor(nb * 0.7), math.ceil(nb * 1.3)), 1) - print("Adding "..nb.." random class talents to boss") - - local count, fails = 0, 0 - while count < nb do - local tid = rng.tableIndex(list, b.learn_tids) - if not tid or fails > nb * 5 then break end - local t = b:getTalentFromId(tid) - if t then - if t.type[2] and known_types[t.type[1]] < t.type[2] - 1 then -- not enough of talents of type - fails = fails + 1 - else -- ok to add - count = count + 1 + else + table.insert(focus_trees, tt) --record that we added the tree as a major tree + local max_talents_from_tree = rng.percent(75) and 4 or 3 + print("Adding primary tree "..tt.." to boss with "..max_talents_from_tree.." talents") + for i = max_talents_from_tree,1,-1 do + local t = table.remove(t_choices, 1) + if not t then break end local max = (t.points == 1) and 1 or math.ceil(t.points * 1.2) local step = max / 50 - local lev = math.ceil(step * data.level) - print(count, " * talent:", tid, lev) + local lev = math.max(1, math.round(rng.float(0.75,1.25)*math.ceil(step * data.level))) + print(#focus_trees, " * talent:", t.id, lev) if instant then -- affected by game difficulty settings - 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 + if b:getTalentLevelRaw(t) < lev then b:learnTalent(t.id, true, lev - b:getTalentLevelRaw(t.id)) end + if t.mode == "sustained" and data.auto_sustain then b:forceUseTalent(t, {ignore_energy=true}) end else -- applied when added to the level (unaffected by game difficulty settings) - b.learn_tids[tid] = lev + b.learn_tids[t.id] = lev end - known_types[t.type[1]] = known_types[t.type[1]] + 1 - list[tid] = nil end - else list[tid] = nil end - end - print(" ** Finished adding", count, "of", nb, "random class talents") + end + print(" ** Finished adding", #focus_trees, "of", nb_focus, "primary class trees") for i, tt in ipairs(focus_trees) do print("\t * ", tt) end + print(" ** Finished adding", #shallow_trees, "of", nb_shallow, "secondary class trees") for i, tt in ipairs(shallow_trees) do print("\t * ", tt) end return true end -- GitLab