diff --git a/game/engines/default/engine/Entity.lua b/game/engines/default/engine/Entity.lua index df65e87de70e818c4715129ba1b3422ecb9bf19d..9be9f9051278d3f7e56bec57e615a18c672a40b0 100644 --- a/game/engines/default/engine/Entity.lua +++ b/game/engines/default/engine/Entity.lua @@ -386,7 +386,7 @@ function _M:getEntityFinalSurface(tiles, w, h) local mos = {} local list = {} - print("===final surface for", self.uid, self.namself, self.x, self.y, self.type, self.subtype) + print("===final surface for", self.uid, self.name, self.x, self.y, self.type, self.subtype) self:getMapObjects(tiles, mos, 1) for i = 1, Map.zdepth do if mos[i] then list[#list+1] = mos[i] end diff --git a/game/engines/default/engine/interface/ActorTalents.lua b/game/engines/default/engine/interface/ActorTalents.lua index aa38b7cff6d0efcfd957ae471bf809e2c8f5880b..57442bc1f911e396680d0af2193fad1d1c2f7f53 100644 --- a/game/engines/default/engine/interface/ActorTalents.lua +++ b/game/engines/default/engine/interface/ActorTalents.lua @@ -302,23 +302,27 @@ end --- Actor forgets a talent -- @param t_id the id of the talent to learn -- @return true if the talent was unlearnt, nil and an error message otherwise -function _M:unlearnTalent(t_id) +function _M:unlearnTalent(t_id, nb) if not self:knowTalent(t_id) then return false, "talent not known" end local t = _M.talents_def[t_id] - if self.talents[t_id] and self.talents[t_id] == 1 then - if self.hotkey then - for i, known_t_id in pairs(self.hotkey) do - if known_t_id[1] == "talent" and known_t_id[2] == t_id then self.hotkey[i] = nil end + nb = math.min(nb or 1, self.talents[t_id]) + + for j = 1, nb do + if self.talents[t_id] and self.talents[t_id] == 1 then + if self.hotkey then + for i, known_t_id in pairs(self.hotkey) do + if known_t_id[1] == "talent" and known_t_id[2] == t_id then self.hotkey[i] = nil end + end end end - end - self.talents[t_id] = self.talents[t_id] - 1 - if self.talents[t_id] == 0 then self.talents[t_id] = nil end + self.talents[t_id] = self.talents[t_id] - 1 + if self.talents[t_id] == 0 then self.talents[t_id] = nil end - if t.on_unlearn then t.on_unlearn(self, t) end + if t.on_unlearn then t.on_unlearn(self, t) end + end self.talents_auto[t_id] = nil diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua index 513cde4ac560d74d58170dd195eada5cefaebcfa..1d66fbfe635c4b65dd657889660ce48132ac109d 100644 --- a/game/engines/default/engine/utils.lua +++ b/game/engines/default/engine/utils.lua @@ -57,6 +57,20 @@ function table.print(src, offset) end end +function table.iprint(src, offset) + offset = offset or "" + for k, e in ipairs(src) do + -- Deep copy subtables, but not objects! + if type(e) == "table" and not e.__CLASSNAME then + print(("%s[%s] = {"):format(offset, tostring(k))) + table.print(e, offset.." ") + print(("%s}"):format(offset)) + else + print(("%s[%s] = %s"):format(offset, tostring(k), tostring(e))) + end + end +end + --- Returns a clone of a table -- @param tbl The original table to be cloned -- @param deep Boolean to determine if recursive cloning occurs diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 78f34d690b981e77763eaa25a757176cc5ea9e4a..be5a5e721223ea23f7088e7eb651ce253a196048 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -2640,7 +2640,7 @@ function _M:unlearnItemTalent(o, tid, level) if self.item_talent_surplus_levels[tid] > 0 then self.item_talent_surplus_levels[tid] = self.item_talent_surplus_levels[tid] - 1 else - self:unlearnTalent(tid, true, 1) + self:unlearnTalent(tid) end end end @@ -2704,8 +2704,8 @@ end --- Actor forgets a talent -- @param t_id the id of the talent to learn -- @return true if the talent was unlearnt, nil and an error message otherwise -function _M:unlearnTalent(t_id) - if not engine.interface.ActorTalents.unlearnTalent(self, t_id, force) then return false end +function _M:unlearnTalent(t_id, nb) + if not engine.interface.ActorTalents.unlearnTalent(self, t_id, nb) then return false end local t = _M.talents_def[t_id] diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index d20ca60b0b5923a9fc2da00124d31eedbe223c8e..e971c68d51a402b9e39b109fb958eafcdbad8dc3 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -192,7 +192,7 @@ function _M:newGame() end for i = 1, 50 do - local o = self.state:generateRandart(true) + local o = self.state:generateRandart{add_pool=true} self.zone.object_list[#self.zone.object_list+1] = o end @@ -1167,7 +1167,10 @@ function _M:setupCommands() end end end end, [{"_g","ctrl"}] = function() if config.settings.cheat then - self:registerDialog(require("mod.dialogs.DownloadCharball").new()) +-- self:registerDialog(require("mod.dialogs.DownloadCharball").new()) + local o = game.state:generateRandart{lev=50, egos=0, power_points_factor=8, nb_powers_add=6} + o:identify(true) + game.zone:addEntity(game.level,o,"object",game.player.x,game.player.y) end end, [{"_f","ctrl"}] = function() if config.settings.cheat then self.player.quests["love-melinda"] = nil diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua index 522f4a11ad53fccee1b70c186f374ff9b487c14c..4488e5771dbc089e72cf95fac0d819a09a9d451e 100644 --- a/game/modules/tome/class/GameState.lua +++ b/game/modules/tome/class/GameState.lua @@ -229,19 +229,20 @@ local randart_name_rules = { } --- Generate randarts for this state -function _M:generateRandart(add, base, lev, nb_egos) +function _M:generateRandart(data) + if not self.randart_powers then self.randart_powers = engine.Object:loadList("/data/general/objects/random-artifacts.lua") end local powers_list = self.randart_powers -- Setup level - lev = lev or rng.range(12, 50) + local lev = data.lev or rng.range(12, 50) local oldlev = game.level.level local oldclev = resolvers.current_level game.level.level = lev resolvers.current_level = math.ceil(lev * 1.4) -- Get a base object - base = base or game.zone:makeEntity(game.level, "object", {ingore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}, special=function(e) + local base = data.base or game.zone:makeEntity(game.level, "object", {ingore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}, special=function(e) return (not e.unique and e.randart_able) and (not e.material_level or e.material_level >= 2) and true or false end}, nil, true) if not base then game.level.level = oldlev resolvers.current_level = oldclev return end @@ -259,8 +260,8 @@ function _M:generateRandart(add, base, lev, nb_egos) ----------------------------------------------------------- -- Determine power ----------------------------------------------------------- - local points = math.ceil((lev * 0.7 + rng.range(5, 15)) / 2) - local nb_powers = 1 + rng.dice(math.max(1, lev / 17), 2) + local points = math.ceil((lev * 0.7 + rng.range(5, 15)) / 2) * (data.power_points_factor or 1) + local nb_powers = 1 + rng.dice(math.max(1, lev / 17), 2) + (data.nb_powers_add or 0) local powers = {} o.cost = o.cost + points * 7 @@ -276,6 +277,7 @@ function _M:generateRandart(add, base, lev, nb_egos) powers[#powers+1] = p end end + print("Selected powers:") table.print(powers) power_themes = table.listify(power_themes) table.sort(power_themes, function(a, b) return a[2] < b[2] end) @@ -311,7 +313,8 @@ function _M:generateRandart(add, base, lev, nb_egos) ----------------------------------------------------------- -- Add ego properties ----------------------------------------------------------- - if o.egos then + local nb_egos = data.egos or 3 + if o.egos and nb_egos > 0 then local legos = {} local been_greater = 0 table.insert(legos, game.level:getEntitiesList("object/"..o.egos..":prefix")) @@ -345,7 +348,7 @@ function _M:generateRandart(add, base, lev, nb_egos) print("table.mergeAddAppendArray failed at creating a randart, retrying") game.level.level = oldlev resolvers.current_level = oldclev - return self:generateRandart(add, base, lev, nb_egos) + return self:generateRandart(data) end end end @@ -391,7 +394,7 @@ function _M:generateRandart(add, base, lev, nb_egos) merger(o.wielder, p.wielder) end if p.copy then merger(o, p.copy) end --- print(" * adding power: "..p.name) + print(" * adding power: "..p.name) end hpoints = hpoints - p.points end @@ -413,7 +416,7 @@ function _M:generateRandart(add, base, lev, nb_egos) merger(o.wielder, p.wielder) end if p.copy then merger(o, p.copy) end --- print(" * adding power: "..p.name) + print(" * adding bias power: "..p.name) end hpoints = hpoints - (p and p.points or 1) * 2 end @@ -421,7 +424,7 @@ function _M:generateRandart(add, base, lev, nb_egos) -- Setup the name o.name = name - if add then self:addWorldArtifact(o) end + if data.add_pool then self:addWorldArtifact(o) end game.level.level = oldlev resolvers.current_level = oldclev @@ -1653,6 +1656,7 @@ function _M:createRandomBoss(base, data) end b.rnd_boss_on_added_to_level = b.on_added_to_level + b._rndboss_resources_boost = data.resources_boost b.on_added_to_level = function(self, ...) self:check("birth_create_alchemist_golem") for tid, lev in pairs(self.learn_tids) do @@ -1666,10 +1670,10 @@ function _M:createRandomBoss(base, data) self.on_added_to_level = nil -- Cheat a bit with ressources - self.max_mana = self.max_mana * (data.resources_boost or 3) self.mana_regen = self.mana_regen + 1 - self.max_vim = self.max_vim * (data.resources_boost or 3) self.vim_regen = self.vim_regen + 1 - self.max_stamina = self.max_stamina * (data.resources_boost or 3) self.stamina_regen = self.stamina_regen + 1 - self.max_psi = self.max_psi * (data.resources_boost or 3) self.psi_regen = self.psi_regen + 2 + self.max_mana = self.max_mana * (self._rndboss_resources_boost or 3) self.mana_regen = self.mana_regen + 1 + self.max_vim = self.max_vim * (self._rndboss_resources_boost or 3) self.vim_regen = self.vim_regen + 1 + self.max_stamina = self.max_stamina * (self._rndboss_resources_boost or 3) self.stamina_regen = self.stamina_regen + 1 + self.max_psi = self.max_psi * (self._rndboss_resources_boost or 3) self.psi_regen = self.psi_regen + 2 self.equilibrium_regen = self.equilibrium_regen - 2 self:resetToFull() end diff --git a/game/modules/tome/data/autolevel_schemes.lua b/game/modules/tome/data/autolevel_schemes.lua index 1a9cba3f0e9913905be792a8d3e0dcebeedbc877..c78f1e391a230d6e4d63a82421d3e7e6dfe142ae 100644 --- a/game/modules/tome/data/autolevel_schemes.lua +++ b/game/modules/tome/data/autolevel_schemes.lua @@ -99,5 +99,5 @@ Autolevel:registerScheme{ name = "warriorwill", levelup = function(self) end} Autolevel:registerScheme{ name = "random_boss", levelup = function(self) - self:learnStats(self.auto_stats) + pcall(function() self:learnStats(self.auto_stats) end) end} diff --git a/game/modules/tome/data/birth/classes/psionic.lua b/game/modules/tome/data/birth/classes/psionic.lua index efadffd7acb0c6c03ecf7c7fdf7c69d1581d5954..229387a4876ef6cb8063687290612e479c64c515 100644 --- a/game/modules/tome/data/birth/classes/psionic.lua +++ b/game/modules/tome/data/birth/classes/psionic.lua @@ -31,6 +31,7 @@ newBirthDescriptor{ { __ALL__ = "disallow", Mindslayer = "allow", + Psion = "allow", }, }, copy = { @@ -110,3 +111,36 @@ newBirthDescriptor{ life_rating = -4, }, } + +newBirthDescriptor{ + type = "subclass", + name = "Psion", + locked = function() return profile.mod.allow_build.psionic_psion end, + locked_desc = "TODO", + desc = { + "blahblah", + "Their most important stats are: Willpower and Cunning", + "#GOLD#Stat modifiers:", + "#LIGHT_BLUE# * +1 Strength, +0 Dexterity, +0 Constitution", + "#LIGHT_BLUE# * +0 Magic, +4 Willpower, +4 Cunning", + }, + power_source = {psionic=true}, + stats = { str=0, wil=5, cun=4, }, + talents_types = { + ["psionic/possession"]={true, 0.3}, + }, + talents = { + [ActorTalents.T_POSSESS] = 1, + }, + copy = { + max_life = 90, + resolvers.equip{ id=true, + {type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000}, + {type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000}, + {type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000}, + }, + }, + copy_add = { + life_rating = -4, + }, +} diff --git a/game/modules/tome/data/birth/classes/wilder.lua b/game/modules/tome/data/birth/classes/wilder.lua index ed754b02802094aca03bbe2ab90bebba48491e3f..a4356021aa1a0b841b16f528b7e744a22236dd11 100644 --- a/game/modules/tome/data/birth/classes/wilder.lua +++ b/game/modules/tome/data/birth/classes/wilder.lua @@ -34,6 +34,7 @@ newBirthDescriptor{ Summoner = "allow", Wyrmic = "allow", ["Stone Warden"] = "allow", + Oozemancer = "allow", }, }, copy = { @@ -183,3 +184,35 @@ newBirthDescriptor{ life_rating = 2, }, } + +newBirthDescriptor{ + type = "subclass", + name = "Oozemancer", + locked = function() return profile.mod.allow_build.wilder_oozemancer end, + locked_desc = "TODO", + desc = { + "Bla bla", + "Their most important stats are: Willpower and Cunning", + "#GOLD#Stat modifiers:", + "#LIGHT_BLUE# * +0 Strength, +0 Dexterity, +0 Constitution", + "#LIGHT_BLUE# * +0 Magic, +5 Willpower, +4 Cunning", + }, + power_source = {nature=true}, + stats = { wil=5, cun=4, }, + talents_types = { + ["wild-gift/call"]={true, 0.2}, + ["wild-gift/harmony"]={false, 0.1}, + ["wild-gift/mindstar-mastery"]={true, 0.3}, + }, + talents = { + [ActorTalents.T_PSIBLADES] = 1, + }, + copy = { + max_life = 90, + resolvers.equip{ id=true, + {type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000}, + {type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000}, + {type="armor", subtype="light", name="rough leather armour", autoreq=true, ego_chance=-1000}, + }, + }, +} diff --git a/game/modules/tome/data/chats/last-hope-lost-merchant.lua b/game/modules/tome/data/chats/last-hope-lost-merchant.lua index 557ae44591e724fb10434306bbd3288016356784..055dc6683a57891e44c45d3c658ff5863fd17ba3 100644 --- a/game/modules/tome/data/chats/last-hope-lost-merchant.lua +++ b/game/modules/tome/data/chats/last-hope-lost-merchant.lua @@ -78,13 +78,13 @@ local maker_list = function() local o = game.zone:makeEntity(game.level, "object", {name=name, ingore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}}, nil, true) if o then l[#l+1] = {o:getName{force_id=true, do_color=true, no_count=true}, action=function(npc, player) - local art = game.state:generateRandart(nil, o, 70, 4) + local art = game.state:generateRandart{base=o, lev=70, egos=4} if art then art:identify(true) player:addObject(player.INVEN_INVEN, art) player:incMoney(-4000) -- clear chrono worlds and their various effects - if game._chronoworlds then + if game._chronoworlds then game.log("#CRIMSON#Your timetravel has no effect on pre-determined outcomes such as this.") game._chronoworlds = nil end diff --git a/game/modules/tome/data/general/objects/egos/totems.lua b/game/modules/tome/data/general/objects/egos/totems.lua index 4df05747541e49b7d324da6a5d82dfe344568017..88b51deb7a66fb6aec3dd9c077c4de5d80acc0ec 100644 --- a/game/modules/tome/data/general/objects/egos/totems.lua +++ b/game/modules/tome/data/general/objects/egos/totems.lua @@ -100,7 +100,7 @@ newEntity{ level_range = {30, 50}, rarity = 12, greater_ego = 1, - cost = 5, + cost = 15, wielder = { talent_cd_reduction={[Talents.T_INVOKE_TENTACLE]=-5}, diff --git a/game/modules/tome/data/general/objects/random-artifacts.lua b/game/modules/tome/data/general/objects/random-artifacts.lua index 74171ddcbef414aa8beb0887d1c88d6dc7fd6288..ffa27e1c1b5a538a1fb835460e707cb98aceb6a7 100644 --- a/game/modules/tome/data/general/objects/random-artifacts.lua +++ b/game/modules/tome/data/general/objects/random-artifacts.lua @@ -33,6 +33,19 @@ newEntity{ theme={spell=true, sorcerous=true}, name="spell crit magnitude", poin wielder = { combat_critical_power = resolvers.randartmax(1, 12), }, } +---------------------------------------------------------------- +-- Mindpower +---------------------------------------------------------------- +newEntity{ theme={mind=true, mindcraft=true}, name="mindpower", points = 1, rarity = 8, level_range = {1, 50}, + wielder = { combat_mindpower = resolvers.randartmax(1, 28), }, +} +newEntity{ theme={mind=true, mindcraft=true}, name="mindcrit", points = 1, rarity = 10, level_range = {1, 50}, + wielder = { combat_mindcrit = resolvers.randartmax(1, 15), }, +} +newEntity{ theme={mind=true, mindcraft=true}, name="mind crit magnitude", points = 1, rarity = 15, level_range = {1, 50}, + wielder = { combat_critical_power = resolvers.randartmax(1, 12), }, +} + ---------------------------------------------------------------- -- Physical damage ---------------------------------------------------------------- @@ -163,34 +176,34 @@ newEntity{ theme={attack=true, psionic=true}, name="inc damage mind", points = 1 -- Immunes ---------------------------------------------------------------- newEntity{ theme={def=true, unyielding=true}, name="immune stun", points = 1, rarity = 7, level_range = {1, 50}, - wielder = { stun_immune = resolvers.randartmax(0.05, 1), }, + wielder = { stun_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, brawny=true, unyielding=true}, name="immune knockback", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { knockback_immune = resolvers.randartmax(0.05, 1), }, + wielder = { knockback_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, sorcerous=true}, name="immune blind", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { blind_immune = resolvers.randartmax(0.05, 1), }, + wielder = { blind_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, psionic=true}, name="immune confusion", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { confusion_immune = resolvers.randartmax(0.05, 1), }, + wielder = { confusion_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, brawny=true}, name="immune pin", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { pin_immune = resolvers.randartmax(0.05, 1), }, + wielder = { pin_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, venom=true, nature=true}, name="immune poison", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { poison_immune = resolvers.randartmax(0.05, 1), }, + wielder = { poison_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, venom=true, nature=true}, name="immune disease", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { disease_immune = resolvers.randartmax(0.05, 1), }, + wielder = { disease_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, sorcerous=true}, name="immune silence", points = 1, rarity = 11, level_range = {1, 50}, - wielder = { silence_immune = resolvers.randartmax(0.05, 1), }, + wielder = { silence_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, nimble=true, unyielding=true}, name="immune disarm", points = 1, rarity = 11, level_range = {1, 50}, - wielder = { disarm_immune = resolvers.randartmax(0.05, 1), }, + wielder = { disarm_immune = resolvers.randartmax(0.05, 0.5), }, } newEntity{ theme={def=true, nimble=true}, name="immune cut", points = 1, rarity = 14, level_range = {1, 50}, - wielder = { cut_immune = resolvers.randartmax(0.05, 1), }, + wielder = { cut_immune = resolvers.randartmax(0.05, 0.5), }, } ---------------------------------------------------------------- diff --git a/game/modules/tome/data/talents/cursed/shadows.lua b/game/modules/tome/data/talents/cursed/shadows.lua index db98743a12e52c019265f703319cdcd2e652ed71..3af3d9d06593969a4cea478e4950f070382833b6 100644 --- a/game/modules/tome/data/talents/cursed/shadows.lua +++ b/game/modules/tome/data/talents/cursed/shadows.lua @@ -305,7 +305,7 @@ local function createShadow(self, level, tCallShadows, tShadowWarriors, tShadowM if self:knowTalent(self.T_SHADOW_FADE) and not self:isTalentCoolingDown(self.T_SHADOW_FADE) then self:forceUseTalent(self.T_SHADOW_FADE, {ignore_energy=true}) end - + return mod.class.Actor.onTakeHit(self, value, src) end, } @@ -324,7 +324,7 @@ newTalent{ return self.level end, getMaxShadows = function(self, t) - return math.max(1, math.floor(self:getTalentLevel(t) * 0.55)) + return math.min(4, math.max(1, math.floor(self:getTalentLevel(t) * 0.55))) end, getPhaseDoorLevel = function(self, t) return self:getTalentLevelRaw(t) @@ -387,7 +387,7 @@ newTalent{ level = t.getLevel(self, t) local tShadowWarriors = self:knowTalent(self.T_SHADOW_WARRIORS) and self:getTalentFromId(self.T_SHADOW_WARRIORS) or nil local tShadowMages = self:knowTalent(self.T_SHADOW_MAGES) and self:getTalentFromId(self.T_SHADOW_MAGES) or nil - + local shadow = createShadow(self, level, t, tShadowWarriors, tShadowMages, 1000, nil) shadow:resolve() diff --git a/game/modules/tome/data/talents/psionic/possession.lua b/game/modules/tome/data/talents/psionic/possession.lua new file mode 100644 index 0000000000000000000000000000000000000000..3e5a2933932c321aeb14d358190bcf04e7b3d027 --- /dev/null +++ b/game/modules/tome/data/talents/psionic/possession.lua @@ -0,0 +1,160 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010, 2011, 2012 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +newTalent{ + name = "Possess", + type = {"psionic/possession", 1}, + require = psi_wil_req1, + points = 5, + cooldown = 30, + psi = 30, + no_npc_use = true, + range = 3, + requires_target = true, + allowedTypes = function(self, t, type) + if type == "animal" then return true end + if type == "humanoid" then return true end + if type == "giant" then return true end + return false + end, + getMaxTalents = function(self, t) return math.ceil(self:getTalentLevel(t)) end, + target = function(self, t) return {type="hit", range=self:getTalentRange(t), selffire=false, talent=t} end, + action = function(self, t) + local tg = self:getTalentTarget(t) + local tx, ty = self:getTarget(tg) + if not tx or not ty then return nil end + local _ _, tx, ty = self:canProject(tg, tx, ty) + target = game.level.map(tx, ty, Map.ACTOR) + if not target or target == self then return nil end + + if target == self.summoner then + game.party:setPlayer(self.summoner, true) + return true + end + + if not t.allowedTypes(self, t, target.type) then game.logPlayer(self, "You may not possess this kind of creature.") return nil end +-- if target.life > target.max_life * 0.25 then game.logPlayer(self, "You may not possess this creature yet its life is too high.") return nil end + if target.dead then game.logPlayer(self, "This creature is dead!") return nil end + + if not self:checkHit(self:combatMindpower(), target:combatMentalResist(), 0, 95, 5) then -- or not target:canBe("instakill") then + game.logPlayer(self, "You fail to shatter %s mind, leaving you unable to possess its body.", target.name) + return true + end + + self.ai = "none" + + target.faction = self.faction + target.ai = "none" + target.ai_state = target.ai_state or {} + target.ai_state.tactic_leash = 100 + target.remove_from_party_on_death = true + target.no_inventory_access = true + target.move_others = true + target.summoner = self + target.summoner_gain_exp = true + target.on_die = function(self, src) if self.summoner then self.summoner:die(src) end end + target.no_leave_control = true + + -- Remove & adjust talents + local nb = t.getMaxTalents(self, t) + local remove = {} + for tid, lev in pairs(target.talents) do + local t = self:getTalentFromId(tid) + if t.mode ~= "passive" then + table.insert(remove, tid) + end + end + local keep = {} + for i = 1, nb do + if #remove == 0 then break end + table.insert(keep, rng.tableRemove(remove)) + end + for _, tid in ipairs(remove) do target:unlearnTalent(tid, target:getTalentLevelRaw(tid)) end + + -- Give a way to go back + target:learnTalent(target.T_POSSESS, true) + + -- Adjust mental stats + target.stats[target.STAT_MAG] = self.stats[self.STAT_MAG] + target.inc_stats[target.STAT_MAG] = self.inc_stats[self.STAT_MAG] + target.stats[target.STAT_WIL] = self.stats[self.STAT_WIL] + target.inc_stats[target.STAT_WIL] = self.inc_stats[self.STAT_WIL] + target.stats[target.STAT_CUN] = self.stats[self.STAT_CUN] + target.inc_stats[target.STAT_CUN] = self.inc_stats[self.STAT_CUN] + + -- Countdown to death + target:setEffect(target.EFF_POSSESSION, 100, {}) + + game.party:addMember(target, { + control="full", + type="possesed", + title="Possessed Husk", + orders = {leash=true, follow=true}, + on_control = function(self) + self:hotkeyAutoTalents() + end, + }) + game.party:setPlayer(target, true) + + return true + end, + info = function(self, t) + return ([[]]): + format() + end, +} + +newTalent{ + name = "Physical Possession", + type = {"psionic/possession", 2}, + require = psi_wil_req2, + points = 5, + mode = "passive", + no_npc_use = true, + info = function(self, t) + return ([[]]): + format() + end, +} + +newTalent{ + name = "Wild Possession", + type = {"psionic/possession", 3}, + require = psi_wil_req3, + mode = "passive", + points = 5, + no_npc_use = true, + info = function(self, t) + return ([[]]): + format() + end, +} + +newTalent{ + name = "Arcane Possession", + type = {"psionic/possession", 4}, + require = psi_wil_req4, + mode = "passive", + points = 5, + no_npc_use = true, + info = function(self, t) + return ([[]]): + format() + end, +} diff --git a/game/modules/tome/data/talents/psionic/psionic.lua b/game/modules/tome/data/talents/psionic/psionic.lua index 4a183c1bba31f21574118fef7697ae9da92c40e3..5792ff0ce7532ec88e5d3a360a862650a917ae25 100644 --- a/game/modules/tome/data/talents/psionic/psionic.lua +++ b/game/modules/tome/data/talents/psionic/psionic.lua @@ -39,6 +39,8 @@ newTalentType{ allow_random=true, type="psionic/brainstorm", name = "brainstorm" newTalentType{ allow_random=true, type="psionic/psychic-assault", name = "psychic assault", description = "Directly attack your opponents minds." } -- Generic Solipsist Trees +newTalentType{ allow_random=true, type="psionic/possession", name = "possession", description = "You have learnt to shed away your body, allowing you to possess any other." } + -- Level 0 wil tree requirements: psi_absorb = { @@ -167,4 +169,7 @@ load("/data/talents/psionic/psi-archery.lua") load("/data/talents/psionic/grip.lua") -- Solipsist -load("/data/talents/psionic/psychic-assault.lua") \ No newline at end of file +load("/data/talents/psionic/psychic-assault.lua") + +load("/data/talents/psionic/possession.lua") + diff --git a/game/modules/tome/data/talents/psionic/voracity.lua b/game/modules/tome/data/talents/psionic/voracity.lua index d17fdfee600d0a203f0384b613863b772e1aabee..cea080f63cd0e2e39e39ef1aca503cec72e5d452 100644 --- a/game/modules/tome/data/talents/psionic/voracity.lua +++ b/game/modules/tome/data/talents/psionic/voracity.lua @@ -171,7 +171,7 @@ newTalent{ local range = self:getTalentRadius(t) local en = t.getLeech(self, t) local dam = damDesc(self, DamageType.LIGHTNING, t.getDam(self, t)) - return ([[You pull electric potential from all targets around you in a radius of %d, gaining %d energy for each one affected and giving them a nasty shock in the process. Deals between %d and %d damage.]]):format(range, en, dam / 3, dam) + return ([[You pull electric potential from all targets around you in a radius of %d, gaining %d energy for each one affected and giving them a nasty shock in the process. Deals between %d and %d damage nad has a chance to daze.]]):format(range, en, dam / 3, dam) end, } newTalent{ diff --git a/game/modules/tome/data/talents/spells/meta.lua b/game/modules/tome/data/talents/spells/meta.lua index 44d9b0296cb3373d1f7cd09bd3ac585a852503d3..7f78662b4a2dc8fb65494c5828a5dc93abe9c856 100644 --- a/game/modules/tome/data/talents/spells/meta.lua +++ b/game/modules/tome/data/talents/spells/meta.lua @@ -50,18 +50,27 @@ newTalent{ local effs = {} -- Go through all spell effects - for eff_id, p in pairs(target.tmp) do - local e = target.tempeffect_def[eff_id] - if e.type == "magical" then - effs[#effs+1] = {"effect", eff_id} + if self:reactionToward(target) < 0 then + for eff_id, p in pairs(target.tmp) do + local e = target.tempeffect_def[eff_id] + if e.type == "magical" and e.status == "beneficial" then + effs[#effs+1] = {"effect", eff_id} + end end - end - -- Go through all sustained spells - for tid, act in pairs(target.sustain_talents) do - if act then - local talent = target:getTalentFromId(tid) - if talent.is_spell then effs[#effs+1] = {"talent", tid} end + -- Go through all sustained spells + for tid, act in pairs(target.sustain_talents) do + if act then + local talent = target:getTalentFromId(tid) + if talent.is_spell then effs[#effs+1] = {"talent", tid} end + end + end + else + for eff_id, p in pairs(target.tmp) do + local e = target.tempeffect_def[eff_id] + if e.type == "magical" and e.status == "detrimental" then + effs[#effs+1] = {"effect", eff_id} + end end end @@ -80,7 +89,7 @@ newTalent{ end, info = function(self, t) local count = t.getRemoveCount(self, t) - return ([[Removes up to %d magical effects (both good and bad) from the target. + return ([[Removes up to %d magical effects (good effects from foes and bad effects from friends) from the target. At level 3 it can be targeted.]]): format(count) end, diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua index b2e5182b4f5a9d3312fbe30a753c8c3dcfb4904e..51bd8969f70ca11a50ec46e9ef506c7e2c5c4552 100644 --- a/game/modules/tome/data/timed_effects/other.lua +++ b/game/modules/tome/data/timed_effects/other.lua @@ -1518,4 +1518,21 @@ newEffect{ -- always remove return true end, -} \ No newline at end of file +} + +newEffect{ + name = "POSSESSION", image = "talents/possess.png", + desc = "Psionic Consume", + long_desc = function(self, eff) return "This creature's mind has been destroyed and a possessor is now controlling the husk. However the intense psionic energies are burning the body away, it will soon disappear." end, + type = "other", + subtype = { psionic=true, possess=true }, + status = "detrimental", + no_stop_resting = true, + parameters = { }, + activate = function(self, eff) + end, + deactivate = function(self, eff) + self.summoner = nil + self:die(self) + end, +} diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua index d7e07ed56c4923bdf84b065adfdbe2f9e003aecc..38bd2fabc0b83068b81a5f675666fb6d8fc1b8db 100644 --- a/game/modules/tome/data/timed_effects/physical.lua +++ b/game/modules/tome/data/timed_effects/physical.lua @@ -244,7 +244,9 @@ newEffect{ activate = function(self, eff) end, deactivate = function(self, eff) - self:setEffect(self.EFF_STONED, eff.stone, {}) + if target:canBe("stun") and target:canBe("stone") and target:canBe("instakill") then + self:setEffect(self.EFF_STONED, eff.stone, {}) + end end, } diff --git a/game/modules/tome/data/zones/valley-moon/npcs.lua b/game/modules/tome/data/zones/valley-moon/npcs.lua index a4a284f0859f0124eb2ef1c1327edfe57294225e..bb7c010035deaf8e912f97ca5cbbc9dde01dc36d 100644 --- a/game/modules/tome/data/zones/valley-moon/npcs.lua +++ b/game/modules/tome/data/zones/valley-moon/npcs.lua @@ -104,6 +104,7 @@ newEntity{ define_as = "LIMMIR", resolvers.sustains_at_birth(), can_talk = "limmir-valley-moon", + never_anger = true, can_craft = true, on_die = function(self, who) game.level.turn_counter = nil diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua index cff1ed3a03a9c41ccccfe9c0e86fcd0e0934a169..60b92c9abc8834d45875aade4139413c8e3c027b 100644 --- a/game/modules/tome/resolvers.lua +++ b/game/modules/tome/resolvers.lua @@ -180,7 +180,7 @@ function resolvers.calc.drop_randart(t, e) end end - local o = game.state:generateRandart(false, base, resolvers.current_level) + local o = game.state:generateRandart{base=base, lev=resolvers.current_level} if o then -- print("Zone made us a randart drop according to filter!", o:getName{force_id=true}) e:addObject(e.INVEN_INVEN, o)