diff --git a/game/engines/default/engine/UserChat.lua b/game/engines/default/engine/UserChat.lua index 1763709e65011a62e709fb26e3761470847c54d8..631850d78bf8a4b1bed865c87c6c826fb01e9965 100644 --- a/game/engines/default/engine/UserChat.lua +++ b/game/engines/default/engine/UserChat.lua @@ -417,8 +417,6 @@ function _M:mouseEvent(button, x, y, xrel, yrel, bx, by, event) local item = self.dlist[i] if item.dh and by >= item.dh - self.mouse.delegate_offset_y then citem = self.dlist[i].src ci=i break end end - print("================================") - util.show_backtrace() for i = 1, #self.dlist do local item = self.dlist[i] if item.dh then print("===", y, by, item.dh - self.mouse.delegate_offset_y, ci==i and "*****" or "") end diff --git a/game/engines/default/engine/ui/Dialog.lua b/game/engines/default/engine/ui/Dialog.lua index 6b0529cdc043802db85cea2b94fa037a97c04330..df596139812de4bb34116e260ad06fc540c1e290 100644 --- a/game/engines/default/engine/ui/Dialog.lua +++ b/game/engines/default/engine/ui/Dialog.lua @@ -57,7 +57,7 @@ function _M:listPopup(title, text, list, w, h, fct) {left = 3, bottom = 3, ui=l}, } d.key:addBind("EXIT", function() game:unregisterDialog(d) if fct then fct() end end) - d.key:addBind("ACCEPT", function() game:unregisterDialog(d) if fct then fct(list[l.sel]) end end) + d.key:addBind("ACCEPT", function() game:unregisterDialog(d) if list[l.sel].fct then list[l.sel].fct(list[l.sel]) return end if fct then fct(list[l.sel]) end end) d:setFocus(l) d:setupUI(true, true) game:registerDialog(d) diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index e15ca67c945aa89b2b404ef7d0572fbd24d6f5e2..52dfe655fcb0c254de5bf330abaa655e875aa78c 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -292,6 +292,10 @@ function _M:actBase() return end + if self.__use_build_order then + self:useBuildOrder() + end + if self:isTalentActive (self.T_DARKEST_LIGHT) and self.positive > self.negative then self:forceUseTalent(self.T_DARKEST_LIGHT, {ignore_energy=true}) game.logSeen(self, "%s's darkness can no longer hold back the light!", self.name:capitalize()) @@ -525,6 +529,131 @@ function _M:act() return true end +--- Follow a build order as possible +function _M:useBuildOrder() + local b = self.__use_build_order + + if self.unused_stats > 0 then + b.stats.i = b.stats.i or 1 + local nb = 0 + + while self.unused_stats > 0 and nb < #b.stats+1 do + local stat = b.stats[b.stats.i] + + if not (self:getStat(stat, nil, nil, true) >= self.level * 1.4 + 20) and + not (self:isStatMax(stat) or self:getStat(stat, nil, nil, true) >= 60 + math.max(0, (self.level - 50))) then + self:incStat(stat, 1) + self.unused_stats = self.unused_stats - 1 + nb = -1 + game.log("#VIOLET#Following build order %s; increasing %s by 1.", b.name, self.stats_def[stat].name) + end + b.stats.i = util.boundWrap(b.stats.i + 1, 1, #b.stats) + nb = nb + 1 + end + end + + if self.unused_talents_types > 0 then + self.__increased_talent_types = self.__increased_talent_types or {} + + local learn = true + while learn do + learn = false + for i, tt in ipairs(b.types) do + if self.unused_talents_types > 0 and (self.__increased_talent_types[tt] or 0) == 0 then + if not self:knowTalentType(tt) then + self:learnTalentType(tt) + else + self.__increased_talent_types[tt] = (self.__increased_talent_types[tt] or 0) + 1 + self:setTalentTypeMastery(tt, self:getTalentTypeMastery(tt) + 0.2) + end + + game.log("#VIOLET#Following build order %s; learning talent category %s.", b.name, tt) + self.unused_talents_types = self.unused_talents_types - 1 + table.remove(b.types, i) + learn = true + break + end + end + end + end + + if self.unused_talents > 0 then + local learn = true + while learn do + learn = false + for i, td in ipairs(b.talents) do + if td.kind == "class" then + local t = self:getTalentFromId(td.tid) + + if self.unused_talents > 0 and self:canLearnTalent(t) and self:getTalentLevelRaw(t.id) < t.points then + self:learnTalent(t.id, true) + game.log("#VIOLET#Following build order %s; learning talent %s.", b.name, t.name) + self.unused_talents = self.unused_talents - 1 + table.remove(b.talents, i) + learn = true + break + end + end + end + end + end + + if self.unused_generics > 0 then + local learn = true + while learn do + learn = false + for i, td in ipairs(b.talents) do + if td.kind == "generic" then + local t = self:getTalentFromId(td.tid) + + if self.unused_generics > 0 and self:canLearnTalent(t) and self:getTalentLevelRaw(t.id) < t.points then + self:learnTalent(t.id, true) + game.log("#VIOLET#Following build order %s; learning talent %s.", b.name, t.name) + self.unused_generics = self.unused_generics - 1 + table.remove(b.talents, i) + learn = true + break + end + end + end + end + end +end + +function _M:loadBuildOrder(file) + local f = fs.open("/build-orders/"..file, "r") + if not f then return end + + local b = {name="xxx", stats={}, talents={}, types={}} + + local cur = "name" + while true do + local line = f:readLine() + if not line then break end + + if line == "#Name" then cur = "name" + elseif line == "#Stats" then cur = "stats" + elseif line == "#Talents" then cur = "talents" + elseif line == "#Types" then cur = "types" + else + if cur == "name" then b.name = line + elseif cur == "stats" then + b.stats = line:split(',') + elseif cur == "talents" then + local t = line:split(',') + table.insert(b.talents, {kind=t[2], tid=t[3]}) + elseif cur == "types" then + local tt = line:split(',') + table.insert(b.types, tt[2]) + end + end + end + + if #b.stats > 0 and #b.talents > 0 then + self.__use_build_order = b + end +end + --- Setup minimap color for this entity -- You may overload this method to customize your minimap function _M:setupMinimapInfo(mo, map) @@ -1349,7 +1478,7 @@ function _M:onTakeHit(value, src) t.absorb(self, t, self:isTalentActive(self.T_BONE_SHIELD)) value = 0 end - + if self.knowTalent and (self:knowTalent(self.T_SEETHE) or self:knowTalent(self.T_GRIM_RESOLVE)) then if not self:hasEffect(self.EFF_CURSED_FORM) then self:setEffect(self.EFF_CURSED_FORM, 1, { increase=0 }) @@ -1706,7 +1835,7 @@ function _M:die(src, death_note) if src and src.knowTalent and src:knowTalent(src.T_UNENDING_FRENZY) then src:incStamina(src:getTalentLevel(src.T_UNENDING_FRENZY) * 2) end - + -- Regain Psi if src and src.attr and src:attr("psi_per_kill") then src:incPsi(src:attr("psi_per_kill")) @@ -3478,7 +3607,7 @@ end -- @return can_project, stop_x, stop_y, radius_x, radius_y. function _M:canProject(t, x, y) local can_project, stop_x, stop_y, radius_x, radius_y = engine.interface.ActorProject.canProject(self, t, x, y) - + -- add line of sight to can project unless pass_block_sight or pass_terrain has been set if not t.pass_terain and not t.pass_block_sight and can_project then if not self:hasLOS(x, y) then can_project = false end @@ -3513,14 +3642,14 @@ function _M:on_project(tx, ty, who, t, x, y, damtype, dam, particles) game.logSeen(self, "%s ignores the spell!", self.name:capitalize()) return true end - + -- LOS check (this is also caught by canProject) if not t.pass_terain and not t.pass_block_sight then if not who:hasLOS(tx, ty) then return true end end - + return false end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 1ebbdac986a660e6283fc24f3d0ac2dd364aa871..9bf46291ef74ba9229ee5177f8ecad4657c07582 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -1115,7 +1115,7 @@ function _M:setupCommands() end end end end, [{"_g","ctrl"}] = function() if config.settings.cheat then - self.state:debugRandomZone() + self.player:loadBuildOrder("archmage-1.csv") end end, [{"_f","ctrl"}] = function() if config.settings.cheat then self.player.quests["love-melinda"] = nil diff --git a/game/modules/tome/data/general/objects/egos/staves.lua b/game/modules/tome/data/general/objects/egos/staves.lua index 92ab11c841a0a95348ea7ab5751a240c04dfbcfe..b6af17cfb13ac4f2f16544ad8e448a62e5926a10 100644 --- a/game/modules/tome/data/general/objects/egos/staves.lua +++ b/game/modules/tome/data/general/objects/egos/staves.lua @@ -221,7 +221,7 @@ newEntity{ local tg = {type="bolt", range= 5 + self.material_level, speed=20, display = {particle=particle, trail=trail},} local weapon = who:hasStaffWeapon() local combat = weapon.combat - + local DamageType = require "engine.DamageType" local damtype = combat.damtype if damtype == DamageType.FIRE then explosion = "flame" particle = "bolt_fire" trail = "firetrail" @@ -236,16 +236,16 @@ newEntity{ elseif damtype == DamageType.TEMPORAL then explosion = "light" particle = "temporal_bolt" trail = "lighttrail" else explosion = "manathrust" particle = "bolt_arcane" trail = "arcanetrail" damtype = DamageType.ARCANE end - + local x, y = who:getTarget(tg) if not x or not y then return nil end - + -- Compute damage local dam = who:combatDamage(combat) local damrange = who:combatDamageRange(combat) dam = rng.range(dam, dam * damrange) dam = who:spellCrit(dam) - + who:projectile(tg, x, y, damtype, dam, {type=explosion}) game.logSeen(who, "%s fires a bolt from %s!", who.name:capitalize(), self.name) @@ -308,28 +308,28 @@ newEntity{ local tg = {type="ball", range=0, radius=self.material_level + 1, selffire=false} local weapon = who:hasStaffWeapon() local combat = weapon.combat - + local DamageType = require "engine.DamageType" local damtype = combat.damtype - if damtype == DamageType.FIRE then explosion = "flame" - elseif damtype == DamageType.COLD then explosion = "freeze" - elseif damtype == DamageType.ACID then explosion = "acid" - elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion" - elseif damtype == DamageType.LIGHT then explosion = "light" - elseif damtype == DamageType.DARKNESS then explosion = "dark" - elseif damtype == DamageType.NATURE then explosion = "slime" - elseif damtype == DamageType.BLIGHT then explosion = "slime" - elseif damtype == DamageType.PHYSICAL then explosion = "dark" - elseif damtype == DamageType.TEMPORAL then explosion = "light" + if damtype == DamageType.FIRE then explosion = "flame" + elseif damtype == DamageType.COLD then explosion = "freeze" + elseif damtype == DamageType.ACID then explosion = "acid" + elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion" + elseif damtype == DamageType.LIGHT then explosion = "light" + elseif damtype == DamageType.DARKNESS then explosion = "dark" + elseif damtype == DamageType.NATURE then explosion = "slime" + elseif damtype == DamageType.BLIGHT then explosion = "slime" + elseif damtype == DamageType.PHYSICAL then explosion = "dark" + elseif damtype == DamageType.TEMPORAL then explosion = "light" else explosion = "manathrust" damtype = DamageType.ARCANE end - + -- Compute damage local dam = who:combatDamage(combat) local damrange = who:combatDamageRange(combat) dam = rng.range(dam, dam * damrange) dam = who:spellCrit(dam) - + who:project(tg, who.x, who.y, damtype, dam, {type=explosion}) game.logSeen(who, "%s unleashes an elemental blastwave from %s!", who.name:capitalize(), self.name) @@ -351,7 +351,7 @@ newEntity{ combat_spellpower = resolvers.mbonus_material(10, 2), mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end), }, - resolvers.charm("channel mana (increasing mana regen by 500% for ten turns)", 30, + resolvers.charm("channel mana (increasing mana regen by 500%% for ten turns)", 30, function(self, who) if who.mana_regen > 0 and not who:hasEffect(who.EFF_MANASURGE) then who:setEffect(who.EFF_MANASURGE, 10, {power=who.mana_regen * 5}) @@ -405,31 +405,31 @@ newEntity{ local tg = {type="cone", range=0, radius=self.material_level * 2, selffire=false} local weapon = who:hasStaffWeapon() local combat = weapon.combat - + local DamageType = require "engine.DamageType" local damtype = combat.damtype - if damtype == DamageType.FIRE then explosion = "flame" - elseif damtype == DamageType.COLD then explosion = "freeze" - elseif damtype == DamageType.ACID then explosion = "acid" - elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion" - elseif damtype == DamageType.LIGHT then explosion = "light" - elseif damtype == DamageType.DARKNESS then explosion = "dark" - elseif damtype == DamageType.NATURE then explosion = "slime" - elseif damtype == DamageType.BLIGHT then explosion = "slime" - elseif damtype == DamageType.PHYSICAL then explosion = "dark" - elseif damtype == DamageType.TEMPORAL then explosion = "light" + if damtype == DamageType.FIRE then explosion = "flame" + elseif damtype == DamageType.COLD then explosion = "freeze" + elseif damtype == DamageType.ACID then explosion = "acid" + elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion" + elseif damtype == DamageType.LIGHT then explosion = "light" + elseif damtype == DamageType.DARKNESS then explosion = "dark" + elseif damtype == DamageType.NATURE then explosion = "slime" + elseif damtype == DamageType.BLIGHT then explosion = "slime" + elseif damtype == DamageType.PHYSICAL then explosion = "dark" + elseif damtype == DamageType.TEMPORAL then explosion = "light" else explosion = "manathrust" damtype = DamageType.ARCANE end - + local x, y = who:getTarget(tg) if not x or not y then return nil end - + -- Compute damage local dam = who:combatDamage(combat) local damrange = who:combatDamageRange(combat) dam = rng.range(dam, dam * damrange) dam = who:spellCrit(dam) - + who:project(tg, x, y, damtype, dam, {type=explosion}) game.logSeen(who, "%s conjures a cone of elemental energy from %s!", who.name:capitalize(), self.name) diff --git a/game/modules/tome/data/general/objects/egos/wands.lua b/game/modules/tome/data/general/objects/egos/wands.lua index 88aada553d85716f41a5e6aafc6933ed034edc55..bfc8973a0188482eaab023d48ddd75ba4a601a43 100644 --- a/game/modules/tome/data/general/objects/egos/wands.lua +++ b/game/modules/tome/data/general/objects/egos/wands.lua @@ -23,6 +23,7 @@ newEntity{ rarity = 15, cost = 5, resolvers.genericlast(function(e) + if not e.use_power or not e.charm_power then return end e.use_power.power = math.ceil(e.use_power.power * rng.float(0.6, 0.8)) e.charm_power = math.ceil(e.charm_power * rng.float(0.4, 0.7)) end), @@ -34,6 +35,7 @@ newEntity{ rarity = 15, cost = 5, resolvers.genericlast(function(e) + if not e.use_power or not e.charm_power then return end e.use_power.power = math.ceil(e.use_power.power * rng.float(1.2, 1.5)) e.charm_power = math.ceil(e.charm_power * rng.float(1.3, 1.5)) end), @@ -44,7 +46,7 @@ Wands *detection *light *trap destruction -*flame +*firewall *lightning *conjuration @@ -154,17 +156,19 @@ newEntity{ } newEntity{ - name = " of flames", suffix=true, instant_resolve=true, + name = " of firewall", suffix=true, instant_resolve=true, level_range = {15, 50}, rarity = 10, charm_power_def = {add=25, max=250, floor=true}, - resolvers.charm("fire a beam of flames (dam %d)", 6, function(self, who) - local tg = {type="beam", range=6 + who:getMag(4)} + resolvers.charm("creates a wall of flames lasting for 4 turns (dam %d overall)", 6, function(self, who) + local tg = {type="wall", range=5, halflength=3, halfmax_spots=3+1} local x, y = who:getTarget(tg) if not x or not y then return nil end local dam = self:getCharmPower() - who:project(tg, x, y, engine.DamageType.FIRE, dam, {type="flame"}) + who:project(tg, x, y, function(px, py) + game.level.map:addEffect(who, px, py, 4, engine.DamageType.FIRE, dam / 4, 0, 5, nil, {type="inferno"}, nil, true) + end) game:playSoundNear(who, "talents/fire") game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true}) return {id=true, used=true} diff --git a/game/modules/tome/dialogs/LevelupDialog.lua b/game/modules/tome/dialogs/LevelupDialog.lua index c8fe9e1320442772edbe9aadf267c4074da47b19..8b3d2893dbfae5b6a3854301db6477b21038c4e7 100644 --- a/game/modules/tome/dialogs/LevelupDialog.lua +++ b/game/modules/tome/dialogs/LevelupDialog.lua @@ -798,6 +798,7 @@ function _M:learnType(tt, v) self.actor:setTalentTypeMastery(tt, self.actor:getTalentTypeMastery(tt) + 0.2) self.talent_types_learned[tt][2] = true end + self:triggerHook{"PlayerLevelup:addTalentType", actor=self.actor, tt=tt} self.actor.unused_talents_types = self.actor.unused_talents_types - 1 self.new_talents_changed = true else @@ -833,6 +834,7 @@ function _M:learnType(tt, v) return end end + self:triggerHook{"PlayerLevelup:subTalentType", actor=self.actor, tt=tt} end end diff --git a/ideas/todo b/ideas/todo index 0d3324131ebf7ab377c1566ae71c206ef08ff0bf..fd2a063315958537f45a7695dae782837cc26fbc 100644 --- a/ideas/todo +++ b/ideas/todo @@ -2,7 +2,7 @@ * RSS feed of events in a character's life, exportable to FB * PIC TALENTS AT LVL 45 FOR HIGH STAT, CLASS DEPENDANT * redo shops -* redo wands * random elites wandering the levels * make low level more fun * "automatic" storage of various ingredients, replace alch quest +* auto-leveling for beginners/lazy