Commit e4c319924195bc772fddb1cfe26fd094bf1df9ec
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 ;)
Showing
3 changed files
with
206 additions
and
6 deletions
... | ... | @@ -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 | ... | ... |
-
Please register or login to post a comment