Skip to content
Snippets Groups Projects
Commit 0112e54d authored by dg's avatar dg
Browse files

Rebalance and add new powers to Alchemist class

git-svn-id: http://svn.net-core.org/repos/t-engine4@929 51575b47-30f0-44d4-a5cc-537603b46e54
parent 49dfb836
No related branches found
No related tags found
No related merge requests found
...@@ -270,6 +270,22 @@ function _M:canSee(actor, def, def_pct) ...@@ -270,6 +270,22 @@ function _M:canSee(actor, def, def_pct)
return true, 100 return true, 100
end end
--- Does the actor have LOS to the target
function _M:hasLOS(x, y)
local l = line.new(self.x, self.y, x, y)
local lx, ly = l()
while lx and ly do
if game.level.map:checkAllEntities(lx, ly, "block_sight") then break end
lx, ly = l()
end
-- Ok if we are at the end reset lx and ly for the next code
if not lx and not ly then lx, ly = x, y end
if lx == x and ly == y then return true, lx, ly end
return false, lx, ly
end
local function gettable(base, name) local function gettable(base, name)
for w in name:gmatch("[^.]+") do for w in name:gmatch("[^.]+") do
base = base[w] base = base[w]
......
...@@ -27,7 +27,7 @@ newAI("dumb_talented", function(self) ...@@ -27,7 +27,7 @@ newAI("dumb_talented", function(self)
for tid, _ in pairs(self.talents) do for tid, _ in pairs(self.talents) do
local t = self:getTalentFromId(tid) local t = self:getTalentFromId(tid)
-- print(self.name, self.uid, "dumb ai talents can try use", t.name, tid, "::", t.mode, not self:isTalentCoolingDown(t), target_dist <= self:getTalentRange(t), self:preUseTalent(t, true), self:canProject({type="bolt"}, self.ai_target.actor.x, self.ai_target.actor.y)) -- print(self.name, self.uid, "dumb ai talents can try use", t.name, tid, "::", t.mode, not self:isTalentCoolingDown(t), target_dist <= self:getTalentRange(t), self:preUseTalent(t, true), self:canProject({type="bolt"}, self.ai_target.actor.x, self.ai_target.actor.y))
if t.mode == "activated" and not self:isTalentCoolingDown(t) and target_dist <= self:getTalentRange(t) and self:preUseTalent(t, true) and self:canProject({type="bolt"}, self.ai_target.actor.x, self.ai_target.actor.y) then if t.mode == "activated" and not self:isTalentCoolingDown(t) and target_dist <= self:getTalentRange(t) and self:preUseTalent(t, true) and self:canProject({type="bolt"}, self.ai_target.actor.x, self.ai_target.actor.y) and self:hasLOS(self.ai_target.actor.x, self.ai_target.actor.y) then
avail[#avail+1] = tid avail[#avail+1] = tid
print(self.name, self.uid, "dumb ai talents can use", t.name, tid) print(self.name, self.uid, "dumb ai talents can use", t.name, tid)
elseif t.mode == "sustained" and not self:isTalentCoolingDown(t) and not self:isTalentActive(t.id) and self:preUseTalent(t, true) then elseif t.mode == "sustained" and not self:isTalentCoolingDown(t) and not self:isTalentActive(t.id) and self:preUseTalent(t, true) then
......
...@@ -104,12 +104,12 @@ newBirthDescriptor{ ...@@ -104,12 +104,12 @@ newBirthDescriptor{
}, },
stats = { mag=5, dex=3, wil=1, }, stats = { mag=5, dex=3, wil=1, },
talents_types = { talents_types = {
["spell/alchemy"]={true, 0.3}, ["spell/explosives"]={true, 0.3},
["spell/infusion"]={true, 0.3}, ["spell/infusion"]={true, 0.3},
["spell/golemancy"]={true, 0.3}, ["spell/golemancy"]={true, 0.3},
["spell/advanced-golemancy"]={false, 0.3}, ["spell/advanced-golemancy"]={false, 0.3},
["spell/gemology"]={true, 0.3}, ["spell/stone-alchemy"]={true, 0.3},
["spell/herbalism"]={false, 0.3}, ["spell/fire-alchemy"]={false, 0.3},
["spell/staff-combat"]={true, 0.3}, ["spell/staff-combat"]={true, 0.3},
["cunning/survival"]={false, -0.1}, ["cunning/survival"]={false, -0.1},
["technique/combat-training"]={false, 0}, ["technique/combat-training"]={false, 0},
......
...@@ -42,7 +42,8 @@ setDefaultProjector(function(src, x, y, type, dam) ...@@ -42,7 +42,8 @@ setDefaultProjector(function(src, x, y, type, dam)
-- Reduce damage with resistance -- Reduce damage with resistance
if target.resists then if target.resists then
local pen = (src.resists_pen.all or 0) + (src.resists_pen[type] or 0) local pen = 0
if src.resists_pen then pen = (src.resists_pen.all or 0) + (src.resists_pen[type] or 0) end
local res = (target.resists.all or 0) + (target.resists[type] or 0) local res = (target.resists.all or 0) + (target.resists[type] or 0)
res = res * (100 - pen) / 100 res = res * (100 - pen) / 100
print("[PROJECTOR] res", res, (100 - res) / 100, " on dam", dam) print("[PROJECTOR] res", res, (100 - res) / 100, " on dam", dam)
......
...@@ -40,7 +40,7 @@ newEntity{ ...@@ -40,7 +40,7 @@ newEntity{
energy = { mod=1 }, energy = { mod=1 },
stats = { str=20, dex=8, mag=6, con=16 }, stats = { str=20, dex=8, mag=6, con=16 },
resists = { [DamageType.PHYSICAL] = 20, [DamageType.FIRE] = 50, }, resists = { [DamageType.PHYSICAL] = 20, [DamageType.COLD] = 50, },
no_breath = 1, no_breath = 1,
confusion_immune = 1, confusion_immune = 1,
......
...@@ -28,16 +28,12 @@ newTalent{ ...@@ -28,16 +28,12 @@ newTalent{
self.alchemy_golem:learnTalent(self.T_SWORD_MASTERY, true) self.alchemy_golem:learnTalent(self.T_SWORD_MASTERY, true)
self.alchemy_golem:learnTalent(self.T_MACE_MASTERY, true) self.alchemy_golem:learnTalent(self.T_MACE_MASTERY, true)
self.alchemy_golem:learnTalent(self.T_AXE_MASTERY, true) self.alchemy_golem:learnTalent(self.T_AXE_MASTERY, true)
self.alchemy_golem:learnTalent(self.T_HEAVY_ARMOUR_TRAINING, true)
self.alchemy_golem:learnTalent(self.T_MASSIVE_ARMOUR_TRAINING, true)
end, end,
on_unlearn = function(self, t) on_unlearn = function(self, t)
self.alchemy_golem:unlearnTalent(self.T_WEAPON_COMBAT, true) self.alchemy_golem:unlearnTalent(self.T_WEAPON_COMBAT, true)
self.alchemy_golem:unlearnTalent(self.T_SWORD_MASTERY, true) self.alchemy_golem:unlearnTalent(self.T_SWORD_MASTERY, true)
self.alchemy_golem:unlearnTalent(self.T_MACE_MASTERY, true) self.alchemy_golem:unlearnTalent(self.T_MACE_MASTERY, true)
self.alchemy_golem:unlearnTalent(self.T_AXE_MASTERY, true) self.alchemy_golem:unlearnTalent(self.T_AXE_MASTERY, true)
self.alchemy_golem:unlearnTalent(self.T_HEAVY_ARMOUR_TRAINING, true)
self.alchemy_golem:unlearnTalent(self.T_MASSIVE_ARMOUR_TRAINING, true)
end, end,
info = function(self, t) info = function(self, t)
return ([[Improves your golem proficiency with two handed weapons.]]) return ([[Improves your golem proficiency with two handed weapons.]])
......
...@@ -109,6 +109,7 @@ newTalent{ ...@@ -109,6 +109,7 @@ newTalent{
if ammo then dam, damtype = t.computeDamage(self, t, ammo) end if ammo then dam, damtype = t.computeDamage(self, t, ammo) end
return ([[Imbue an alchemist gem with an explosive charge of mana and throw it. return ([[Imbue an alchemist gem with an explosive charge of mana and throw it.
The gem will explode for %0.2f %s damage. The gem will explode for %0.2f %s damage.
Each kind of gem will also provide a specific effect.
The damage will improve with better gems and Magic stat and the range with your dexterity.]]):format(dam, DamageType:get(damtype).name) The damage will improve with better gems and Magic stat and the range with your dexterity.]]):format(dam, DamageType:get(damtype).name)
end, end,
} }
...@@ -149,38 +150,82 @@ newTalent{ ...@@ -149,38 +150,82 @@ newTalent{
} }
newTalent{ newTalent{
name = "Stone Touch", name = "Shockwave Bomb",
type = {"spell/explosives",4}, type = {"spell/explosives",4},
require = spells_req4, require = spells_req4,
points = 5, points = 5,
mana = 80, mana = 40,
cooldown = 15, cooldown = 10,
range = function(self, t) range = function(self, t)
if self:getTalentLevel(t) < 3 then return 1 return math.ceil(5 + self:getDex(12))
else return math.floor(self:getTalentLevel(t)) end end,
computeDamage = function(self, t, ammo)
local inc_dam = 0
local damtype = DamageType.SPELLKNOCKBACK
local particle = "ball_fire"
inc_dam = self:getTalentLevel(self.T_FIRE_INFUSION) * 0.05 + (ammo.alchemist_bomb.power or 0) / 100
local dam = self:combatTalentSpellDamage(t, 15, 120, (ammo.alchemist_power + self:combatSpellpower()) / 2)
dam = dam * (1 + inc_dam)
return dam, damtype, particle
end, end,
action = function(self, t) action = function(self, t)
local tg = {type="beam", range=self:getTalentRange(t), talent=t} local ammo = self:hasAlchemistWeapon()
if self:getTalentLevel(t) >= 3 then tg.type = "beam" end if not ammo or ammo:getNumber() < 2 then
game.logPlayer(self, "You need to ready at least two alchemist gems in your quiver.")
return
end
local tg = {type="ball", range=self:getTalentRange(t)+(ammo.alchemist_bomb.range or 0), radius=2, talent=t}
local x, y = self:getTarget(tg) local x, y = self:getTarget(tg)
if not x or not y then return nil end if not x or not y then return nil end
self:project(tg, x, y, function(tx, ty)
ammo = self:removeObject(self:getInven("QUIVER"), 1)
if not ammo then return end
local dam, damtype, particle = t.computeDamage(self, t, ammo)
local prot = self:getTalentLevelRaw(self.T_ALCHEMIST_PROTECTION) * 0.2
local golem = game.level:hasEntity(self.alchemy_golem) and self.alchemy_golem or nil
local dam_done = 0
local tmp = {}
local grids = self:project(tg, x, y, function(tx, ty)
local d = dam
-- Protect yourself
if tx == self.x and ty == self.y then d = dam * (1 - prot) end
-- Protect the golem
if golem and tx == golem.x and ty == golem.y then d = dam * (1 - prot) end
DamageType:get(damtype).projector(self, tx, ty, damtype, self:spellCrit(d), tmp)
local target = game.level.map(tx, ty, Map.ACTOR) local target = game.level.map(tx, ty, Map.ACTOR)
if not target then return end if not target then return end
if ammo.alchemist_bomb.splash then
if target:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 10) and target:canBe("stone") and target:canBe("instakill") then DamageType:get(DamageType[ammo.alchemist_bomb.splash.type]).projector(self, tx, ty, DamageType[ammo.alchemist_bomb.splash.type], ammo.alchemist_bomb.splash.dam)
target:setEffect(target.EFF_STONED, math.floor((3 + self:getTalentLevel(t)) / 1.5), {}) end
game.level.map:particleEmitter(tx, ty, 1, "archery") if ammo.alchemist_bomb.stun and rng.percent(ammo.alchemist_bomb.stun.chance) and target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 5) and target:canBe("stun") then
target:setEffect(target.EFF_STUNNED, ammo.alchemist_bomb.stun.dur, {})
end
if ammo.alchemist_bomb.daze and rng.percent(ammo.alchemist_bomb.daze.chance) and target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 5) and target:canBe("stun") then
target:setEffect(target.EFF_DAZED, ammo.alchemist_bomb.daze.dur, {})
end end
end) end)
game:playSoundNear(self, "talents/earth")
if ammo.alchemist_bomb.leech then self:heal(math.min(self.max_life * ammo.alchemist_bomb.leech / 100, dam_done)) end
local _ _, x, y = self:canProject(tg, x, y)
game.level.map:particleEmitter(x, y, tg.radius, particle, {radius=tg.radius, grids=grids, tx=x, ty=y})
if ammo.alchemist_bomb.mana then self:incMana(ammo.alchemist_bomb.mana) end
game:playSoundNear(self, "talents/arcane")
return true return true
end, end,
info = function(self, t) info = function(self, t)
return ([[Touch your foe and turn it into stone for %d turns. local ammo = self:hasAlchemistWeapon()
Stoned creatures are unable to act or regen life and are very brittle. local dam, damtype = 1
If a stoned creature if hit by an attack that deals more than 30%% of its life it will shatter and be destroyed. if ammo then dam = t.computeDamage(self, t, ammo) end
Stoned creatures are highly resistant to fire and lightning and somewhat resistant to physical attacks. return ([[Crush together two alchemmist gems, this makes them extremely unstable.
At level 3 it will become a beam.]]):format(math.floor((3 + self:getTalentLevel(t)) / 1.5)) You then throw them to a target area, they explode on impact dealing %0.2f physical damage and knocking back any creatures in the blast radius.
Each kind of gem will also provide a specific effect.
The damage will improve with better gems and Magic stat and the range with your dexterity.]]):format(dam)
end, end,
} }
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
newTalent{ newTalent{
name = "Create Alchemist Gems", name = "Create Alchemist Gems",
type = {"spell/gemology-base", 1}, type = {"spell/stone-alchemy-base", 1},
require = spells_req1, require = spells_req1,
points = 1, points = 1,
range = function(self, t) range = function(self, t)
...@@ -58,7 +58,7 @@ newTalent{ ...@@ -58,7 +58,7 @@ newTalent{
newTalent{ newTalent{
name = "Extract Gems", name = "Extract Gems",
type = {"spell/gemology", 1}, type = {"spell/stone-alchemy", 1},
require = spells_req1, require = spells_req1,
points = 5, points = 5,
mana = 5, mana = 5,
...@@ -84,7 +84,7 @@ newTalent{ ...@@ -84,7 +84,7 @@ newTalent{
newTalent{ newTalent{
name = "Imbue Item", name = "Imbue Item",
type = {"spell/gemology", 2}, type = {"spell/stone-alchemy", 2},
require = spells_req2, require = spells_req2,
points = 5, points = 5,
mana = 80, mana = 80,
...@@ -106,39 +106,10 @@ newTalent{ ...@@ -106,39 +106,10 @@ newTalent{
You can only imbue items once, and it is permanent.]]) You can only imbue items once, and it is permanent.]])
end, end,
} }
newTalent{
name = "Gem Vision",
type = {"spell/gemology", 3},
require = spells_req3,
cooldown = 10,
mana = 15,
points = 5,
action = function(self, t)
local ammo = self:hasAlchemistWeapon()
if not ammo or ammo:getNumber() < 2 then
game.logPlayer(self, "You need to ready 2 alchemist gems in your quiver.")
return
end
local x, y = self:getTarget{type="ball", nolock=true, no_restrict=true, range=100, radius=3 + self:getTalentLevel(t)}
if not x then return nil end
for i = 1, 2 do self:removeObject(self:getInven("QUIVER"), 1) end
self:magicMap(3 + self:getTalentLevel(t), x, y)
game:playSoundNear(self, "talents/spell_generic2")
return true
end,
info = function(self, t)
return ([[Consumes two alchemist gems to see remote areas in a radius of %d.]]):
format(3 + self:getTalentLevel(t))
end,
}
newTalent{ newTalent{
name = "Gem Portal", name = "Gem Portal",
type = {"spell/gemology",4}, type = {"spell/stone-alchemy",3},
require = spells_req4, require = spells_req3,
cooldown = 20, cooldown = 20,
mana = 20, mana = 20,
points = 5, points = 5,
...@@ -167,3 +138,40 @@ newTalent{ ...@@ -167,3 +138,40 @@ newTalent{
format(math.floor(4 + self:combatSpellpower(0.06) * self:getTalentLevel(t))) format(math.floor(4 + self:combatSpellpower(0.06) * self:getTalentLevel(t)))
end, end,
} }
newTalent{
name = "Stone Touch",
type = {"spell/stone-alchemy",4},
require = spells_req4,
points = 5,
mana = 80,
cooldown = 15,
range = function(self, t)
if self:getTalentLevel(t) < 3 then return 1
else return math.floor(self:getTalentLevel(t)) end
end,
action = function(self, t)
local tg = {type="beam", range=self:getTalentRange(t), talent=t}
if self:getTalentLevel(t) >= 3 then tg.type = "beam" end
local x, y = self:getTarget(tg)
if not x or not y then return nil end
self:project(tg, x, y, function(tx, ty)
local target = game.level.map(tx, ty, Map.ACTOR)
if not target then return end
if target:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 10) and target:canBe("stone") and target:canBe("instakill") then
target:setEffect(target.EFF_STONED, math.floor((3 + self:getTalentLevel(t)) / 1.5), {})
game.level.map:particleEmitter(tx, ty, 1, "archery")
end
end)
game:playSoundNear(self, "talents/earth")
return true
end,
info = function(self, t)
return ([[Touch your foe and turn it into stone for %d turns.
Stoned creatures are unable to act or regen life and are very brittle.
If a stoned creature is hit by an attack that deals more than 30%% of its life it will shatter and be destroyed.
Stoned creatures are highly resistant to fire and lightning and somewhat resistant to physical attacks.
At level 3 it will become a beam.]]):format(math.floor((3 + self:getTalentLevel(t)) / 1.5))
end,
}
No preview for this file type
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment