diff --git a/game/engines/default/engine/Projectile.lua b/game/engines/default/engine/Projectile.lua index 586e87b326e2dd4483568bc49c5f7783c6a3ebbe..1fe5486a282d550f452e1aafc0c6eaa934a00f4e 100644 --- a/game/engines/default/engine/Projectile.lua +++ b/game/engines/default/engine/Projectile.lua @@ -45,7 +45,7 @@ function _M:save() end function _M:loaded() - if self.project and self.project.def and self.project.def.typ and self.project.def.typ.line_function then + if self.project and self.project.def and self.project.def.typ and self.project.def.typ.line_function and type(self.project.def.typ.line_function.line) == "table" then self.project.def.typ.line_function.line = core.fov.line_import(unpack(self.project.def.typ.line_function.line)) -- The metatable gets lost somewhere in the save, so let's remake it diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index b74a15472e591deec9233ba85ab0282e40c6e182..b15b691e9e247a9fdc57dfe6046221259828bc28 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -828,12 +828,22 @@ end function _M:chronoClone(name) local d = Dialog:simpleWaiter("Chronomancy", "Folding the space time structure...") - local ret = nil + local to_reload = {} + for uid, e in pairs(self.level.entities) do + if type(e.project) == "table" and e.project.def and e.project.def.typ and e.project.def.typ.line_function then + e.project.def.typ.line_function.line = { game.level.map.w, game.level.map.h, e.project.def.typ.line_function:export() } + to_reload[#to_reload + 1] = e + end + end + + local ret = self:cloneFull() + + for uid, e in pairs(to_reload) do e:loaded() end + if name then self._chronoworlds = self._chronoworlds or {} - self._chronoworlds[name] = self:cloneFull() - else - ret = self:cloneFull() + self._chronoworlds[name] = ret + ret = nil end d:done() return ret @@ -852,6 +862,8 @@ function _M:chronoRestore(name, remove) ngame:cloneReloaded() _G.game = ngame + + game.inited = nil game:run() game.key:setCurrent() game.mouse:setCurrent() diff --git a/game/modules/tome/data/talents/chronomancy/chronomancy.lua b/game/modules/tome/data/talents/chronomancy/chronomancy.lua index a86f76c2774cb2cfcca2b52bb4cce9a07f6da802..c63c2a2a359b0ce3973ca959c020a3aa7ce39f4c 100644 --- a/game/modules/tome/data/talents/chronomancy/chronomancy.lua +++ b/game/modules/tome/data/talents/chronomancy/chronomancy.lua @@ -65,7 +65,7 @@ newTalent{ require = temporal_req1, points = 5, paradox = 5, - cooldown = 1, + cooldown = 10, no_npc_use = true, getDuration = function(self, t) return 4 + math.ceil((self:getTalentLevel(t) * 2)) end, action = function(self, t) diff --git a/game/modules/tome/data/talents/chronomancy/timetravel.lua b/game/modules/tome/data/talents/chronomancy/timetravel.lua index 9e8ffa01c448dd5907e31abd0b6d4a0457c97d0e..c0aa022e62791e288d57c5601a088c70088a8ff7 100644 --- a/game/modules/tome/data/talents/chronomancy/timetravel.lua +++ b/game/modules/tome/data/talents/chronomancy/timetravel.lua @@ -66,47 +66,75 @@ newTalent{ getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 250) * getParadoxModifier(self, pm) end, getDuration = function(self, t) return 2 + math.ceil(self:getTalentLevel(t) / 2 * getParadoxModifier(self, pm)) end, action = function(self, t) - -- Find the target and check hit local tg = {type="hit", range=self:getTalentRange(t), talent=t} - local tx, ty, target = self:getTarget(tg) - if not tx or not ty then return nil end - tx, ty = checkBackfire(self, tx, ty, t.paradox) - local _ _, tx, ty = self:canProject(tg, tx, ty) - if tx then - target = game.level.map(tx, ty, engine.Map.ACTOR) - end - - -- checks for spacetime mastery hit bonus - local power = self:combatSpellpower() - if self:knowTalent(self.T_SPACETIME_MASTERY) then - power = self:combatSpellpower() * (1 + self:getTalentLevel(self.T_SPACETIME_MASTERY)/10) - end + local x, y, _ = self:getTarget(tg) + if not x or not y then return nil end + x, y = checkBackfire(self, x, y, t.paradox) + _, x, y = self:canProject(tg, x, y) + local target = x and game.level.map(x, y, engine.Map.ACTOR) or nil + if not target then return nil end - if target then - local hit = self:checkHit(power, target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) - if not hit then - game.logSeen(target, "%s resists!", target.name:capitalize()) - return true - end - else - return - end - - -- deal the damage first so time prison doesn't prevent it - self:project(tg, tx, ty, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t))) - game.level.map:particleEmitter(tx, ty, 1, "temporal_thrust") + local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) + if not hit then game.logSeen(target, "%s resists!", target.name:capitalize()) return true end + + target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self:combatSpellpower(0.3)}) + self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t))) + game.level.map:particleEmitter(x, y, 1, "temporal_thrust") game:playSoundNear(self, "talents/arcane") - -- make sure the target survives the initial hit and then time prison - if not target.dead then - if target ~= self then - target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self:combatSpellpower(0.3)}) - end - target:setEffect(target.EFF_TIME_PRISON, t.getDuration(self, t), {}) + -- End it here if we've killed the target or the target is a player + if target.dead or target.player then return true end + + -- set up instability + local summoner = self + -- Store the current terrain + local terrain = game.level.map(target.x, target.y, engine.Map.TERRAIN) + -- Store target attributes as needed + local a = {} + a.life = target.life + -- Instability + local temporal_instability = mod.class.Object.new{ + old_feat = game.level.map(target.x, target.y, engine.Map.TERRAIN), + name = "temporal instability", type="temporal", subtype="anomaly", + display = '&', color=colors.LIGHT_BLUE, + temporary = t.getDuration(self, t), + canAct = false, + target = target, + act = function(self) + self:useEnergy() + self.temporary = self.temporary - 1 + -- return the rifted actor + if self.temporary <= 0 then + game.level.map(self.target.x, self.target.y, engine.Map.TERRAIN, self.old_feat) + game.level:removeEntity(self) + local mx, my = util.findFreeGrid(self.target.x, self.target.y, 20, true, {[engine.Map.ACTOR]=true}) + game.zone:addEntity(game.level, self.target, "actor", mx, my) + self.target.life = a.life + end + end, + summoner_gain_exp = true, + summoner = summoner, + } + + -- Mixin the old terrain + table.update(temporal_instability, terrain) + -- Now update the display overlay + local overlay = engine.Entity.new{ + display = '&', color=colors.LIGHT_BLUE, image="object/temporal_instability.png", + display_on_seen = true, + display_on_remember = true, + } + if not temporal_instability.add_displays then + temporal_instability.add_displays = {overlay} else - game.logSeen(target, "%s has been killed by the temporal energy!", target.name:capitalize()) + table.append(temporal_instability.add_displays, overlay) end - + + game.logSeen(target, "%s has moved forward in time!", target.name:capitalize()) + game.level:removeEntity(target) + game.level:addEntity(temporal_instability) + game.level.map(target.x, target.y, engine.Map.TERRAIN, temporal_instability) + return true end, info = function(self, t) diff --git a/game/modules/tome/data/talents/misc/inscriptions.lua b/game/modules/tome/data/talents/misc/inscriptions.lua index 3b114b02625395645ac1a91a016171dfed7f6517..3ec8d32290a6d346e812bb25d417c77e8e2bae6f 100644 --- a/game/modules/tome/data/talents/misc/inscriptions.lua +++ b/game/modules/tome/data/talents/misc/inscriptions.lua @@ -720,27 +720,32 @@ newInscription{ getDamage = function(self, t) return 150 + self:getWil() * 4 end, getDuration = function(self, t) return 4 end, action = function(self, t) - -- Find the target and check hit local tg = {type="hit", range=self:getTalentRange(t), talent=t} - local tx, ty, target = self:getTarget(tg) - if not tx or not ty then return nil end - local _ _, tx, ty = self:canProject(tg, tx, ty) - if tx then - target = game.level.map(tx, ty, engine.Map.ACTOR) - end - if target and not target.player then - local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) - if not hit then - game.logSeen(target, "%s resists!", target.name:capitalize()) - return true - end - else - return - end + local x, y, _ = self:getTarget(tg) + if not x or not y then return nil end + _, x, y = self:canProject(tg, x, y) + local target = x and game.level.map(x, y, engine.Map.ACTOR) or nil + if not target then return nil end + + local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0)) + if not hit then game.logSeen(target, "%s resists!", target.name:capitalize()) return true end + + target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self:combatSpellpower(0.3)}) + self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t))) + game.level.map:particleEmitter(x, y, 1, "temporal_thrust") + game:playSoundNear(self, "talents/arcane") - -- Create an object to time the effect and store the creature - -- First, clone the terrain that we are replacing + -- End it here if we've killed the target or the target is a player + if target.dead or target.player then return true end + + -- set up instability + local summoner = self + -- Store the current terrain local terrain = game.level.map(target.x, target.y, engine.Map.TERRAIN) + -- Store target attributes as needed + local a = {} + a.life = target.life + -- Instability local temporal_instability = mod.class.Object.new{ old_feat = game.level.map(target.x, target.y, engine.Map.TERRAIN), name = "temporal instability", type="temporal", subtype="anomaly", @@ -751,21 +756,23 @@ newInscription{ act = function(self) self:useEnergy() self.temporary = self.temporary - 1 + -- return the rifted actor if self.temporary <= 0 then game.level.map(self.target.x, self.target.y, engine.Map.TERRAIN, self.old_feat) game.level:removeEntity(self) local mx, my = util.findFreeGrid(self.target.x, self.target.y, 20, true, {[engine.Map.ACTOR]=true}) game.zone:addEntity(game.level, self.target, "actor", mx, my) + self.target.life = a.life end end, summoner_gain_exp = true, - summoner = self, + summoner = summoner, } + -- Mixin the old terrain table.update(temporal_instability, terrain) -- Now update the display overlay local overlay = engine.Entity.new{ - -- image = "terrain/wormhole.png", display = '&', color=colors.LIGHT_BLUE, image="object/temporal_instability.png", display_on_seen = true, display_on_remember = true, @@ -775,24 +782,13 @@ newInscription{ else table.append(temporal_instability.add_displays, overlay) end + + game.logSeen(target, "%s has moved forward in time!", target.name:capitalize()) + game.level:removeEntity(target) + game.level:addEntity(temporal_instability) + game.level.map(target.x, target.y, engine.Map.TERRAIN, temporal_instability) - self:project(tg, tx, ty, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t))) - game.level.map:particleEmitter(tx, ty, 1, "temporal_thrust") - game:playSoundNear(self, "talents/arcane") - -- Remove the target and place the temporal placeholder - if not target.dead then - if target ~= self then - target:setEffect(target.EFF_CONTINUUM_DESTABILIZATION, 100, {power=self:combatSpellpower(0.3)}) - end - game.logSeen(target, "%s has moved forward in time!", target.name:capitalize()) - game.level:removeEntity(target) - game.level:addEntity(temporal_instability) - game.level.map(target.x, target.y, engine.Map.TERRAIN, temporal_instability) - else - game.logSeen(target, "%s has been killed by the temporal energy!", target.name:capitalize()) - end - - self:incParadox(-120) + self:incParadox(-60) return true end, @@ -800,7 +796,7 @@ newInscription{ local damage = t.getDamage(self, t) local duration = t.getDuration(self, t) return ([[Inflicts %0.2f temporal damage. If your target survives it will be sent %d turns into the future. - It will also lower your paradox by 120 (if you have any). + It will also lower your paradox by 60 (if you have any). Note that messing with the spacetime continuum may have unforeseen consequences.]]):format(damDesc(self, DamageType.TEMPORAL, damage), duration) end, short_info = function(self, t) diff --git a/utils/te4_pack_module.sh b/utils/te4_pack_module.sh index 74c0ad073e9ad274c3230673c09e3ef553e9f469..127b8a51207890b20ea24209ae1575408841056b 100755 --- a/utils/te4_pack_module.sh +++ b/utils/te4_pack_module.sh @@ -9,24 +9,9 @@ mod="$1" version="$2" exclude_ogg="$3" -pushd "$mod" -teams=`lua <<EOS -local init = loadfile("init.lua") -local d = {} -setfenv(init, d) -init() -if not d.teams then return end -for i, def in ipairs(d.teams) do - io.write(def[1]..":"..table.concat(def[3],":"):gsub("^/", ""):gsub(":/", ":")) - if i < #d.teams then io.write(";") end -end -EOS` -teams=`echo "$teams"| sed "s/#name#/$mod/g" | sed "s/#version#/$version/g"` -popd - cp -a "$mod" tmp find tmp -name .svn -or -name '*~' | xargs rm -rf -pushd tmp +cd tmp if test "$exclude_ogg" -eq 1; then IFS=$'\n'; for i in `find -name '*.ogg'`; do @@ -39,25 +24,11 @@ mkdir mod mv * mod mv mod/data . -IFS=';' -for teamdef in `echo "$teams"`; do - tname=`echo "$teamdef"|cut -d: -f1` - tlist=`echo "$teamdef"|cut -d: -f2-` - echo "=== Teamdef: $tname" - IFS=':' - for list in `echo "$tlist"`; do - echo "=== Adding: $tlist" - zip --quiet -r -0 ../"$tname" "$list" - rm -rf "$list" - done - IFS=';' -done - if test "$exclude_ogg" -eq 1; then - zip --quiet -r -0 ../"$mod"-"$version-nomusic".team * + zip -r -0 ../"$mod"-"$version-nomusic".team * else - zip --quiet -r -0 ../"$mod"-"$version".team * + zip -r -0 ../"$mod"-"$version".team * fi -popd +cd - rm -rf tmp