diff --git a/game/engines/default/engine/Savefile.lua b/game/engines/default/engine/Savefile.lua index a3a5bfc207888596ff68ebb30e15999388c3528a..8a4207f93f01361bb4f091f538366181052a66a6 100644 --- a/game/engines/default/engine/Savefile.lua +++ b/game/engines/default/engine/Savefile.lua @@ -101,14 +101,6 @@ function _M:saveObject(obj, zip) local tbl = table.remove(self.process) self.tables[tbl] = self:getFileName(tbl) zip:add(self:getFileName(tbl), tbl:save()) - -- If run from a coroutine, we pause every object - if self.coroutine then - local coret = coroutine.yield() - if coret and type(coret) == "string" and coret == "cancel" then - print("[SAVE] abording") - break - end - end end return self.tables[obj] end diff --git a/game/engines/default/engine/class.lua b/game/engines/default/engine/class.lua index ba02bfc0026be1a469e99abebc1d01b32d5e7d48..adb6ba7a415c44619d76a9887d41fd174798a61c 100644 --- a/game/engines/default/engine/class.lua +++ b/game/engines/default/engine/class.lua @@ -168,6 +168,9 @@ local function basicSerialize(o, t) end local function serialize_data(outf, name, value, saved, filter, allow, savefile, force) + -- If run from a coroutine, we pause every table + if savefile.coroutine then coroutine.yield() end + saved = saved or {} -- initial value outf(name, " = ") local tvalue = type(value) diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 27721f79fd1a424f68fbba93f7a484ce49e44709..1f6301e3deab9637be95ec3c9f44e580ae2870df 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -1416,7 +1416,7 @@ function _M:getTalentFullDescription(t, addlevel) if self:getTalentRange(t) > 1 then d:add({"color",0x6f,0xff,0x83}, "Range: ", {"color",0xFF,0xFF,0xFF}, ""..self:getTalentRange(t), true) else d:add({"color",0x6f,0xff,0x83}, "Range: ", {"color",0xFF,0xFF,0xFF}, "melee/personal", true) end - if t.cooldown then d:add({"color",0x6f,0xff,0x83}, "Cooldown: ", {"color",0xFF,0xFF,0xFF}, ""..util.getval(t.cooldown, self, t), true) end + if self:getTalentCooldown(t) then d:add({"color",0x6f,0xff,0x83}, "Cooldown: ", {"color",0xFF,0xFF,0xFF}, ""..self:getTalentCooldown(t), true) end local speed = self:getTalentProjectileSpeed(t) if speed then d:add({"color",0x6f,0xff,0x83}, "Travel Speed: ", {"color",0xFF,0xFF,0xFF}, ""..(speed * 100).."% of base", true) else d:add({"color",0x6f,0xff,0x83}, "Travel Speed: ", {"color",0xFF,0xFF,0xFF}, "instantaneous", true) @@ -1432,18 +1432,23 @@ function _M:getTalentFullDescription(t, addlevel) return d end ---- Starts a talent cooldown; overloaded from the default to handle talent cooldown reduction --- @param t the talent to cooldown -function _M:startTalentCooldown(t) +function _M:getTalentCooldown(t) if not t.cooldown then return end local cd = t.cooldown if type(cd) == "function" then cd = cd(self, t) end if self.talent_cd_reduction[t.id] then cd = cd - self.talent_cd_reduction[t.id] end if t.is_spell then - self.talents_cd[t.id] = math.ceil(cd * (1 - self.spell_cooldown_reduction or 0)) + return math.ceil(cd * (1 - self.spell_cooldown_reduction or 0)) else - self.talents_cd[t.id] = cd + return cd end +end + +--- Starts a talent cooldown; overloaded from the default to handle talent cooldown reduction +-- @param t the talent to cooldown +function _M:startTalentCooldown(t) + if not t.cooldown then return end + self.talents_cd[t.id] = self:getTalentCooldown(t) self.changed = true end diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 97067bee6d2264ed4b81154bb2dabbaf1e574d92..581d716bf6e490919aea43d65e2fb3dfe65f1be9 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -108,6 +108,13 @@ function _M:onEnterLevel(zone, level) if self.random_escort_levels and self.random_escort_levels[zone.short_name] and self.random_escort_levels[zone.short_name][level.level] then self:grantQuest("escort-duty") end + + -- Cancel effects + local effs = {} + for eff_id, p in pairs(self.tmp) do + if self.tempeffect_def[eff_id].cancel_on_level_change then effs[#effs+1] = eff_id end + end + for i, eff_id in ipairs(effs) do self:removeEffect(eff_id) end end function _M:onLeaveLevel(zone, level) @@ -139,6 +146,7 @@ function _M:move(x, y, force) if obj.auto_pickup then self:pickupFloor(i, true) else + if self:attr("auto_id_mundane") and obj:getPowerRank() <= 1 then obj:identify(true) end nb = nb + 1 i = i + 1 end @@ -249,6 +257,7 @@ local wild_fovdist = {} for i = 0, 10 * 10 do wild_fovdist[i] = math.max((5 - math.sqrt(i)) / 1.4, 0.6) end +local arcane_eye_true_seeing = function() return true, 100 end function _M:playerFOV() -- Clean FOV before computing it @@ -293,6 +302,20 @@ function _M:playerFOV() end, true, true, true) end + -- Handle arcane eye + if self:hasEffect(self.EFF_ARCANE_EYE) then + local eff = self:hasEffect(self.EFF_ARCANE_EYE) + local map = game.level.map + + core.fov.calc_circle( + eff.x, eff.y, eff.radius, function(_, x, y) if map:checkAllEntities(x, y, "block_sight", self) then return true end end, + function(_, x, y) + local t = map(x, y, map.ACTOR) + if t and (eff.true_seeing or self:canSee(t)) then map.seens(x, y, 1) end + end, + cache and map._fovcache["block_sight"] + ) + end -- Handle Preternatural Senses talent, a simple FOV, using cache. if self:knowTalent(self.T_PRETERNATURAL_SENSES) then diff --git a/game/modules/tome/data/talents/spells/divination.lua b/game/modules/tome/data/talents/spells/divination.lua index 6b4bb4cdf2135f209f2b844d8cbcd29ee85f3b29..d5d217cee89a7e886396d313e9a8281dea1ff422 100644 --- a/game/modules/tome/data/talents/spells/divination.lua +++ b/game/modules/tome/data/talents/spells/divination.lua @@ -25,9 +25,6 @@ newTalent{ random_ego = "utility", mana = 10, cooldown = 10, - tactical = { - ATTACK = 10, - }, action = function(self, t) local rad = 10 + self:combatSpellpower(0.1) * self:getTalentLevel(t) self:setEffect(self.EFF_SENSE, 2, { @@ -48,58 +45,36 @@ newTalent{ } newTalent{ - name = "Identify", + name = "Arcane Eye", type = {"spell/divination", 2}, require = spells_req2, points = 5, - random_ego = "utility", - mana = 20, + mana = 15, + cooldown = 10, + no_energy = true, action = function(self, t) - local rad = math.floor(0 + (self:getTalentLevel(t) - 4)) - - if self:getTalentLevel(t) < 3 then - self:showEquipInven("Identify object", function(o) return not o:isIdentified() end, function(o) - o:identify(true) - game.logPlayer(self, "You identify: %s", o:getName{do_color=true}) - return true - end) - return true - end - - if self:getTalentLevel(t) >= 3 then - for inven_id, inven in pairs(self.inven) do - for i, o in ipairs(inven) do - o:identify(true) - end - end - game.logPlayer(self, "You identify all your inventory.") - end - - if self:getTalentLevel(t) >= 4 then - local idfloor = function(x, y) - local idx = 1 - while true do - local o = game.level.map:getObject(x, y, idx) - if not o then break end - o:identify(true) - idx = idx + 1 - end - end - local rad = math.floor(0 + (self:getTalentLevel(t) - 4)) - if rad == 0 then idfloor(self.x, self.y) - else self:project({type="ball", radius=rad}, self.x, self.y, idfloor) - end - - game.logPlayer(who, "You identify everything around you.") - end + local tg = {type="hit", nolock=true, pass_terrain=true, nowarning=true, range=100, requires_knowledge=false} + x, y = self:getTarget(tg) + if not x then return nil end + -- Target code doesnot restrict the target coordinates to the range, it lets the poject function do it + -- but we cant ... + local _ _, x, y = self:canProject(tg, x, y) + local dur = math.floor(10 + self:getTalentLevel(t) * 3) + local radius = math.floor(4 + self:getTalentLevel(t) * 3) + self:setEffect(self.EFF_ARCANE_EYE, dur, {x=x, y=y, radius=radius, true_seeing=self:getTalentLevel(t) >= 5}) game:playSoundNear(self, "talents/spell_generic") return true end, info = function(self, t) - return ([[Identify the powers and nature of an object. - At level 3 it identifies all the objects in your possession. - At level 4 it identifies all the objects on the floor in a radius of %d.]]):format(math.floor(0 + (self:getTalentLevel(t) - 4))) + return ([[Summons an etheral magical eye at the designated location that lasts for %d turns. + The eye can not be seen or attacked by other creatures and posses magical vision that allows it to see any creature in a %d range around it. + It does not require light to do so but it can not see through walls. + Casting the eye does not take a turn. + Only one arcane eye can exist at any given time. + At level 5 its vision can see through invisibility, stealth and all other sight affecting effects. + ]]): + format(math.floor(10 + self:getTalentLevel(t) * 3), math.floor(4 + self:getTalentLevel(t) * 3)) end, } @@ -112,12 +87,12 @@ newTalent{ mana = 20, cooldown = 20, action = function(self, t) - self:magicMap(10 + self:combatSpellpower(0.1) * self:getTalentLevel(t)) + self:magicMap(5 + self:combatTalentSpellDamage(t, 2, 12)) game:playSoundNear(self, "talents/spell_generic") return true end, info = function(self, t) - return ([[Form a map of your surroundings in your mind in a radius of %d.]]):format(10 + self:combatSpellpower(0.1) * self:getTalentLevel(t)) + return ([[Form a map of your surroundings in your mind in a radius of %d.]]):format(5 + self:combatTalentSpellDamage(t, 2, 12)) end, } @@ -131,7 +106,7 @@ newTalent{ cooldown = 30, activate = function(self, t) -- There is an implicit +10, as it is the default radius - local rad = self:combatSpellpower(0.1) * self:getTalentLevel(t) + local rad = self:combatTalentSpellDamage(t, 2, 10) game:playSoundNear(self, "talents/spell_generic") return { esp = self:addTemporaryValue("esp", {range=rad, all=1}), @@ -146,6 +121,6 @@ newTalent{ info = function(self, t) return ([[Allows you to sense the presence of foes, in a radius of %d. This powerful spell will continuously drain mana while active. - The bonus will increase with the Magic stat]]):format(10 + self:combatSpellpower(0.1) * self:getTalentLevel(t)) + The bonus will increase with the Magic stat]]):format(10 + self:combatTalentSpellDamage(t, 2, 10)) end, } diff --git a/game/modules/tome/data/talents/spells/spells.lua b/game/modules/tome/data/talents/spells/spells.lua index f4843c97b4d0eaeb90b490dcd7733e5e46637fcc..fde774fe4b4b037b8041573b1317745c5386cf12 100644 --- a/game/modules/tome/data/talents/spells/spells.lua +++ b/game/modules/tome/data/talents/spells/spells.lua @@ -31,13 +31,13 @@ newTalentType{ no_silence=true, is_spell=true, type="spell/air", name = "air", d newTalentType{ no_silence=true, is_spell=true, type="spell/storm", name = "storm", description = "Harness the power of the storm to incinerate your foes." } -- Various other magic schools -newTalentType{ no_silence=true, is_spell=true, type="spell/conveyance", name = "conveyance", generic = true, description = "Conveyance is the school of travel. It allows you to travel faster and to track others." } -newTalentType{ no_silence=true, is_spell=true, type="spell/nature", name = "nature", generic = true, description = "Summons the power of nature to rejuvenate yourself and the world." } newTalentType{ no_silence=true, is_spell=true, type="spell/meta", name = "meta", description = "Meta spells alter the working of magic itself." } -newTalentType{ no_silence=true, is_spell=true, type="spell/divination", name = "divination", generic = true, description = "Divination allows the caster to sense its surroundings, find hidden things." } newTalentType{ no_silence=true, is_spell=true, type="spell/temporal", name = "temporal", description = "The school of time manipulation." } newTalentType{ no_silence=true, is_spell=true, type="spell/phantasm", name = "phantasm", description = "Control the power of tricks and illusions." } newTalentType{ no_silence=true, is_spell=true, type="spell/enhancement", name = "enhancement", description = "Magical enhancement of your body." } +newTalentType{ no_silence=true, is_spell=true, type="spell/conveyance", name = "conveyance", generic = true, description = "Conveyance is the school of travel. It allows you to travel faster and to track others." } +newTalentType{ no_silence=true, is_spell=true, type="spell/divination", name = "divination", generic = true, description = "Divination allows the caster to sense its surroundings, find hidden things." } +newTalentType{ no_silence=true, is_spell=true, type="spell/nature", name = "nature", generic = true, description = "Summons the power of nature to rejuvenate yourself and the world." } -- Alchemist spells newTalentType{ no_silence=true, is_spell=true, type="spell/explosives", name = "explosive admixtures", description = "Manipulate gems to turn them into explosive magical bombs." } diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua index ff18a3423d97025ecd196868315f76ad665c24b1..48bf60fef293556f3069cd0577ffee93b5204c9c 100644 --- a/game/modules/tome/data/timed_effects.lua +++ b/game/modules/tome/data/timed_effects.lua @@ -648,6 +648,22 @@ newEffect{ end, } +newEffect{ + name = "ARCANE_EYE", + desc = "Arcane Eye", + long_desc = function(self, eff) return ("You have an arcane eye observing for you in a radius of %d."):format(eff.radius) end, + type = "magical", + status = "beneficial", + cancel_on_level_change = true, + parameters = { range=10, actor=1, object=0, trap=0 }, + activate = function(self, eff) + game.level.map.changed = true + end, + deactivate = function(self, eff) + game.level.map.changed = true + end, +} + newEffect{ name = "ALL_STAT", desc = "All stats increase", diff --git a/ideas/spells.ods b/ideas/spells.ods index 4d83b6faf5221639459d7a39e061b1651f355f75..873788b214ac42fee6e264601ea924fc9a765384 100644 Binary files a/ideas/spells.ods and b/ideas/spells.ods differ