Commit 635d0abbe9dc5e98fbd7d33e3d626674d9a7a7d0

Authored by DarkGod
1 parent e4c31992

wanderer can use & share seeds, and unlock. woot!

... ... @@ -341,8 +341,16 @@ function _M:newGame()
341 341 if __module_extra_info.no_birth_popup then d.key:triggerVirtual("EXIT") end
342 342 end
343 343
344   - if self.player.no_birth_levelup or __module_extra_info.no_birth_popup then birthend()
345   - else self.player:playerLevelup(birthend, true) end
  344 + local birthend_lvlup = function()
  345 + if self.player.no_birth_levelup or __module_extra_info.no_birth_popup then birthend()
  346 + else self.player:playerLevelup(birthend, true) end
  347 + end
  348 + if self.player.custom_birthend then
  349 + self.player:custom_birthend(birth, birthend_lvlup)
  350 + self.player.custom_birthend = nil
  351 + else
  352 + birthend_lvlup()
  353 + end
346 354 -- Player was loaded from a premade
347 355 else
348 356 self.calendar = Calendar.new("/data/calendar_"..(self.player.calendar or "allied")..".lua", "Today is the %s %s of the %s year of the Age of Ascendancy of Maj'Eyal.\nThe time is %02d:%02d.", 122, 167, 11)
... ... @@ -376,7 +384,8 @@ function _M:newGame()
376 384 self:setTacticalMode(self.always_target)
377 385 self:triggerHook{"ToME:birthDone"}
378 386 end
379   - end, quickbirth, 800, 600)
  387 + end, quickbirth, math.min(math.max(game.w * 0.8, 800), 1200, game.w), 600)
  388 + -- end, quickbirth, 800, 600)
380 389 self:registerDialog(birth)
381 390 end
382 391
... ...
... ... @@ -20,7 +20,7 @@
20 20 newBirthDescriptor{
21 21 type = "class",
22 22 name = "Adventurer",
23   - locked = function() return profile.mod.allow_build.adventurer and true or "hide" end,
  23 + locked = function() return (profile.mod.allow_build.adventurer or profile.mod.allow_build.wanderer) and true or "hide" end,
24 24 desc = {
25 25 _t"Adventurers can learn to do a bit of everything, getting training in whatever they happen to find.",
26 26 _t"#{bold}##GOLD#This is a bonus class for winning the game. It is by no means balanced.#WHITE##{normal}#",
... ... @@ -124,12 +124,12 @@ newBirthDescriptor{
124 124 newBirthDescriptor{
125 125 type = "subclass",
126 126 name = "Wanderer",
127   - locked = function() return profile.mod.allow_build.adventurer and true or "hide" end,
  127 + locked = function() return profile.mod.allow_build.wanderer and true or "hide" end,
128 128 desc = {
129 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 130 _t"#{bold}##PURPLE#Every 5 levels they gain a new unlocked class tree, at random.#{normal}##LAST#",
131 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}#",
  132 + _t"#{bold}##GOLD#This is a bonus class for the chaotically inclined. It is by no means balanced, fun or winnable, it is most of all #{italic}#RANDOM#{bold}#.#WHITE##{normal}#",
133 133 _t"Their most important stats depend on what they get to do.",
134 134 _t"#GOLD#Stat modifiers:",
135 135 _t"#LIGHT_BLUE# * +2 Strength, +2 Dexterity, +2 Constitution",
... ... @@ -139,90 +139,6 @@ newBirthDescriptor{
139 139 not_on_random_boss = true,
140 140 stats = { str=2, con=2, dex=2, mag=2, wil=2, cun=2 },
141 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 142 return {["technique/combat-training"] = {true, 0}}
227 143 end,
228 144 copy_add = {
... ... @@ -233,6 +149,9 @@ newBirthDescriptor{
233 149 unused_talents_types = 3,
234 150 },
235 151 copy = {
  152 + custom_birthend = function(self, birth, finish)
  153 + game:registerDialog(require("mod.dialogs.WandererSeed").new(self, birth, finish))
  154 + end,
236 155 randventurerLearn = function(self, what, silent)
237 156 local tt = table.remove(what == "class" and self.randventurer_class_trees or self.randventurer_generic_trees, 1)
238 157 if not tt then return end
... ... @@ -259,12 +178,6 @@ newBirthDescriptor{
259 178 end
260 179 self.randventurer_last_learn_level = self.level
261 180 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 181 resolvers.inventorybirth{ id=true, transmo=true,
269 182 {type="weapon", subtype="dagger", name="iron dagger", autoreq=true, ego_chance=-1000},
270 183 {type="weapon", subtype="dagger", name="iron dagger", autoreq=true, ego_chance=-1000},
... ...
  1 +-- ToME - Tales of Maj'Eyal
  2 +-- Copyright (C) 2009 - 2019 Nicolas Casalini
  3 +--
  4 +-- This program is free software: you can redistribute it and/or modify
  5 +-- it under the terms of the GNU General Public License as published by
  6 +-- the Free Software Foundation, either version 3 of the License, or
  7 +-- (at your option) any later version.
  8 +--
  9 +-- This program is distributed in the hope that it will be useful,
  10 +-- but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 +-- GNU General Public License for more details.
  13 +--
  14 +-- You should have received a copy of the GNU General Public License
  15 +-- along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +--
  17 +-- Nicolas Casalini "DarkGod"
  18 +-- darkgod@te4.org
  19 +
  20 +return _t"New Class: #LIGHT_GREEN#Wanderer",
  21 +_t[[You have wanderer quite a lot since your birth!
  22 +You can now create new characters with the #LIGHT_GREEN#Wanderer class#WHITE#.
  23 +
  24 +Wanderers start the game with 4 randomly selected talent trees points and gain new random ones as they levelup.
  25 +They are a #{bold}#bonus#{normal}# class, in no way meant to be balanced or even working with all possible talent combos.
  26 +Use at your own risk, and have fun.]]
... ...
... ... @@ -56,4 +56,7 @@ return {
56 56 game.player:hasQuest("staff-absorption"):start_ambush(game.player)
57 57 end
58 58 end,
  59 + on_leave = function()
  60 + game:setAllowedBuild("wanderer", true)
  61 + end,
59 62 }
... ...
... ... @@ -90,7 +90,7 @@ function _M:init(title, actor, order, at_end, quickbirth, w, h)
90 90 self.c_ok = Button.new{text=_t" Play! ", fct=function() self:atEnd("created") end}
91 91 self.c_random = Button.new{text=_t"Random!", fct=function() self:randomBirth() end}
92 92 self.c_premade = Button.new{text=_t"Load premade", fct=function() self:loadPremadeUI() end}
93   - self.c_tile = Button.new{text=_t"Select custom tile", fct=function() self:selectTile() end}
  93 + self.c_tile = Button.new{text=_t"Custom tile", fct=function() self:selectTile() end}
94 94 self.c_cancel = Button.new{text=_t"Cancel", fct=function() self:atEnd("quit") end}
95 95 self.c_tut = Button.new{text=_t"Tutorial", fct=function() self:tutorial() end}
96 96 self.c_options = Button.new{text=_t"Customize", fct=function() self:customizeOptions() end}
... ... @@ -123,7 +123,9 @@ function _M:init(title, actor, order, at_end, quickbirth, w, h)
123 123 self.c_permadeath_text = Textzone.new{auto_width=true, auto_height=true, text=_t"Permadeath: "}
124 124 self.c_permadeath = Dropdown.new{width=150, fct=function(item) self:permadeathUse(item) end, on_select=function(item) self:updateDesc(item) end, list=self.all_permadeaths, nb_items=#self.all_permadeaths}
125 125
126   - self.c_desc = TextzoneList.new{width=math.floor(self.iw / 3 - 10), height=self.ih - self.c_female.h - self.c_ok.h - self.c_difficulty.h - self.c_campaign.h - 10, scrollbar=true, pingpong=20, no_color_bleed=true}
  126 + local raceclass_w = math.min(262, math.floor(self.iw / 3 - 10))
  127 +
  128 + self.c_desc = TextzoneList.new{width=self.iw - 2 * raceclass_w, height=self.ih - self.c_female.h - self.c_ok.h - self.c_difficulty.h - self.c_campaign.h - 10, scrollbar=true, pingpong=20, no_color_bleed=true}
127 129
128 130 self:setDescriptor("base", "base")
129 131 self:setDescriptor("world", self.default_campaign)
... ... @@ -132,7 +134,7 @@ function _M:init(title, actor, order, at_end, quickbirth, w, h)
132 134 self:setDescriptor("sex", "Female")
133 135
134 136 self:generateRaces()
135   - self.c_race = TreeList.new{width=math.floor(self.iw / 3 - 10), height=self.ih - self.c_female.h - self.c_ok.h - (self.c_extra_options.hide and 0 or self.c_extra_options.h) - self.c_difficulty.h - self.c_campaign.h - 10, scrollbar=true, columns={
  137 + self.c_race = TreeList.new{width=raceclass_w, height=self.ih - self.c_female.h - self.c_ok.h - (self.c_extra_options.hide and 0 or self.c_extra_options.h) - self.c_difficulty.h - self.c_campaign.h - 10, scrollbar=true, columns={
136 138 {width=100, display_prop="name"},
137 139 }, tree=self.all_races,
138 140 fct=function(item, sel, v) self:raceUse(item, sel, v) end,
... ... @@ -141,7 +143,7 @@ function _M:init(title, actor, order, at_end, quickbirth, w, h)
141 143 }
142 144
143 145 self:generateClasses()
144   - self.c_class = TreeList.new{width=math.floor(self.iw / 3 - 10), height=self.ih - self.c_female.h - self.c_ok.h - self.c_difficulty.h - self.c_campaign.h - 10, scrollbar=true, columns={
  146 + self.c_class = TreeList.new{width=raceclass_w, height=self.ih - self.c_female.h - self.c_ok.h - self.c_difficulty.h - self.c_campaign.h - 10, scrollbar=true, columns={
145 147 {width=100, display_prop="name"},
146 148 }, tree=self.all_classes,
147 149 fct=function(item, sel, v) self:classUse(item, sel, v) end,
... ...
... ... @@ -346,6 +346,17 @@ function _M:mouseLink(link, text, _, _, _, w, h, x, y)
346 346 }, true)
347 347 end
348 348
  349 +function _M:mouseClick(fct, text, _, _, _, w, h, x, y)
  350 + self:mouseZones({
  351 + { x=x, y=y, w=w, h=h, fct=function(button)
  352 + game.tooltip_x, game.tooltip_y = 1, 1; game:tooltipDisplayAtMap(game.w, game.h, text)
  353 + if button == "left" then
  354 + fct()
  355 + end
  356 + end},
  357 + }, true)
  358 +end
  359 +
349 360 -- Switch between equipment sets (by reference only) for the equip doll
350 361 -- This makes sure the equipment shown in the equipdoll matches the tab setting
351 362 -- Done this way to make sure the actor's equipment is never actually touched
... ... @@ -479,7 +490,8 @@ function _M:drawDialog(kind, actor_to_compare)
479 490 local text = ""
480 491 local dur_text = ""
481 492
482   - if player.__te4_uuid and profile.auth and profile.auth.drupid and not config.settings.disable_all_connectivity and config.settings.tome.upload_charsheet then
  493 + -- if player.__te4_uuid and profile.auth and profile.auth.drupid and not config.settings.disable_all_connectivity and config.settings.tome.upload_charsheet then
  494 + if true then profile.auth.drupid=1 player.__te4_uuid="jklljkljlk"
483 495 local path = "https://te4.org/characters/"..profile.auth.drupid.."/tome/"..player.__te4_uuid
484 496 local LinkTxt = ("Online URL: #LIGHT_BLUE##{underline}#%s#{normal}#"):tformat(path)
485 497 local Link_w, Link_h = self.font:size(LinkTxt)
... ... @@ -612,6 +624,13 @@ function _M:drawDialog(kind, actor_to_compare)
612 624 local follow = (player.faction == "zigur" or player:attr("zigur_follower")) and _t"Zigur follower" or _t"Antimagic adherent"
613 625 self:mouseTooltip(self.TOOLTIP_ANTIMAGIC_USER, s:drawColorStringBlended(self.font, "#ORCHID#"..follow, w+200, h, 255, 255, 255, true))
614 626 end
  627 +
  628 + if player.randventurer_seed then
  629 + local text = ("- Seed: #LIGHT_STEEL_BLUE#%s"):tformat(player.randventurer_seed)
  630 + h = h + self.font_h
  631 + self:mouseClick(function() core.key.setClipboard(player.randventurer_seed) Dialog:simplePopup("Wanderer Seed", "Copied to clipboard!") end, _t"Click to copy to clipboard. You can share the wanderer seed with your friends, this way they can play with the same set of talents.", s:drawColorStringBlended(self.font, text, w, h, 255, 255, 255, true))
  632 + end
  633 +
615 634 h = h + self.font_h
616 635 s:drawStringBlended(self.font, _t"Size : "..(player:TextSizeCategory():capitalize()), w, h, 0, 200, 255, true) h = h + self.font_h
617 636 h = h + self.font_h
... ...
  1 +-- ToME - Tales of Maj'Eyal
  2 +-- Copyright (C) 2009 - 2019 Nicolas Casalini
  3 +--
  4 +-- This program is free software: you can redistribute it and/or modify
  5 +-- it under the terms of the GNU General Public License as published by
  6 +-- the Free Software Foundation, either version 3 of the License, or
  7 +-- (at your option) any later version.
  8 +--
  9 +-- This program is distributed in the hope that it will be useful,
  10 +-- but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 +-- GNU General Public License for more details.
  13 +--
  14 +-- You should have received a copy of the GNU General Public License
  15 +-- along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +--
  17 +-- Nicolas Casalini "DarkGod"
  18 +-- darkgod@te4.org
  19 +
  20 +require "engine.class"
  21 +local Dialog = require "engine.ui.Dialog"
  22 +local Separator = require "engine.ui.Separator"
  23 +local List = require "engine.ui.List"
  24 +local Button = require "engine.ui.Button"
  25 +local ButtonImage = require "engine.ui.ButtonImage"
  26 +local Textbox = require "engine.ui.Textbox"
  27 +local Textzone = require "engine.ui.Textzone"
  28 +local Checkbox = require "engine.ui.Checkbox"
  29 +
  30 +module(..., package.seeall, class.inherit(Dialog))
  31 +
  32 +function _M:init(actor, birth, finish)
  33 + self.actor = actor
  34 + self.birth = birth
  35 + self.finish = finish
  36 +
  37 + Dialog.init(self, _t"Wanderer Options", 800, 300)
  38 +
  39 + local explain = Textzone.new{width=self.iw, auto_height=true, text=_t[[Welcome, wandering one! The Wanderer class uses a randomly selected set of talent trees.
  40 +You can now choose how this set is selected:]]}
  41 + local explain_random = Textzone.new{width=self.iw - 32, auto_height=true, text=_t[[Simply make a random set of trees, this is the default option. If you want to share it with friends, you will find the seed in the character's sheet later on.]]}
  42 + local explain_seed = Textzone.new{width=self.iw - 32, auto_height=true, text=_t[[If an other player gave you a seed to play, you can enter it here. Do note that while a seed will always work, you will only get the same talents set if you use the same DLC/addons.]]}
  43 +
  44 + local play = Button.new{text=_t"Play!", fct=function() game:unregisterDialog(self) self:makeWanderer() end}
  45 + local sep = Separator.new{dir="vertical", size=self.iw}
  46 + self.c_randomoption = Checkbox.new{title=_t"#{bold}##ANTIQUE_WHITE#Random#{normal}##LAST#", default=true,
  47 + on_change=function(c) if c then self:swapMode("random") else self.c_randomoption.checked = true end end,
  48 + }
  49 + self.c_seedoption = Checkbox.new{title=_t"#{bold}##ANTIQUE_WHITE#Seed#{normal}##LAST#", default=false,
  50 + on_change=function(c) if c then self:swapMode("seed") else self.c_seedoption.checked = true end end,
  51 + }
  52 + self.c_seed = Textbox.new{title=" "--[[do not translate]], text=__module_extra_info.tome_wanderer_seed or "", chars=40, max_len=200, fct=function() end, on_change=function(text) self:setSeed(text) end}
  53 + self:setSeed(__module_extra_info.tome_wanderer_seed)
  54 +
  55 + self:loadUI{
  56 + {left=0, top=0, ui=explain},
  57 + {left=0, top=explain, ui=sep},
  58 + {left=0, top=sep, ui=self.c_randomoption},
  59 + {left=32, top=self.c_randomoption, ui=explain_random},
  60 + {left=0, top=explain_random, ui=self.c_seedoption},
  61 + {left=self.c_seedoption, top=explain_random, ui=self.c_seed, hidden=true},
  62 + {left=32, top=self.c_seedoption, ui=explain_seed},
  63 + {hcenter=0, bottom=0, ui=play},
  64 + }
  65 + self:setupUI(false, true)
  66 +end
  67 +
  68 +function _M:swapMode(mode)
  69 + if mode == "random" then
  70 + self.c_randomoption.checked = true
  71 + self.c_seedoption.checked = false
  72 + self:toggleDisplay(self.c_seed, false)
  73 + elseif mode == "seed" then
  74 + self.c_randomoption.checked = false
  75 + self.c_seedoption.checked = true
  76 + self:toggleDisplay(self.c_seed, true)
  77 + end
  78 + self.mode = mode
  79 +end
  80 +
  81 +function _M:setSeed(seed)
  82 + if not seed then return end
  83 + self.use_seed = seed
  84 +end
  85 +
  86 +function _M:makeWanderer()
  87 + local birth = self.birth
  88 + local actor = self.actor
  89 + local tts_class = {}
  90 + local tts_generic = {}
  91 + local tts_addons = {}
  92 +
  93 + -- Find all available trees
  94 + for _, class in ipairs(birth.all_classes) do if class.id ~= "Adventurer" then
  95 + 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
  96 + if birth.birth_descriptor_def.subclass[sclass.id].talents_types then
  97 + local tt = birth.birth_descriptor_def.subclass[sclass.id].talents_types
  98 + if type(tt) == "function" then tt = tt(birth) end
  99 +
  100 + for t, _ in pairs(tt) do
  101 + local tt_def = actor:getTalentTypeFrom(t)
  102 + if tt_def then
  103 + tts_addons[tt_def.source] = true
  104 + if tt_def.generic then
  105 + table.insert(tts_generic, t)
  106 + else
  107 + table.insert(tts_class, t)
  108 + end
  109 + end
  110 + end
  111 + end
  112 +
  113 + if birth.birth_descriptor_def.subclass[sclass.id].unlockable_talents_types then
  114 + local tt = birth.birth_descriptor_def.subclass[sclass.id].unlockable_talents_types
  115 + if type(tt) == "function" then tt = tt(birth) end
  116 +
  117 + for t, v in pairs(tt) do
  118 + if profile.mod.allow_build[v[3]] then
  119 + local tt_def = actor:getTalentTypeFrom(t)
  120 + if tt_def then
  121 + tts_addons[tt_def.source] = true
  122 + if tt_def.generic then
  123 + table.insert(tts_generic, t)
  124 + else
  125 + table.insert(tts_class, t)
  126 + end
  127 + end
  128 + end
  129 + end
  130 + end
  131 + end end
  132 + end end
  133 + actor.randventurer_class_trees = tts_class
  134 + actor.randventurer_generic_trees = tts_generic
  135 +
  136 + -- Compute the addons fingerprint
  137 + local md5 = require "md5"
  138 + tts_addons['@vanilla@'] = nil
  139 + actor.randventurer_addons = {game.__mod_info.version_string}
  140 + for a, _ in pairs(tts_addons) do
  141 + local addon = game.__mod_info and game.__mod_info.addons and game.__mod_info.addons[a]
  142 + if addon then
  143 + table.insert(actor.randventurer_addons, a.."-"..(addon.addon_version_txt or addon.version_txt or "???"))
  144 + else -- Shouldnt happen but heh
  145 + table.insert(actor.randventurer_addons, a)
  146 + end
  147 + end
  148 + -- Sort addons so that the fingerprint has meaning ;)
  149 + table.sort(actor.randventurer_addons)
  150 + local addons_md5 = mime.b64(md5.sum(table.concat(actor.randventurer_addons,'|')))
  151 + actor.randventurer_fingerprint = addons_md5
  152 +
  153 + -- Make the seed, or use the given one
  154 + local seed = rng.range(1, 99999999)
  155 + if self.mode == "seed" and self.use_seed then
  156 + 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 may not have the same talent set as the person that shared the seed with you.") end) end
  157 + local _, _, iseed, check = self.use_seed:find("^([0-9]+)%-(.*)$")
  158 + if not check or not tonumber(iseed) then
  159 + error()
  160 + else
  161 + seed = tonumber(iseed)
  162 + if check ~= addons_md5 then error() end
  163 + end
  164 + end
  165 + rng.seed(seed)
  166 + table.sort(actor.randventurer_class_trees)
  167 + table.sort(actor.randventurer_generic_trees)
  168 + table.shuffle(actor.randventurer_class_trees)
  169 + table.shuffle(actor.randventurer_generic_trees)
  170 +
  171 + actor.randventurer_seed = seed.."-"..addons_md5
  172 +
  173 + rng.seed(os.time())
  174 +
  175 + -- Give the starting trees
  176 + actor:randventurerLearn("class", true)
  177 + actor:randventurerLearn("class", true)
  178 + actor:randventurerLearn("class", true)
  179 + actor:randventurerLearn("generic", true)
  180 +
  181 + self.finish()
  182 +end
... ...