Commit e4c319924195bc772fddb1cfe26fd094bf1df9ec

Authored by DarkGod
1 parent fe1d20fc

New Wanderer class. It's akin to adventurer but more chaotic! Instead of choosin…

…g talent trees you get a random set as you levelup! The set is determined by a seed that you can share with others to have friendly random competitions, or just share cool combos ;)
... ... @@ -31,6 +31,7 @@ newBirthDescriptor{
31 31 {
32 32 __ALL__ = "disallow",
33 33 Adventurer = "allow",
  34 + Wanderer = "allow",
34 35 },
35 36 },
36 37 copy = {
... ... @@ -63,7 +64,10 @@ newBirthDescriptor{
63 64 if type(tt) == "function" then tt = tt(birth) end
64 65
65 66 for t, _ in pairs(tt) do
66   - tts[t] = {false, 0}
  67 + local tt_def = birth.actor:getTalentTypeFrom(t)
  68 + if tt_def then
  69 + tts[t] = {false, 0}
  70 + end
67 71 end
68 72 end
69 73
... ... @@ -73,7 +77,10 @@ newBirthDescriptor{
73 77
74 78 for t, v in pairs(tt) do
75 79 if profile.mod.allow_build[v[3]] then
76   - tts[t] = {false, 0}
  80 + local tt_def = birth.actor:getTalentTypeFrom(t)
  81 + if tt_def then
  82 + tts[t] = {false, 0}
  83 + end
77 84 end
78 85 end
79 86 end
... ... @@ -113,3 +120,178 @@ newBirthDescriptor{
113 120 chooseCursedAuraTree = true,
114 121 },
115 122 }
  123 +
  124 +newBirthDescriptor{
  125 + type = "subclass",
  126 + name = "Wanderer",
  127 + locked = function() return profile.mod.allow_build.adventurer and true or "hide" end,
  128 + desc = {
  129 + _t"Wanderers are adventurers who embrace the chaotic nature of the world. They start the game with the Combat Training talent tree, 3 random class trees and 1 random generic tree.",
  130 + _t"#{bold}##PURPLE#Every 5 levels they gain a new unlocked class tree, at random.#{normal}##LAST#",
  131 + _t"#{bold}##PURPLE#Every 10 levels starting at level 2 they gain a new unlocked generic tree, at random.#{normal}##LAST#",
  132 + _t"#{bold}##GOLD#This is a bonus class for winning the game. It is by no means balanced, fun or winnable, it is most of all #{italic}#RANDOM#{bold}#.#WHITE##{normal}#",
  133 + _t"Their most important stats depend on what they get to do.",
  134 + _t"#GOLD#Stat modifiers:",
  135 + _t"#LIGHT_BLUE# * +2 Strength, +2 Dexterity, +2 Constitution",
  136 + _t"#LIGHT_BLUE# * +2 Magic, +2 Willpower, +2 Cunning",
  137 + _t"#GOLD#Life per level:#LIGHT_BLUE# +2",
  138 + },
  139 + not_on_random_boss = true,
  140 + stats = { str=2, con=2, dex=2, mag=2, wil=2, cun=2 },
  141 + talents_types = function(birth)
  142 + local tts_class = {}
  143 + local tts_generic = {}
  144 + local tts_addons = {}
  145 +
  146 + -- Fnid all available trees
  147 + for _, class in ipairs(birth.all_classes) do if class.id ~= "Adventurer" then
  148 + for _, sclass in ipairs(class.nodes) do if sclass.def and ((not sclass.def.not_on_random_boss) or (sclass.id == "Stone Warden" and birth.descriptors_by_type.race == "Dwarf")) then
  149 + if birth.birth_descriptor_def.subclass[sclass.id].talents_types then
  150 + local tt = birth.birth_descriptor_def.subclass[sclass.id].talents_types
  151 + if type(tt) == "function" then tt = tt(birth) end
  152 +
  153 + for t, _ in pairs(tt) do
  154 + local tt_def = birth.actor:getTalentTypeFrom(t)
  155 + if tt_def then
  156 + tts_addons[tt_def.source] = true
  157 + if tt_def.generic then
  158 + table.insert(tts_generic, t)
  159 + else
  160 + table.insert(tts_class, t)
  161 + end
  162 + end
  163 + end
  164 + end
  165 +
  166 + if birth.birth_descriptor_def.subclass[sclass.id].unlockable_talents_types then
  167 + local tt = birth.birth_descriptor_def.subclass[sclass.id].unlockable_talents_types
  168 + if type(tt) == "function" then tt = tt(birth) end
  169 +
  170 + for t, v in pairs(tt) do
  171 + if profile.mod.allow_build[v[3]] then
  172 + local tt_def = birth.actor:getTalentTypeFrom(t)
  173 + if tt_def then
  174 + tts_addons[tt_def.source] = true
  175 + if tt_def.generic then
  176 + table.insert(tts_generic, t)
  177 + else
  178 + table.insert(tts_class, t)
  179 + end
  180 + end
  181 + end
  182 + end
  183 + end
  184 + end end
  185 + end end
  186 + birth.actor.randventurer_class_trees = tts_class
  187 + birth.actor.randventurer_generic_trees = tts_generic
  188 +
  189 + -- Compute the addons fingerprint
  190 + local md5 = require "md5"
  191 + tts_addons['@vanilla@'] = nil
  192 + birth.actor.randventurer_addons = {game.__mod_info.version_string}
  193 + for a, _ in pairs(tts_addons) do
  194 + local addon = game.__mod_info and game.__mod_info.addons and game.__mod_info.addons[a]
  195 + if addon then
  196 + table.insert(birth.actor.randventurer_addons, a.."-"..(addon.addon_version_txt or addon.version_txt or "???"))
  197 + else -- Shouldnt happen but heh
  198 + table.insert(birth.actor.randventurer_addons, a)
  199 + end
  200 + end
  201 + -- Sort addons so that the fingerprint has meaning ;)
  202 + table.sort(birth.actor.randventurer_addons)
  203 + local addons_md5 = mime.b64(md5.sum(table.concat(birth.actor.randventurer_addons,'|')))
  204 +
  205 + local seed = rng.range(1, 99999999)
  206 + if __module_extra_info and __module_extra_info.tome_wanderer_seed then
  207 + local error = function() game:onTickEnd(function() require("engine.ui.Dialog"):simplePopup(_t"Wanderer Seed", _t"The wanderer seed you used was generated for a different set of DLC/addons. Your character will still work fine but you will not have the same talent set as the person that shared the seed with you.") end) end
  208 + local _, _, iseed, check = __module_extra_info.tome_wanderer_seed:find("^([0-9]+)%-(.*)$")
  209 + if not check or not tonumber(iseed) then
  210 + error()
  211 + else
  212 + seed = tonumber(iseed)
  213 + if check ~= addons_md5 then error() end
  214 + end
  215 + end
  216 + rng.seed(seed)
  217 + table.sort(tts_class)
  218 + table.sort(tts_generic)
  219 + table.shuffle(tts_class)
  220 + table.shuffle(tts_generic)
  221 +
  222 + birth.actor.randventurer_seed = seed.."-"..addons_md5
  223 +
  224 + rng.seed(os.time())
  225 +
  226 + return {["technique/combat-training"] = {true, 0}}
  227 + end,
  228 + copy_add = {
  229 + mana_regen = 0.5,
  230 + life_rating = 2,
  231 + unused_generics = 2,
  232 + unused_talents = 3,
  233 + unused_talents_types = 3,
  234 + },
  235 + copy = {
  236 + randventurerLearn = function(self, what, silent)
  237 + local tt = table.remove(what == "class" and self.randventurer_class_trees or self.randventurer_generic_trees, 1)
  238 + if not tt then return end
  239 + local tt_def = self:getTalentTypeFrom(tt)
  240 + if tt_def then
  241 + if self:knowTalentType(tt) then return self:randventurerLearn(what, silent) end
  242 + if not silent then
  243 + local cat = tt_def.type:gsub("/.*", "")
  244 + local name = tstring{{"font", "bold"}, _t(cat, "talent category"):capitalize().." / "..tt_def.name:capitalize(), {"font", "normal"}}
  245 + game.bignews:say(90, "#GOLD#As you level up you learn the talent tree: #LIGHT_BLUE#%s", tostring(name))
  246 + end
  247 + self:learnTalentType(tt)
  248 + end
  249 + end,
  250 + randventurer_last_learn_level = 0,
  251 + resolvers.register_callbacks{ callbackOnLevelup = function(self)
  252 + for i = self.randventurer_last_learn_level + 1, self.level do
  253 + if i % 5 == 0 then
  254 + self:randventurerLearn("class")
  255 + end
  256 + if i % 10 == 2 then
  257 + self:randventurerLearn("generic")
  258 + end
  259 + end
  260 + self.randventurer_last_learn_level = self.level
  261 + end },
  262 + resolvers.generic(function(self)
  263 + self:randventurerLearn("class", true)
  264 + self:randventurerLearn("class", true)
  265 + self:randventurerLearn("class", true)
  266 + self:randventurerLearn("generic", true)
  267 + end),
  268 + resolvers.inventorybirth{ id=true, transmo=true,
  269 + {type="weapon", subtype="dagger", name="iron dagger", autoreq=true, ego_chance=-1000},
  270 + {type="weapon", subtype="dagger", name="iron dagger", autoreq=true, ego_chance=-1000},
  271 + {type="weapon", subtype="longsword", name="iron longsword", ego_chance=-1000, ego_chance=-1000},
  272 + {type="weapon", subtype="longsword", name="iron longsword", ego_chance=-1000, ego_chance=-1000},
  273 + {type="weapon", subtype="greatsword", name="iron greatsword", autoreq=true, ego_chance=-1000, ego_chance=-1000},
  274 + {type="weapon", subtype="staff", name="elm staff", autoreq=true, ego_chance=-1000},
  275 + {type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
  276 + {type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
  277 + {type="armor", subtype="shield", name="iron shield", autoreq=true, ego_chance=-1000, ego_chance=-1000},
  278 + {type="armor", subtype="shield", name="iron shield", autoreq=true, ego_chance=-1000, ego_chance=-1000},
  279 + {type="armor", subtype="hands", name="iron gauntlets", autoreq=true, ego_chance=-1000, ego_chance=-1000},
  280 + {type="armor", subtype="hands", name="rough leather gloves", ego_chance=-1000, ego_chance=-1000},
  281 + {type="armor", subtype="light", name="rough leather armour", ego_chance=-1000, ego_chance=-1000},
  282 + {type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000},
  283 + {type="scroll", subtype="rune", name="manasurge rune", ego_chance=-1000, ego_chance=-1000},
  284 + {type="weapon", subtype="longbow", name="elm longbow", autoreq=true, ego_chance=-1000},
  285 + {type="ammo", subtype="arrow", name="quiver of elm arrows", autoreq=true, ego_chance=-1000},
  286 + {type="weapon", subtype="sling", name="rough leather sling", autoreq=true, ego_chance=-1000},
  287 + {type="ammo", subtype="shot", name="pouch of iron shots", autoreq=true, ego_chance=-1000},
  288 + {type="armor", subtype="cloak", name="linen cloak", autoreq=true, ego_chance=-1000},
  289 + },
  290 + chooseCursedAuraTree = true,
  291 + },
  292 + cosmetic_options = {
  293 + wanderer_seed = {
  294 + {name=_t"Wanderer Seed", on_actor=function(actor) actor.alchemist_golem_is_drolem = true end, unlock="cosmetic_class_alchemist_drolem"},
  295 + },
  296 + },
  297 +}
... ...
... ... @@ -38,6 +38,24 @@ function Talents.aiLowerTacticals(tactical)
38 38 return tacts
39 39 end
40 40
  41 +local oldNewTalentType = Talents.newTalentType
  42 +Talents.newTalentType = function(self, t)
  43 + -- That's some trikery ... try to guess where the talent tree comes from, base game or addon
  44 + local i = 1
  45 + while true do
  46 + local info = debug.getinfo(i, "S")
  47 + if not info then break end
  48 + if info.source then
  49 + local _, _, addon = info.source:find("/data%-([^/]+)/")
  50 + if addon then t.source = addon
  51 + elseif info.source:find("/data/talents") then t.source = "@vanilla@"
  52 + end
  53 + end
  54 + i = i + 1
  55 + end
  56 + return oldNewTalentType(self, t)
  57 +end
  58 +
41 59 local oldNewTalent = Talents.newTalent
42 60 Talents.newTalent = function(self, t)
43 61 local tt = engine.interface.ActorTalents.talents_types_def[t.type[1]]
... ...
... ... @@ -393,10 +393,10 @@ function _M:makeDefault()
393 393 self:setDescriptor("permadeath", "Adventure")
394 394 self:setDescriptor("race", "Human")
395 395 self:setDescriptor("subrace", "Cornac")
396   - -- self:setDescriptor("class", "Mage")
397   - -- self:setDescriptor("subclass", "Archmage")
398   - self:setDescriptor("class", "Warrior")
399   - self:setDescriptor("subclass", "Berserker")
  396 + self:setDescriptor("class", "Adventurer")
  397 + self:setDescriptor("subclass", "Wanderer")
  398 + -- self:setDescriptor("class", "Warrior")
  399 + -- self:setDescriptor("subclass", "Berserker")
400 400 __module_extra_info.no_birth_popup = true
401 401 self:atEnd("created")
402 402 end
... ...