Skip to content
Snippets Groups Projects
Commit 2624a783 authored by dg's avatar dg
Browse files

Big overhaul of the Cursed/Doomed classes

git-svn-id: http://svn.net-core.org/repos/t-engine4@4453 51575b47-30f0-44d4-a5cc-537603b46e54
parent da84c188
No related branches found
No related tags found
No related merge requests found
Showing
with 326 additions and 174 deletions
......@@ -86,7 +86,7 @@ end
--- Move one step to the given target if possible
-- This tries the most direct route, if not available it checks sides and always tries to get closer
function _M:moveDirection(x, y)
function _M:moveDirection(x, y, force)
if not self.x or not self.y then return false end
local l = line.new(self.x, self.y, x, y)
local lx, ly = l()
......@@ -109,10 +109,10 @@ function _M:moveDirection(x, y)
-- Move to closest
if #l > 0 then
table.sort(l, function(a,b) return a[3]<b[3] end)
return self:move(l[1][1], l[1][2])
return self:move(l[1][1], l[1][2], force)
end
else
return self:move(lx, ly)
return self:move(lx, ly, force)
end
end
end
......
......@@ -217,6 +217,39 @@ end
function _M:useEnergy(val)
engine.Actor.useEnergy(self, val)
-- handle stalking
local effStalker = self:hasEffect(self.EFF_STALKER)
if effStalker then
if effStalker.hit then
-- consecutive hit on stalkee..add hate then bonus
local t = self:getTalentFromId(self.T_STALK)
self:incHate(t.getHitHateChange(self, t, effStalker.bonus))
effStalker.bonus = math.min(3, (effStalker.bonus or 1) + 1)
effStalker.hit = false
else
-- no consecutive hit on stalkee..remove bonus
effStalker.bonus = math.max(1, (effStalker.bonus or 1) - 1)
end
elseif self:isTalentActive(self.T_STALK) then
local stalk = self:isTalentActive(self.T_STALK)
if stalk.hit and stalk.hit_target and not stalk.hit_target.dead then
stalk.hit_turns = (stalk.hit_turns or 0) + 1
stalk.hit = false
if stalk.hit_turns > 1 then
-- multiple hits begin stalking
local t = self:getTalentFromId(self.T_STALK)
t.doStalk(self, t, stalk.hit_target)
stalk.hit_turns = 0
stalk.hit_target = nil
end
else
stalk.hit = false
stalk.hit_target = nil
stalk.hit_turns = 0
end
end
-- Do not fire those talents if this is not turn's end
if self:enoughEnergy() or game.zone.wilderness then return end
if self:isTalentActive(self.T_KINETIC_AURA) then
......@@ -261,10 +294,27 @@ function _M:actBase()
end
self:regenResources()
-- Hate decay
if self:knowTalent(self.T_HATE_POOL) and self.hate > 0 then
if self:knowTalent(self.T_HATE_POOL) then
-- hate loss speeds up as hate increases
local hateChange = -math.max(0.02, 0.07 * math.pow(self.hate / 10, 1.5))
self:incHate(hateChange)
if self:knowTalent(self.T_SEETHE) then
-- seethe prevents loss at low levels and gains some back and very low levels
local t = self:getTalentFromId(self.T_SEETHE)
local hateLossMinHate = t.getHateLossMinHate(self, t)
local hateGainMaxHate = t.getHateGainMaxHate(self, t)
if self.hate < hateGainMaxHate then
hateChange = math.min(t.getHateGainChange(self, t), hateGainMaxHate - self.hate)
elseif self.hate < hateLossMinHate then
hateChange = 0
elseif self.hate + hateChange <= hateLossMinHate then
hateChange = hateLossMinHate - self.hate
end
end
if hateChange ~= 0 then
self:incHate(hateChange)
end
end
-- Compute timed effects
......@@ -967,11 +1017,6 @@ function _M:onTakeHit(value, src)
if self:hasEffect(self.EFF_SPACETIME_TUNING) then
self:removeEffect(self.EFF_SPACETIME_TUNING)
end
-- remove stalking if there is an interaction
if self.stalker and src and self.stalker == src then
self.stalker:removeEffect(self.EFF_STALKER)
self:removeEffect(self.EFF_STALKED)
end
-- Remove domination hex
if self:hasEffect(self.EFF_DOMINATION_HEX) and src and src == self:hasEffect(self.EFF_DOMINATION_HEX).src then
......@@ -1463,6 +1508,12 @@ function _M:die(src)
local t = src:getTalentFromId(src.T_CRUEL_VIGOR)
t.on_kill(src, t)
end
local effStalked = self:hasEffect(self.EFF_STALKED)
if effStalked and not effStalked.source.dead and effStalked.source:hasEffect(self.EFF_STALKER) then
local t = effStalked.source:getTalentFromId(effStalked.source.T_STALK)
t.on_targetDied(effStalked.source, t, self)
end
if src and src.knowTalent and src:knowTalent(src.T_BLOODRAGE) then
local t = src:getTalentFromId(src.T_BLOODRAGE)
......@@ -1843,6 +1894,12 @@ function _M:onWear(o, bypass_set)
o.talent_on_spell[i]._id = id
end
end
-- apply any special cursed logic
if self:knowTalent(self.T_CURSED_TOUCH) then
local t = self:getTalentFromId(self.T_CURSED_TOUCH)
t.on_onWear(self, t, o)
end
self:updateModdableTile()
end
......@@ -1888,6 +1945,12 @@ function _M:onTakeoff(o, bypass_set)
self.talent_on_spell[id] = nil
end
end
-- apply any special cursed logic
if self:knowTalent(self.T_CURSED_TOUCH) then
local t = self:getTalentFromId(self.T_CURSED_TOUCH)
t.on_onTakeOff(self, t, o)
end
self:updateModdableTile()
end
......@@ -2700,13 +2763,6 @@ function _M:canSeeNoCache(actor, def, def_pct)
end
end
-- check if the actor is stalking you
if self.stalker then
if self.stalker == actor then
return false, 0
end
end
-- Check for invisibility. This is a "simple" checkHit between invisible and see_invisible attrs
if actor:attr("invisible") then
-- Special case, 0 see invisible, can NEVER see invisible things
......
......@@ -227,7 +227,7 @@ function _M:act()
-- Clean log flasher
-- game.flash:empty()
-- update feed immediately before the player moves for best visual consistency (this is not perfect but looks much better than updating mid-move)
-- update feed/beckoned immediately before the player moves for best visual consistency (this is not perfect but looks much better than updating mid-move)
if self:hasEffect(self.EFF_FEED) then
self.tempeffect_def[self.EFF_FEED].updateFeed(self, self:hasEffect(self.EFF_FEED))
elseif self:hasEffect(self.EFF_FED_UPON) then
......@@ -349,6 +349,13 @@ function _M:playerFOV()
game.level.map.seens(x, y, 0.6)
end
end, true, true, true)
local effStalker = self:hasEffect(self.EFF_STALKER)
if effStalker then
if core.fov.distance(self.x, self.y, effStalker.target.x, effStalker.target.y) <= 10 then
game.level.map.seens(effStalker.target.x, effStalker.target.y, 0.6)
end
end
end
if not self:attr("blind") then
......
......@@ -89,11 +89,6 @@ function _M:attackTarget(target, damtype, mult, noenergy)
game.logPlayer(self, "%s notices you at the last moment!", target.name:capitalize())
end
if target and target:hasEffect(self.EFF_DOMINATED) and target.dominatedSource and target.dominatedSource == self then
-- target is being dominated by self
mult = (mult or 1) * (target.dominatedDamMult or 1)
end
-- Change attack type if using gems
if not damtype and self:getInven(self.INVEN_GEM) then
local gems = self:getInven(self.INVEN_GEM)
......@@ -171,9 +166,9 @@ function _M:attackTarget(target, damtype, mult, noenergy)
elseif sound_miss then game:playSoundNear(self, sound_miss) end
-- cleave second attack
if self:knowTalent(self.T_CLEAVE) then
if self:isTalentActive(self.T_CLEAVE) then
local t = self:getTalentFromId(self.T_CLEAVE)
t.on_attackTarget(self, t, target, multiplier)
t.on_attackTarget(self, t, target)
end
-- Cancel stealth!
......@@ -219,6 +214,15 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
-- Does the blow connect? yes .. complex :/
local atk, def = self:combatAttack(weapon), target:combatDefense()
-- add stalker damage and attack bonus
local effStalker = self:hasEffect(self.EFF_STALKER)
if effStalker and effStalker.target == target then
local t = self:getTalentFromId(self.T_STALK)
atk = atk + t.getAttackChange(self, t, effStalker.bonus)
mult = mult * t.getStalkedDamageMultiplier(self, t, effStalker.bonus)
end
if not self:canSee(target) then atk = atk / 3 end
local dam, apr, armor = force_dam or self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
print("[ATTACK] to ", target.name, " :: ", dam, apr, armor, def, "::", mult)
......@@ -228,11 +232,20 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
def = def + diff * target:getTalentLevelRaw(target.T_DUCK_AND_DODGE) * 1.2
end
-- check repel
local repelled = false
if target:isTalentActive(target.T_REPEL) then
local t = target:getTalentFromId(target.T_REPEL)
repelled = t.isRepelled(target, t)
end
-- If hit is over 0 it connects, if it is 0 we still have 50% chance
local hitted = false
local crit = false
local evaded = false
if self:checkEvasion(target) then
if repelled then
game.logSeen(target, "%s repels an attack from %s.", target.name:capitalize(), self.name)
elseif self:checkEvasion(target) then
evaded = true
game.logSeen(target, "%s evades %s.", target.name:capitalize(), self.name)
elseif self:checkHit(atk, def) then
......@@ -263,6 +276,25 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
local srcname = game.level.map.seens(self.x, self.y) and self.name:capitalize() or "Something"
game.logSeen(target, "%s misses %s.", srcname, target.name)
end
-- handle stalk targeting for hits (also handled in Actor for turn end effects)
if hitted and target ~= self then
if effStalker then
-- mark if stalkee was hit
effStalker.hit = effStalker.hit or effStalker.target == target
elseif self:isTalentActive(self.T_STALK) then
local stalk = self:isTalentActive(self.T_STALK)
if not stalk.hit then
-- mark a new target
stalk.hit = true
stalk.hit_target = target
elseif stalk.hit_target ~= target then
-- more than one target; clear it
stalk.hit_target = nil
end
end
end
-- Spread diseases
if hitted and self:knowTalent(self.T_CARRIER) and rng.percent(4 * self:getTalentLevelRaw(self.T_CARRIER)) then
......@@ -516,6 +548,10 @@ function _M:combatDefense()
local t = self:getTalentFromId(self.T_STEADY_MIND)
add = add + t.getDefense(self, t)
end
if self:isTalentActive(Talents.T_SURGE) then
local t = self:getTalentFromId(self.T_SURGE)
add = add + t.getDefenseChange(self, t)
end
local d = math.max(0, self.combat_def + (self:getDex() - 10) * 0.35 + add + (self:getLck() - 50) * 0.4)
if self:hasLightArmor() and self:knowTalent(self.T_MOBILE_DEFENCE) then
......@@ -690,7 +726,7 @@ function _M:combatSpellpower(mod)
add = add + self:hasEffect(self.EFF_BLOODLUST).dur
end
return (self.combat_spellpower + add + self:getMag()) * mod
return ((self.combat_spellpower > 0 and self.combat_spellpower or 0) + add + self:getMag()) * mod
end
--- Gets damage based on talent
......@@ -718,6 +754,7 @@ function _M:getOffHandMult(mult)
elseif self:knowTalent(Talents.T_CORRUPTED_STRENGTH) then
offmult = (mult or 1) / (2 - (math.min(self:getTalentLevel(Talents.T_CORRUPTED_STRENGTH), 8) / 9))
end
return offmult
end
......@@ -748,13 +785,6 @@ function _M:physicalCrit(dam, weapon, target)
return dam * (1.5 + self:getTalentLevel(self.T_SHADOWSTRIKE) / 7), true
end
if target.stalker and target.stalker == self and self:knowTalent(self.T_STALK) then
local t = self:getTalentFromId(self.T_STALK)
if rng.percent(math.min(100, 40 + self:getTalentLevel(t) * 12)) then
return dam * 1.5, true
end
end
local chance = self:combatCrit(weapon)
local crit = false
if self:knowTalent(self.T_BACKSTAB) and target:attr("stunned") then chance = chance + self:getTalentLevel(self.T_BACKSTAB) * 10 end
......@@ -827,7 +857,7 @@ end
function _M:combatMindpower(mod)
mod = mod or 1
local add = 0
return (self.combat_mindpower + add + self:getWil() * 0.7 + self:getCun() * 0.4) * mod
return ((self.combat_mindpower > 0 and self.combat_mindpower or 0) + add + self:getWil() * 0.7 + self:getCun() * 0.4) * mod
end
--- Gets damage based on talent
......@@ -957,6 +987,20 @@ function _M:hasCursedWeapon()
return weapon
end
--- Check if the actor has a cursed weapon
function _M:hasCursedOffhandWeapon()
if self:attr("disarmed") then
return nil, "disarmed"
end
if not self:getInven("OFFHAND") then return end
local weapon = self:getInven("OFFHAND")[1]
if not weapon or not weapon.combat or not weapon.cursed then
return nil
end
return weapon
end
--- Check if the actor has a two handed weapon
function _M:hasTwoHandedWeapon()
if self:attr("disarmed") then
......
......@@ -57,9 +57,9 @@ newBirthDescriptor{
stats = { wil=4, str=5, },
talents_types = {
["cursed/gloom"]={true, 0.0},
["cursed/slaughter"]={true, 0.0},
["cursed/endless-hunt"]={true, 0.0},
["cursed/strife"]={true, 0.0},
["cursed/slaughter"]={true, 0.3},
["cursed/endless-hunt"]={true, 0.3},
["cursed/strife"]={true, 0.3},
["cursed/cursed-form"]={true, 0.0},
["cursed/fateful-aura"]={true, 0.0},
["cursed/unyielding"]={true, 0.0},
......
......@@ -69,18 +69,6 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
end
-- dark vision increases damage done in creeping dark
if src and src.knowTalent and src:knowTalent(src.T_DARK_VISION) then
local t = src:getTalentFromId(src.T_DARK_VISION)
local damageIncrease = t.getDamageIncrease(src, t)
if damageIncrease > 0
and src and src.x and src.y
and core.fov.distance(src.x, src.y, target.x, target.y) > (src.lite or 0) -- outside of lite radius
and game.level.map:checkAllEntities(x, y, "creepingDark") then -- creeping dark square
dam = dam + (dam * damageIncrease / 100)
game.logPlayer(src, "You strike in the darkness. (+%d damage)", damageIncrease)
end
end
if src and src.knowTalent and src:knowTalent(src.T_DARK_VISION)
and src.x and src.y
and game.level.map:checkAllEntities(x, y, "creepingDark") then
......@@ -145,6 +133,8 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr)
if target.resists then
local pen = 0
if src.resists_pen then pen = (src.resists_pen.all or 0) + (src.resists_pen[type] or 0) end
local dominated = target:hasEffect(target.EFF_DOMINATED)
if dominated and dominated.source == src then pen = pen + (dominated.resistPenetration or 0) end
local res = target:combatGetResist(type)
res = res * (100 - pen) / 100
print("[PROJECTOR] res", res, (100 - res) / 100, " on dam", dam)
......
......@@ -81,7 +81,6 @@ newEntity{
{tid=e.T_SUMMON, level=1},
{tid=e.T_WILLFUL_STRIKE, level=5},
{tid=e.T_REPROACH, level=5},
{tid=e.T_ENRAGE, level=4},
{tid=e.T_FEED_STRENGTHS, level=4},
{tid=e.T_FEED_POWER, level=4},
}
......
......@@ -186,8 +186,8 @@ newEntity{
item.wielder.talents_types_mastery["cursed/slaughter"] = math.max(item.wielder.talents_types_mastery["cursed/slaughter"] or 0, math.ceil(15 * power) * 0.01)
item.wielder.talent_cd_reduction = item.wielder.talent_cd_reduction or {}
item.wielder.talent_cd_reduction[Talents.T_SLASH] = math.max(item.wielder.talent_cd_reduction[Talents.T_SLASH] or 0, math.ceil(3 * power))
item.wielder.talent_cd_reduction[Talents.T_FRENZY] = math.max(item.wielder.talent_cd_reduction[Talents.T_FRENZY] or 0, math.ceil(5 * power))
item.wielder.talent_cd_reduction[Talents.T_SLASH] = math.max(item.wielder.talent_cd_reduction[Talents.T_SLASH] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_FRENZY] = math.max(item.wielder.talent_cd_reduction[Talents.T_FRENZY] or 0, math.ceil(3 * power))
end,
}
newEntity{
......@@ -195,7 +195,7 @@ newEntity{
apply = function(item, who, power)
item.combat = item.combat or {}
item.combat.atk = (item.combat.atk or 0) + math.ceil(8 * power)
item.combat.apr = (item.combat.atk or 0) + math.ceil(8 * power)
item.combat.apr = (item.combat.apr or 0) + math.ceil(8 * power)
item.combat.combat_physcrit = (item.combat.combat_physcrit or 0) + math.ceil(5 * power)
item.wielder = item.wielder or {}
......@@ -203,8 +203,7 @@ newEntity{
item.wielder.talents_types_mastery["cursed/endless-hunt"] = math.max(item.wielder.talents_types_mastery["cursed/endless-hunt"] or 0, math.ceil(5 * power) * 0.01)
item.wielder.talent_cd_reduction = item.wielder.talent_cd_reduction or {}
item.wielder.talent_cd_reduction[Talents.T_DOMINATE] = math.max(item.wielder.talent_cd_reduction[Talents.T_DOMINATE] or 0, 1)
item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] = math.max(item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] or 0, 1)
item.wielder.talent_cd_reduction[Talents.T_HARASS_PREY] = math.max(item.wielder.talent_cd_reduction[Talents.T_HARASS_PREY] or 0, 1)
end,
}
newEntity{
......@@ -212,7 +211,7 @@ newEntity{
apply = function(item, who, power)
item.combat = item.combat or {}
item.combat.atk = (item.combat.atk or 0) + math.ceil(10 * power)
item.combat.apr = (item.combat.atk or 0) + math.ceil(10 * power)
item.combat.apr = (item.combat.apr or 0) + math.ceil(10 * power)
item.combat.combat_physcrit = (item.combat.combat_physcrit or 0) + math.ceil(5 * power)
item.wielder = item.wielder or {}
......@@ -220,8 +219,7 @@ newEntity{
item.wielder.talents_types_mastery["cursed/endless-hunt"] = math.max(item.wielder.talents_types_mastery["cursed/endless-hunt"] or 0, math.ceil(15 * power) * 0.01)
item.wielder.talent_cd_reduction = item.wielder.talent_cd_reduction or {}
item.wielder.talent_cd_reduction[Talents.T_DOMINATE] = math.max(item.wielder.talent_cd_reduction[Talents.T_DOMINATE] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] = math.max(item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_HARASS_PREY] = math.max(item.wielder.talent_cd_reduction[Talents.T_HARASS_PREY] or 0, 1)
end,
}
newEntity{
......@@ -235,9 +233,8 @@ newEntity{
item.wielder.talents_types_mastery["cursed/strife"] = math.max(item.wielder.talents_types_mastery["cursed/strife"] or 0, math.ceil(5 * power) * 0.01)
item.wielder.talent_cd_reduction = item.wielder.talent_cd_reduction or {}
item.wielder.talent_cd_reduction[Talents.T_BAIT] = math.max(item.wielder.talent_cd_reduction[Talents.T_BAIT] or 0, 1)
item.wielder.talent_cd_reduction[Talents.T_SMASH] = math.max(item.wielder.talent_cd_reduction[Talents.T_SMASH] or 0, 1)
item.wielder.talent_cd_reduction[Talents.T_ASSAIL] = math.max(item.wielder.talent_cd_reduction[Talents.T_ASSAIL] or 0, math.ceil(3 * power))
item.wielder.talent_cd_reduction[Talents.T_DOMINATE] = math.max(item.wielder.talent_cd_reduction[Talents.T_DOMINATE] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] = math.max(item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] or 0, math.ceil(2 * power))
end,
}
newEntity{
......@@ -251,9 +248,8 @@ newEntity{
item.wielder.talents_types_mastery["cursed/strife"] = math.max(item.wielder.talents_types_mastery["cursed/strife"] or 0, math.ceil(15 * power) * 0.01)
item.wielder.talent_cd_reduction = item.wielder.talent_cd_reduction or {}
item.wielder.talent_cd_reduction[Talents.T_BAIT] = math.max(item.wielder.talent_cd_reduction[Talents.T_BAIT] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_SMASH] = math.max(item.wielder.talent_cd_reduction[Talents.T_SMASH] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_ASSAIL] = math.max(item.wielder.talent_cd_reduction[Talents.T_ASSAIL] or 0, math.ceil(6 * power))
item.wielder.talent_cd_reduction[Talents.T_DOMINATE] = math.max(item.wielder.talent_cd_reduction[Talents.T_DOMINATE] or 0, math.ceil(2 * power))
item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] = math.max(item.wielder.talent_cd_reduction[Talents.T_BLINDSIDE] or 0, math.ceil(2 * power))
end,
}
......
......@@ -22,27 +22,28 @@ base_size = 32
return { generator = function()
local ad = rng.range(0, 360)
local a = math.rad(ad)
local dir = math.rad(ad)
local r = rng.range(15, 18)
local dirchance = rng.chance(2)
local r = 18
local life = 35
local x1 = r * math.cos(a)
local y1 = r * math.sin(a) * 0.2 + 11
local y2 = 11
return {
-- rail = 1,
life = 10,
size = 5, sizev = -0.3, sizea = 0,
life = life,
size = 12, sizev = -11 / life, sizea = 0,
x = r * math.cos(a), xv = 0, xa = 0,
y = r * math.sin(a), yv = 0, ya = 0,
dir = dir, dirv = 0, dira = 0,
vel = -0.4, velv = 0, vela = 0,
x = x1, xv = 0, xa = 0,
y = y1, yv = (y2 - y1) / life, ya = 0,
dir = math.rad(270), dirv = 0, dira = 0,
vel = 5 / life, velv = 9 * (2 / life / life), vela = 0,
r = 88 / 255, rv = 0, ra = 0,
g = 40 / 255, gv = 0, ga = 0,
b = 48 / 255, bv = 0, ba = 0,
a = 180 / 255, av = 0 / 255, aa = 0,
r = (rng.percent(50) and 10 or 160) / 255, rv = 0, ra = 0,
g = 0, gv = 0, ga = 0,
b = 20 / 255, bv = 0, ba = 0,
a = 0.6, av = .2 / life, aa = 0,
}
end, },
function(self)
self.ps:emit(6)
self.ps:emit(3)
end,
60
200
......@@ -19,30 +19,36 @@
base_size = 32
local nb = 0
return { generator = function()
local ad = 90 * rng.range(0, 3)
local a = math.rad(ad)
local dir = math.rad(ad + 90)
local r = rng.range(2, 15)
local dirchance = rng.chance(2)
local angle = math.rad(rng.range(0, 360))
local r = 18
local life = 30
return {
-- rail = 1,
life = 30,
size = 4, sizev = -0.1, sizea = 0,
life = life,
size = 3, sizev = 0, sizea = 0,
x = r * math.cos(a), xv = 0, xa = 0,
y = r * math.sin(a), yv = 0, ya = 0,
dir = dir, dirv = 0, dira = 0,
vel = dirchance and 0.8 or -0.8, velv = 0, vela = 0,
x = r * math.cos(angle), xv = -r * math.cos(angle) / life, xa = 0,
y = r * math.sin(angle), yv = -r * math.sin(angle) / life, ya = 0,
dir = 0, dirv = 0, dira = 0,
vel = 0, velv = 0, vela = 0,
r = 228 / 255, rv = 0, ra = 0,
g = 40 / 255, gv = 0, ga = 0,
b = 5 / 255, bv = 0, ba = 0,
a = 255 / 255, av = 0 / 255, aa = 0,
a = 230 / 255, av = 0, aa = 0,
}
end, },
function(self)
self.ps:emit(60)
if nb == 0 then
self.ps:emit(100)
elseif nb == 10 and bonus >= 2 then
self.ps:emit(100)
elseif nb == 20 and bonus >= 3 then
self.ps:emit(100)
end
nb = (nb + 1) % 40
end,
60
300, nil, true
game/modules/tome/data/gfx/talents/assail.png

5.23 KiB

game/modules/tome/data/gfx/talents/bait.png

3.68 KiB

game/modules/tome/data/gfx/talents/beckon.png

3.72 KiB

game/modules/tome/data/gfx/talents/enrage.png

3.16 KiB

game/modules/tome/data/gfx/talents/harass_prey.png

4.86 KiB

game/modules/tome/data/gfx/talents/repel.png

3.67 KiB

game/modules/tome/data/gfx/talents/stoic.png

1.91 KiB

game/modules/tome/data/gfx/talents/surge.png

3.46 KiB

......@@ -17,10 +17,6 @@
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
local function getHateMultiplier(self, min, max)
return (min + ((max - min) * math.min(self.hate, 10) / 10))
end
local function combatTalentDamage(self, t, min, max)
return self:combatTalentSpellDamage(t, min, max, (self.level + self:getWil()) * 1.2)
end
......@@ -38,7 +34,10 @@ newTalent{
return true
end,
getHealPerKill = function(self, t)
return combatTalentDamage(self, t, 15, 55)
return combatTalentDamage(self, t, 25, 70)
end,
getMaxUnnaturalBodyHeal = function(self, t)
return t.getHealPerKill(self, t) * 2
end,
getRegenRate = function(self, t)
return 3 + math.sqrt(self:getTalentLevel(t) * 2) * math.min(1000, self.max_life) * 0.006
......@@ -46,12 +45,40 @@ newTalent{
getResist = function(self, t)
return -18 + (self:getTalentLevel(t) * 3) + (18 * getHateMultiplier(self, 0, 1))
end,
do_regenLife = function(self, t)
getCurseHealingFactorChange = function(self, t)
return 0.05
end,
updateHealingFactor = function(self, t)
-- initialize
if (self.unnatural_body_healing_factor or 0) == 0 then
if self.unnatural_body_healing_factor == nil then
self.unnatural_body_healing_factor = -0.5
self.healing_factor = (self.healing_factor or 1) + self.unnatural_body_healing_factor
end
-- equipped items changed
local oldHealingFactor = self.unnatural_body_healing_factor
local bonus = t.getCurseHealingFactorChange(self, t)
local newHealingFactor = -0.5
if self:hasShield() and self:hasShield().cursed then newHealingFactor = newHealingFactor + bonus end
if self:getInven("BODY") and self:getInven("BODY")[1] and self:getInven("BODY")[1].cursed then newHealingFactor = newHealingFactor + bonus end
if self:getInven("CLOAK") and self:getInven("CLOAK")[1] and self:getInven("CLOAK")[1].cursed then newHealingFactor = newHealingFactor + bonus end
if self:getInven("HANDS") and self:getInven("HANDS")[1] and self:getInven("HANDS")[1].cursed then newHealingFactor = newHealingFactor + bonus end
if self:getInven("FEET") and self:getInven("FEET")[1] and self:getInven("FEET")[1].cursed then newHealingFactor = newHealingFactor + bonus end
if self:getInven("HEAD") and self:getInven("HEAD")[1] and self:getInven("HEAD")[1].cursed then newHealingFactor = newHealingFactor + bonus end
if self:getInven("BELT") and self:getInven("BELT")[1] and self:getInven("BELT")[1].cursed then newHealingFactor = newHealingFactor + bonus end
if self.unnatural_body_healing_factor ~= newHealingFactor then
self.healing_factor = (self.healing_factor or 1) + newHealingFactor - self.unnatural_body_healing_factor
self.unnatural_body_healing_factor = newHealingFactor
self.changed = true
end
end,
do_regenLife = function(self, t)
-- initialize
if self.unnatural_body_healing_factor == nil then
t.updateHealingFactor(self, t)
end
-- heal
local maxHeal = self.unnatural_body_heal or 0
......@@ -76,87 +103,81 @@ newTalent{
heal = math.min(t.getHealPerKill(self, t), target.max_life)
if heal > 0 then
self.unnatural_body_heal = math.min(self.life, (self.unnatural_body_heal or 0) + heal)
self.unnatural_body_heal = math.min(self.unnatural_body_heal, t.getMaxUnnaturalBodyHeal(self, t))
end
end
end,
info = function(self, t)
-- initialize
if self.unnatural_body_healing_factor == nil then
t.updateHealingFactor(self, t)
end
local healPerKill = t.getHealPerKill(self, t)
local maxUnnaturalBodyHeal = t.getMaxUnnaturalBodyHeal(self, t)
local regenRate = t.getRegenRate(self, t)
local healingFactor = self.unnatural_body_healing_factor or -0.5
local resist = -18 + (self:getTalentLevel(t) * 3)
local curseHealingFactorChange = t.getCurseHealingFactorChange(self, t)
local modifier1, modifier2 = "more", "more"
if resist > 0 then modifier1 = "less" end
if resist + 18 > 0 then modifier2 = "less" end
return ([[Your body's strength is fed by your hatred. With each kill you regenerate %d life at a rate of %0.1f life per turn. This healing cannot be reduced, but most other forms of healing are reduced by 50%%. You also take %d%% %s damage (at 0 Hate) to %d%% %s damage (at 10+ Hate).
Healing from kills improves with the Willpower stat.]]):format(healPerKill, regenRate, math.abs(resist), modifier1, math.abs(resist + 18), modifier2)
return ([[Your body's strength is fed by your hatred. With each kill you regenerate %d life (up to a maximum of %d) at a rate of %0.1f life per turn. This healing cannot be reduced, but most other forms of healing are reduced by %d%%. You also take %d%% %s damage (at 0 Hate) to %d%% %s damage (at 10+ Hate).
Healing from kills improves with the Willpower stat. Each piece of cursed armor you wear restores %d%% of your body's ability to heal.]]):format(healPerKill, maxUnnaturalBodyHeal, regenRate, -healingFactor * 100, math.abs(resist), modifier1, math.abs(resist + 18), modifier2, curseHealingFactorChange * 100)
end,
}
--newTalent{
-- name = "Obsession",
-- type = {"cursed/cursed-form", 2},
-- require = cursed_wil_req2,
-- mode = "passive",
-- points = 5,
-- on_learn = function(self, t)
-- self.hate_per_kill = self.hate_per_kill + 0.1
-- end,
-- on_unlearn = function(self, t)
-- self.hate_per_kill = self.hate_per_kill - 0.1
-- end,
-- info = function(self, t)
-- return ([[Your suffering will become theirs. For every life that is taken you gain an extra %0.1f hate.]]):format(self:getTalentLevelRaw(t) * 0.1)
-- end
--}
newTalent{
name = "Seethe",
type = {"cursed/cursed-form", 2},
require = cursed_wil_req2,
mode = "passive",
points = 5,
getHateLossMinHate = function(self, t)
return math.sqrt(self:getTalentLevel(t)) * 1.3
end,
getHateGainMaxHate = function(self, t)
return math.max(0, self:getTalentLevel(t) * 0.25)
end,
getHateGainChange = function(self, t)
return 0.01
end,
on_learn = function(self, t)
end,
on_unlearn = function(self, t)
end,
info = function(self, t)
local hateLossMinHate = t.getHateLossMinHate(self, t)
local hateGainMaxHate = t.getHateGainMaxHate(self, t)
return ([[You have learned to keep your hatred burning deep inside. Below %0.2f hate you will no longer lose hate over time. Below %0.2f hate you will even slowly gain it back.]]):format(hateLossMinHate, hateGainMaxHate)
end
}
--newTalent{
-- name = "Suffering",
-- name = "Seethe",
-- type = {"cursed/cursed-form", 2},
-- random_ego = "utility",
-- require = cursed_wil_req2,
-- mode = "passive",
-- points = 5,
-- on_learn = function(self, t)
-- return true
-- cooldown = 400,
-- tactical = { BUFF = 1 },
-- getHateGain = function(self, t)
-- return (math.sqrt(self:getTalentLevel(t)) - 0.5) * 3
-- end,
-- on_unlearn = function(self, t)
-- action = function(self, t)
-- self:incHate(t.getHateGain(self, t))
-- game.level.map:particleEmitter(self.x, self.y, 5, "fireflash", {radius=1, tx=self.x, ty=self.y})
-- game:playSoundNear(self, "talents/fireflash")
-- return true
-- end,
-- do_onTakeHit = function(self, t, damage)
-- if damage > 0 then
-- local hatePerLife = (1 + self:getTalentLevel(t)) / (self.max_life * 1.5)
-- self.hate = math.max(self.max_hate, self.hate + damage * hatePerLife)
-- end
-- end,
-- info = function(self, t)
-- local hatePerLife = (1 + self:getTalentLevel(t)) / (self.max_life * 1.5)
-- return ([[Your suffering will become theirs. For every %d life that is taken, you gain 1 hate.]]):format(1 / hatePerLife)
-- end
-- local hateGain = t.getHateGain(self, t)
-- return ([[Focus your rage gaining %0.1f hate.]]):format(hateGain)
-- end,
--}
newTalent{
name = "Seethe",
type = {"cursed/cursed-form", 2},
random_ego = "utility",
require = cursed_wil_req2,
points = 5,
cooldown = 400,
tactical = { BUFF = 1 },
getHateGain = function(self, t)
return (math.sqrt(self:getTalentLevel(t)) - 0.5) * 3
end,
action = function(self, t)
self:incHate(t.getHateGain(self, t))
game.level.map:particleEmitter(self.x, self.y, 5, "fireflash", {radius=1, tx=self.x, ty=self.y})
game:playSoundNear(self, "talents/fireflash")
return true
end,
info = function(self, t)
local hateGain = t.getHateGain(self, t)
return ([[Focus your rage gaining %0.1f hate.]]):format(hateGain)
end,
}
newTalent{
name = "Relentless",
type = {"cursed/cursed-form", 3},
......@@ -183,21 +204,21 @@ newTalent{
}
newTalent{
name = "Enrage",
name = "Stoic",
type = {"cursed/cursed-form", 4},
require = cursed_wil_req4,
mode = "passive",
points = 5,
rage = 0.1,
cooldown = 50,
tactical = { DEFEND = 2 },
action = function(self, t)
local life = 50 + self:getTalentLevel(t) * 50
self:setEffect(self.EFF_INCREASED_LIFE, 20, { life = life })
return true
on_learn = function(self, t)
self:incIncStat("con", 3)
self.hate_per_kill = self.hate_per_kill - 0.03
end,
on_unlearn = function(self, t)
self:incIncStat("con", -3)
self.hate_per_kill = self.hate_per_kill + 0.03
end,
info = function(self, t)
local life = 50 + self:getTalentLevel(t) * 50
return ([[In a burst of rage you become an even more fearsome opponent, gaining %d extra life for 20 turns.]]):format(life)
return ([[Years of battling your curse has given you some mastery over it and restored a part of your former self. If that is the path you choose. (+%d constitution, %0.2f hate gain per kill)]]):format(self:getTalentLevelRaw(t) * 3, 0.8 - 0.03 * self:getTalentLevelRaw(t))
end,
}
......
......@@ -18,9 +18,9 @@
-- darkgod@te4.org
-- Cursed
newTalentType{ allow_random=true, type="cursed/slaughter", name = "slaughter", description = "Your axe yearns for its next victim." }
newTalentType{ allow_random=true, type="cursed/slaughter", name = "slaughter", description = "Your weapon yearns for its next victim." }
newTalentType{ allow_random=true, type="cursed/endless-hunt", name = "endless hunt", description = "Each day you lift your weary body and begin the unending hunt." }
newTalentType{ allow_random=true, type="cursed/strife", name = "strife", description = "It is not enough that they die. So too must they suffer at your hands." }
newTalentType{ allow_random=true, type="cursed/strife", name = "strife", description = "The battlefield is your home; death and confusion, your comfort." }
newTalentType{ allow_random=true, type="cursed/gloom", name = "gloom", description = "All those in your sight must share your despair." }
newTalentType{ allow_random=true, type="cursed/rampage", name = "rampage", description = "Let loose the hate that has grown within." }
......@@ -35,8 +35,8 @@ newTalentType{ allow_random=true, type="cursed/primal-magic", name = "primal mag
-- Generic
newTalentType{ allow_random=true, type="cursed/cursed-form", name = "cursed form", generic = true, description = "You are wracked with the dark energies of the curse." }
newTalentType{ allow_random=true, type="cursed/fateful-aura", name = "fateful aura", generic = true, description = "The things you surround yourself with soon wither away." }
newTalentType{ allow_random=true, type="cursed/dark-figure", name = "dark figure", generic = true, description = "Life as an outcast has given you time to reflect on your misfortunes." }
newTalentType{ allow_random=true, type="cursed/traveler", name = "traveler", generic = true, description = "You have become accustomed to the hard life of a lone traveler." }
newTalentType{ allow_random=false, type="cursed/curses", name = "curses", hide = true, description = "The effects of cursed objects." }
newTalentType{ allow_random=true, type="cursed/dark-figure", name = "dark figure", description = "Life as an outcast has given you time to reflect on your misfortunes." }
cursed_wil_req1 = {
stat = { wil=function(level) return 12 + (level-1) * 2 end },
......@@ -101,6 +101,39 @@ cursed_mag_req5 = {
level = function(level) return 16 + (level-1) end,
}
-- utility functions
function getHateMultiplier(self, min, max, cursedWeaponBonus, hate)
local fraction = (hate or self.hate) / 10
if cursedWeaponBonus then
if self:hasDualWeapon() then
if self:hasCursedWeapon() then fraction = fraction + 0.13 end
if self:hasCursedOffhandWeapon() then fraction = fraction + 0.07 end
else
if self:hasCursedWeapon() then fraction = fraction + 0.2 end
end
end
fraction = math.min(fraction, 1)
return (min + ((max - min) * fraction))
end
function checkWillFailure(self, target, minChance, maxChance, attackStrength)
-- attack power is analogous to mental resist except all willpower and no cunning
local attack = self:getWil() * 0.5 * attackStrength
local defense = target:combatMentalResist()
-- used this instead of checkHit to get a curve that is a little more ratio dependent than difference dependent.
-- + 10 prevents large changes for low attack/defense values
-- 2 * log adjusts falloff to roughly get 0% break near attack = 0.5 * defense and 100% break near attack = 2 * defense
local chance = minChance + (1 + 2 * math.log((attack + 10) / (defense + 10))) * (maxChance - minChance) * 0.5
local result = rng.avg(1, 100)
print("checkWillFailure", self.name, self.level, target.name, target.level, minChance, chance, maxChance)
if result <= minChance then return true end
if result >= maxChance then return false end
return result <= chance
end
load("/data/talents/cursed/slaughter.lua")
load("/data/talents/cursed/endless-hunt.lua")
load("/data/talents/cursed/strife.lua")
......@@ -117,4 +150,3 @@ load("/data/talents/cursed/primal-magic.lua")
load("/data/talents/cursed/cursed-form.lua")
load("/data/talents/cursed/fateful-aura.lua")
load("/data/talents/cursed/dark-figure.lua")
load("/data/talents/cursed/traveler.lua")
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