From cd0f2719c2a1261274809f119bd7c7ceb4a5a85e Mon Sep 17 00:00:00 2001 From: DarkGod <darkgod@net-core.org> Date: Sun, 27 Apr 2014 20:12:12 +0200 Subject: [PATCH] New callbackOnHeal trigger The Heart of the Sandworm Queen can now be corrupted to gain a new talent category: Vile Life --- game/modules/tome/class/Actor.lua | 5 + .../data/general/objects/world-artifacts.lua | 9 +- .../tome/data/gfx/talents/blood_splash.png | Bin 0 -> 3874 bytes .../data/gfx/talents/elemental_discord.png | Bin 0 -> 3660 bytes .../data/gfx/talents/healing_inversion.png | Bin 0 -> 3458 bytes .../tome/data/gfx/talents/vile_transplant.png | Bin 0 -> 3615 bytes .../data/talents/corruptions/vile-life.lua | 142 ++++++++++++------ .../tome/data/timed_effects/magical.lua | 33 +++- .../tome/data/timed_effects/physical.lua | 2 +- .../tome/data/zones/mark-spellblaze/grids.lua | 4 +- .../tome/data/zones/sandworm-lair/objects.lua | 3 +- src/core_lua.c | 6 +- src/map.c | 1 + src/music.c | 2 +- src/web.c | 2 + 15 files changed, 146 insertions(+), 63 deletions(-) create mode 100644 game/modules/tome/data/gfx/talents/blood_splash.png create mode 100644 game/modules/tome/data/gfx/talents/elemental_discord.png create mode 100644 game/modules/tome/data/gfx/talents/healing_inversion.png create mode 100644 game/modules/tome/data/gfx/talents/vile_transplant.png diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index f98564c716..c6dd50ca6c 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -1797,6 +1797,9 @@ function _M:onHeal(value, src) end end + local ret = self:fireTalentCheck("callbackOnHeal", value, src) + if ret then value = ret.value end + -- print("[HEALING]", self.uid, self.name, "for", value) if (not self.resting and (not game.party:hasMember(self) or not game:getPlayer(true).resting)) and value + psi_heal >= 1 and not self:attr("silent_heal") then if game.level.map.seens(self.x, self.y) then @@ -4357,6 +4360,8 @@ local sustainCallbackCheck = { callbackOnArcheryMiss = "talents_on_archery_miss", callbackOnCrit = "talents_on_crit", callbackOnStatChange = "talents_on_stat_change", + callbackOnTakeDamage = "talents_on_take_damage", + callbackOnHeal = "talents_on_heal", } _M.sustainCallbackCheck = sustainCallbackCheck diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua index aba4b3029d..23ef08edd7 100644 --- a/game/modules/tome/data/general/objects/world-artifacts.lua +++ b/game/modules/tome/data/general/objects/world-artifacts.lua @@ -548,7 +548,7 @@ newEntity{ base = "BASE_LIGHT_ARMOR", for eff_id, p in pairs(who.tmp) do -- p only has parameters, we need to get the effect definition (e) to check subtypes local e = who.tempeffect_def[eff_id] - if e.subtype and (e.subtype.bleed or e.subtype.poison or e.subtype.wound) then + if e.status == "detrimental" and e.subtype and (e.subtype.bleed or e.subtype.poison or e.subtype.wound) then -- Copy the effect parameters then change only the source -- This will preserve everything passed to the debuff in setEffect but will use the new source for +damage%, etc @@ -571,9 +571,12 @@ newEntity{ base = "BASE_LIGHT_ARMOR", game.logPlayer(who, "#CRIMSON#Rogue Plight transfers an effect to a nearby enemy!") return true end - end end end end + end + end + end + end return true - end, + end, } newEntity{ diff --git a/game/modules/tome/data/gfx/talents/blood_splash.png b/game/modules/tome/data/gfx/talents/blood_splash.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ef910a1308e32407017dd235ee0d9dde2743de GIT binary patch literal 3874 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 literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/gfx/talents/elemental_discord.png b/game/modules/tome/data/gfx/talents/elemental_discord.png new file mode 100644 index 0000000000000000000000000000000000000000..ec283fcd6f140de02dee01b0064d35e8853ecfe9 GIT binary patch literal 3660 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 literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/gfx/talents/healing_inversion.png b/game/modules/tome/data/gfx/talents/healing_inversion.png new file mode 100644 index 0000000000000000000000000000000000000000..a251145d2a9ac678dde9936a14af440d3631fd12 GIT binary patch literal 3458 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 literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/gfx/talents/vile_transplant.png b/game/modules/tome/data/gfx/talents/vile_transplant.png new file mode 100644 index 0000000000000000000000000000000000000000..7257e6fcd25046955ac9ed99ad13ab0c8fd6fe06 GIT binary patch literal 3615 zcmV+)4&d>LP)<h;3K|Lk000e1NJLTq002M$002M;0ssI2B@5<>00009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-vl8xjg2NLwEL000fXNkl<ZXx{BwZERd;m4435c*f)J zk8y0*@#iLK+I&)#rYS5fq|J(LXbai4bdf-)<wHnSf${^XVoT_1MG;-0swyaz=ytVg zrIu{Os-;4OMii3}wJQRwlK{0nc5EESvB$N?9((4VbN0vkzV}``V<&c;uv+mdvf?|w zbI*C-bDr~@=Um{g>o2=#&Ay1JqN1X)v8JU3O-)FpP+5t1oR~2?tC<Xqj_U9*jf~_n znT+Ro|5qF+DJkjbXxg<4ANT-vT#r%!fV!_{Km@E{B~h?|6`A*N{5XE~EA;earl+U> zVh*HIsSkfR`H4?pQwzvgP3DL7KmbojR9PWP#(D;rAs|+;;?39Tl~-oZojZ3aPmDw& zs;a8ti?LOh-q_f<e}DWl_q&@lu$u_u^XTox@GvqN%4RhZp+o|8by&Y1ZEc_k1jxRJ zbQ*($)Z42fQuHbDc)YT*GL@=sZbo~%{>=uOp2D-wj?T=?tlojLva-AHuK)5E?QP_u zWfpkj=jiT6PfvbgV#4#hXfzs+$K&z1h%j?LpDz>&u~@9Cs;W>Z%*@P$?T*D_<>lqI zwY5!6)Y^)U4qVd(u7W7BDl4%NE8hJtEV6!O4qSI#>tm1M`qsd31>QN0mtMk&6VpW0 z)m5=~Z(`%d=B_SnY(z3btja<HuwrbCjvd2u&yD2s`G$sumX@-X7Ibt_XQ$S65Gy<- zQ57KuSRe{(y+Q!)ryu{gf0a29jYjXjyXCP*lx(O&3GbZ3!GjnX;Tvy^?%RhOH$xR_ zv(|*T-8@zGK%&Y*UwkM(GBWbL@3pV%04t1po|w&s`5TiStPlk|f1dg3#N_1Ug|=P% z1WHRwAAY#ullzni3P3RfeEUgCr}dtDuzzn9fRc?RQDP{oGDws}NmV_CsCr7GShp@Q zGJ?4|5@Vm;?2z>^{;RvLtaSJ(Dr!A|$nw^gmzRI@o9iCf=fXzOeF9&36gS+U|NboY z|DCx8Qb6s-8@pK{Le3MgLKQ4%X#s$~KJ~HHeCnT@2*i8|%tv(kC+O+vUCP4P@+tfH z<8`<1Qgz7q!Xb>0;|EV6Le_MPLj-g5q9z`o3Wkaji`pWf5TK(200su=W(A81j1S66 z3@|M0vb!Q#96mg-jFGWrD%7Ko*6-N`1wbI+g+pj-!)N{h_7ap704b>mZ2l<}n3%$u zGZ-5~KCh7o)zqN5nUZy2L0cOD3=fCX6e9L0%$Bo2;EtjUO-)V1!^10f;8UM!y5|nN z$)xzvPw|nDptS~StXCznKxArdPVw67_~kFr+dDfsIk|`|5K(z~`TF&#L;?WD#&UwP zpvD0%aa9xoVj;14kNf|r^trE9E>*LOqtNc%t<QWL#zZKNpTzbpC{>WFwSF~Z#c+lW z9@Osc$xG)2$z<}We`|C(1GD9x*hmZT$4B8lJoBBtMKyTI6G){}2M!RCsse<wS=_J% zB?kBnUr-ZN#G>DQ7O%c~es*?tMFlaJ%gGE$5^9rPeNPxJ`&}xtfID#8ZCyu>^j;DQ zJ@inrKA}*<4yd`(S`UB-q#%HldIt2q&(g~;pINE(W{viP6`t5M@HgI}kU>?O`Xbn{ zA9Zzg7k6OWw$}ST>KG*%fOKf%%9s*f@76DUX|lh6aMfI}zaL^sti@BZWkJbvh-`Di zxS{m1f4rCj(P;DwUkJbv3R0-rL{TLZMXw&AC!QF)OeQ=yXn{zA(0BObeibp{M6Beg z%0{#q6kE!H9Xqbsz0Kt{Irs#W02lnnd+5n0&(F=xT_%qo88P+FLXe1sAofGZ<bw+* z<LB;s<I6d4|NXE*1HZs7z^O?O2M)}yF6bAn@$pH9va{H<K9X^#Az=7~$|qNlYtYcp zP~3s_>(}4D8z3bR5r_h;GzTHTx4wnZ(a|+&1+&?#2#FXJf(VYjfP?=$W(@_2sEr?U zCb0jx<wMoQ9r)k}BWC~A0H_Adp+W_C^ElpmYiO-{*?d0FS&KiOAbSGc-F;J2Q@?$Q z77*zGnoNL^+(eN`WU&L0NaT(?)Ye@;{t4uOpOt?2Ln>NIR=uYCED;jL^Ut3(7mpqt zVAp?IW?}fLSeOz;i=l*J2U4lj&J6}9ZEvXV1XLkHM}MQIPY+^ES2}GXn||~!;^$SN zP<Z!HSOic}|EI}px^8>vVh1*CD7Dtx#8tQ)U<E@DA118z8Xi^=`t8d|r_<r<Z@)b% zFr>(~3O0!)!T^i%`!C3W>#w(V8)omS7ugac^t<0pT>%I3={NMvH`9wlYkFGFIlD#u zLg7G`I7YEpY=HxtHd(OO5XUpo>8ZZ+KUk_Ex;zJl4;@M~bCD`>%rOfMS#J+SMNw5% z6*v%yMB3ZoXRzsfO_y!R`tN^#MN~o6B{h}aUe8KN@Ut1NP7^ED*473NBoc{+1{eMy za^R)zp1!`Tt$2=)k2`Kh0j;oUO{}P?i3M~z9*<YVNDbE^wSOdji-d`ZtL?zt+?>-S z9j)*gtAL@X4D|!iXf)<1o9py^o(Klkf;y~hF|$noG0m}UtOLrF2suDR1~gr|xZ5m# z=^BdIEAYW?-vVhvU{hHr<bdaS;;T9e6{8NgOb{dzSKInXB;v5&@S+gkHg4oYb)Zlv zWW}{}3eQE311~Dp30>KhNF-QQB#2}Y5>-*PT39yZ!2JCD`Sb9ZtpqHbSd;~AZC5*l zYHDhNBzAn8m4eKi)W88|K63_v{3Kw3CkBQ|6kE6IGJ}~b;Xr$PnP0;EX28Is0oF_= zv!D|H@sCa#a1E&6WH8Xa85I>3MI?<_Y|oyK%F4<$ccA3`v|#&9=KvptXliO|fdeN` zhKqKP!M;MaX;bRL$L!hD`q9s#zP^6V6F};N0_=(UI;qc6=jZ1aIPj-Gd9Fr;%7<eU zth8_6;>UD$cJBQ&SkcfBSz8CTZEH7Xc!o-XSl}r{)HFJhzJQI6j*gx?PabT9u{be9 zED`V6zMzdLD=T~W8#X#yTi0}KN)*4#vQA$b3Q<w8fPce_9bo34{Y=G2&u|mu^5KC8 zO8na%e6Z0=*i$ls^IEO#+c%2O280CAK-{*|nsWmKMS9|2`~o6@Fy@*d^5M1XCfc&4 z6Tq#vcDCN^r#q^;*3A0S($eI|$><UOZhETXlrK?|^T_A(MI7kwANuo|5N8S$8-HM- zpZ_{GZ|>apIf#G6N?eY3JiaClyzkyNR`ui7w(}NwlueQS`D}4jLPTDC5o~UdU@mRN z86i)Jqj>Ne&OJK<gJ^M(UFo`c_a^QN7{3G>Be9aHOQIMZ99&Y^I)3~t&k%>2AT?tW zJ3kE2DVSXYEL2}#bD7p}*>bJyH7XE!ehiBpG>Jd~0r5|k)kf#%=fD4b6;;m#lFzQ$ z4y}R_q5}#N)#m2Qs>eHaTw8vx8mbfCpa6vcPr-uor%qo)oj!VW=zQA7k2vjH{E36O zS(p{RO=!{ulIsds=kCAXRC<q7xco7pfCEYo5mEuaGJSD*otdA0+DUn4-Y9+}rwk3p zm32u`*SQ+&8yg#UJ-(4|A~TZ>?Uc{w{R2@Rq=}&-x?uFeOOun6G+)!T)l$EpI5;fx zOsk5}YbcfU_G>HXJ5#CD4fn0D*_#wqaY)S}_Ga-d0CAf7k9UhI0L6!Vuf29=>(;i0 zZ2_+iPp?G5P!@m6OQM=gCg<kns;a7HXJ-qALeUaiU0r?cwd+c6S58EHWMs<`$j#-I zgAsvk1Ng=9qTjis1I+yN(_;s|+rSkISz(Z22)pD7s;a8y=H~8ttbyZ@EM$PZ3C+(F zMZwkJW^lE`05RH*`ziixT+M*Y@PJ^a-k`~)-^Yn8BY*$v6L~xO6t(?CFoLJBULcBw zhDueH2#JD|#G6%aCi)QM7RYswYEpj?@9R?%Mme>)i*Wsc{F)|vPAvxm%Y1grEeW>` zMwU^(gh>cqjdo<19`{*Ili9C{3p)~oG!nRf<|*0Gkk9z`Hf4^Tx(JRf&1pM#d`#_t zMBv%n4Gdb48$zje0GLV#s1+_6q1PqIsZ<u?Bu8?LSc#MBIbdKw-a@AP)J5^2cn;Lo z)_(G9cFxRxmn<R0F3_0VuTAzHg3d5@0fJy^6woI?X2C}>cQzlpH7>gx#JPLrKXaLZ zflC3jA`V2O(MKMsaj(7j)mJ%q0Ewu87?2#e4-*48d9nbYukUQzpPOVI80Iw(f5bwf z%6~xN6b%fV%jI&-&CT&U<I#$^eObtVH?W{{&!5R=vzOXGTzF~!{;r*O1w_sBX-@&t zkKuj{4dLwBLMD@0^yXMJ8Z9j?ou8jKubh>Xl$d$H=XsvzMIw>v>gu+(b#fDAohv5p zBt4TGM=*Zk4=b7jEk1$z`ud%>Dl51b{rwmm#K;JZk7u&kY?y@`7SPz(*w|R!)I{a& zDxJiUKt^VPOcD#2z?H7M4dsjgAwElTQr|n0Ud8m5E)*K#@pvwmyXZE=<MBK1Y>WS` z1xHWAIyiB-P)MMTgkFe%XK?esk@@vNE|*(n3woLTYi(`q&YkrYw?PvAHrv;)TtjDT zwr8@)RWUCOIW{{yG_=%+;A%J!Udd##si~>6vqU?<Eszp;KG86mLIykl?#H>Ivr|)3 lYdi3~QtJxocK@%|{{jQo>&O_f6`244002ovPDHLkV1g)$@P+^Y literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/talents/corruptions/vile-life.lua b/game/modules/tome/data/talents/corruptions/vile-life.lua index c4ac2f25c5..7064b72107 100644 --- a/game/modules/tome/data/talents/corruptions/vile-life.lua +++ b/game/modules/tome/data/talents/corruptions/vile-life.lua @@ -59,34 +59,63 @@ newTalent{ points = 5, cooldown = 20, vim = 30, - range = 10, - radius = 2, - tactical = { DISABLE = 2 }, - direct_hit = true, - requires_target = true, - target = function(self, t) - return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + mode = "sustained", + tactical = { BUFF = 2 }, + getFire = function(self, t) return self:combatTalentSpellDamage(t, 10, 400) end, + getCold = function(self, t) return self:combatTalentSpellDamage(t, 10, 500) end, + getLightning = function(self, t) return math.floor(self:combatTalentLimit(t, 8, 3, 5)) end, + getAcid = function(self, t) return math.floor(self:combatTalentLimit(t, 8, 2, 5)) end, + getNature = function(self, t) return self:combatTalentLimit(t, 60, 15, 45) end, + callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp, no_martyr) + local p = self:isTalentActive(t.id) + if not p then return end + if not src.setEffect then return end + if not p.last_turn[type] or game.turn - p.last_turn[type] < 100 then return end + + if type == DamageType.FIRE then + src:setEffect(src.EFF_BURNING, 5, {src=self, apply_power=self:combatSpellpower(), power=t.getFire(self, t) / 5}) + elseif type == DamageType.COLD then + src:setEffect(src.EFF_FROZEN, 3, {apply_power=self:combatSpellpower(), hp=t.getCold(self, t)}) + elseif type == DamageType.ACID then + src:setEffect(src.EFF_BLINDED, t.getAcid(self, t), {apply_power=self:combatSpellpower(), hp=t.getCold(self, t)}) + elseif type == DamageType.LIGHTNING then + src:setEffect(src.EFF_DAZED, t.getLightning(self, t), {apply_power=self:combatSpellpower()}) + elseif type == DamageType.NATURE then + src:setEffect(src.EFF_SLOW, 4, {apply_power=self:combatSpellpower(), power=t.getNature(self, t) / 100}) + end + p.last_turn[type] = game.turn end, - getCDincrease = function(self, t) return self:combatTalentScale(t, 0.15, 0.5) end, - action = function(self, t) - local tg = self:getTalentTarget(t) - 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 or target == self then return end - target:setEffect(target.EFF_BURNING_HEX, 20, {src=self, dam=self:spellCrit(self:combatTalentSpellDamage(t, 4, 90)), power=1 + t.getCDincrease(self, t), apply_power=self:combatSpellpower()}) - end) - local _ _, _, _, x, y = self:canProject(tg, x, y) - game.level.map:particleEmitter(x, y, tg.radius, "circle", {oversize=0.7, g=100, b=100, a=90, limit_life=8, appear=8, speed=2, img="blight_circle", radius=self:getTalentRadius(t)}) + activate = function(self, t) game:playSoundNear(self, "talents/slime") + return { + last_turn = { + [DamageType.FIRE] = game.turn - 100, + [DamageType.COLD] = game.turn - 100, + [DamageType.ACID] = game.turn - 100, + [DamageType.LIGHTNING] = game.turn - 100, + [DamageType.NATURE] = game.turn - 100, + }, + } + end, + deactivate = function(self, t, p) return true end, info = function(self, t) - return ([[Hexes your target and everything within a radius 2 ball around it for 20 turns. Each time an affected target uses a resource (stamina, mana, vim, ...), it takes %0.2f fire damage. - In addition, the cooldown of any talent used while so hexed is increased by %d%% + 1 turn. + return ([[Use elemental damage deal to you to trigger terrible effects on the source: + - Fire: burn for %0.2f fire damage over 5 turns + - Cold: freeze for 3 turns with %d iceblock power + - Acid: blind for %d turns + - Lightning: daze for %d turns + - Nature: %d%% slow for 4 turns + This effect can only happen once every 10 turns per damage type. The damage will increase with your Spellpower.]]): - format(damDesc(self, DamageType.FIRE, self:combatTalentSpellDamage(t, 4, 90)), t.getCDincrease(self, t)*100) + format( + damDesc(self, DamageType.FIRE, t.getFire(self, t)), + t.getCold(self, t), + t.getAcid(self, t), + t.getLightning(self, t), + t.getNature(self, t) + ) end, } @@ -95,17 +124,14 @@ newTalent{ type = {"corruption/vile-life", 3}, require = corrs_req3, points = 5, - cooldown = 20, - vim = 30, - range = 10, - radius = 2, + cooldown = 15, + vim = 16, + range = 5, tactical = { DISABLE = 2 }, direct_hit = true, requires_target = true, - target = function(self, t) - return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t} - end, - recoil = function(self,t) return self:combatLimit(self:combatTalentSpellDamage(t, 4, 20), 100, 0, 0, 12.1, 12.1) end, -- Limit to <100% + target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end, + getPower = function(self,t) return self:combatLimit(self:combatTalentSpellDamage(t, 4, 100), 100, 0, 0, 18.1, 18.1) end, -- Limit to <100% action = function(self, t) local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) @@ -113,16 +139,15 @@ newTalent{ self:project(tg, x, y, function(tx, ty) local target = game.level.map(tx, ty, Map.ACTOR) if not target or target == self then return end - target:setEffect(target.EFF_EMPATHIC_HEX, 20, {power=t.recoil(self,t), apply_power=self:combatSpellpower()}) + target:setEffect(target.EFF_HEALING_INVERSION, 5, {apply_power=self:combatSpellpower(), power=t.getPower(self, t)}) end) - local _ _, _, _, x, y = self:canProject(tg, x, y) - game.level.map:particleEmitter(x, y, tg.radius, "circle", {oversize=0.7, r=100, b=100, a=90, limit_life=8, appear=8, speed=2, img="blight_circle", radius=self:getTalentRadius(t)}) game:playSoundNear(self, "talents/slime") return true end, info = function(self, t) - return ([[Hexes your target and everything within a radius 2 ball around it. Each time they do damage, they take %d%% of the same damage for 20 turns. - The damage will increase with your Spellpower.]]):format(t.recoil(self,t)) + return ([[You manipulate the vim of your target to temporarily invert all healing done to it (but not regeneration). + For 5 turns all healing will instead damage them for %d%% of the healing done as blight. + The effect will increase with your Spellpower.]]):format(t.getPower(self,t)) end, } @@ -131,16 +156,14 @@ newTalent{ type = {"corruption/vile-life", 4}, require = corrs_req4, points = 5, - cooldown = 20, - vim = 30, - range = 10, - no_npc_use = true, + cooldown = 10, + vim = 18, direct_hit = true, requires_target = true, - target = function(self, t) - return {type="hit", range=self:getTalentRange(t), talent=t} - end, - getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end, + range = 1, + target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end, + getNb = function(self, t) return math.floor(self:combatTalentScale(t, 2, 9)) end, + getDam = function(self, t) return 4 end, action = function(self, t) local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) @@ -148,8 +171,32 @@ newTalent{ self:project(tg, x, y, function(tx, ty) local target = game.level.map(tx, ty, Map.ACTOR) if not target or target == self then return end - if target:canBe("instakill") then - target:setEffect(target.EFF_DOMINATION_HEX, t.getDuration(self, t), {src=self, apply_power=self:combatSpellpower(), faction = self.faction}) + + local list = {} + local nb = t.getNb(self, t) + for eff_id, p in pairs(self.tmp) do + local e = self.tempeffect_def[eff_id] + if (e.type == "physical" or e.type == "magical") and e.status == "detrimental" then + list[#list+1] = eff_id + end + end + + local dam = t.getDam(self, t) * self.life / 100 + while #list > 0 and nb > 0 do + if self:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 5) then + local eff_id = rng.tableRemove(list) + local p = self.tmp[eff_id] + local e = self.tempeffect_def[eff_id] + local effectParam = self:copyEffect(eff_id) + effectParam.src = self + + target:setEffect(eff_id, p.dur, effectParam) + self:removeEffect(eff_id) + local dead, val = self:takeHit(dam, self, {source_talent=t}) + target:heal(val, self) + game.logPlayer(self, "#CRIMSON#%s transfers an effect (%s) to %s!", self.name:capitalize(), e.desc, target.name) + end + nb = nb - 1 end end) local _ _, _, _, x, y = self:canProject(tg, x, y) @@ -158,7 +205,8 @@ newTalent{ return true end, info = function(self, t) - return ([[Hexes your target, forcing it to be your thrall for %d turns. - If you damage the target, it will be freed from the hex.]]):format(t.getDuration(self, t)) + return ([[You touch a nearby creature to transfer up to %d physical or magical detrimental effects currently affecting you. + The transfer takes %d%% of your remaining life and heals the target for the same value.]]): + format(t.getNb(self, t), t.getDam(self, t)) end, } diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua index 4d7ac4e8d5..3131703aac 100644 --- a/game/modules/tome/data/timed_effects/magical.lua +++ b/game/modules/tome/data/timed_effects/magical.lua @@ -2636,7 +2636,7 @@ newEffect{ name = "ILLUMINATION", desc = "Illumination ", image = "talents/illumination.png", long_desc = function(self, eff) return ("The target glows in the light, reducing its stealth and invisibility power by %d, defense by %d and looses all evasion bonus from being unseen."):format(eff.power, eff.def) end, - type = "physical", + type = "magical", subtype = { sun=true }, status = "detrimental", parameters = { power=20, def=20 }, @@ -2654,7 +2654,7 @@ newEffect{ name = "LIGHT_BURST", desc = "Light Burst ", image = "talents/light_burst.png", long_desc = function(self, eff) return ("The is invigorated when dealing damage with Searing Sight."):format() end, - type = "physical", + type = "magical", subtype = { sun=true }, status = "beneficial", parameters = { max=1 }, @@ -2664,9 +2664,9 @@ newEffect{ newEffect{ name = "LIGHT_BURST_SPEED", - desc = "Light Burst Speed ", image = "effects/light_burst_speed.png", - long_desc = function(self, eff) return ("The is invigorated from Searing Sight, increasing movement speed by %d%%."):format(eff.charges * 10) end, - type = "physical", + desc = "Light Burst Speed", image = "effects/light_burst_speed.png", + long_desc = function(self, eff) return ("The target is invigorated from Searing Sight, increasing movement speed by %d%%."):format(eff.charges * 10) end, + type = "magical", subtype = { sun=true }, status = "beneficial", parameters = {}, @@ -2690,3 +2690,26 @@ newEffect{ self:removeTemporaryValue("movement_speed", eff.tmpid) end, } + +newEffect{ + name = "HEALING_INVERSION", + desc = "Healing Inversion", image = "talents/healing_inversion.png", + long_desc = function(self, eff) return ("All healing done to the target will instead turn into %d%% blight damage."):format(eff.power) end, + type = "magical", + subtype = { heal=true }, + status = "detrimental", + parameters = { power=10 }, + on_gain = function(self, err) return nil, "+Healing Inversion" end, + on_lose = function(self, err) return nil, "-Healing Inversion" end, + callbackOnHeal = function(self, eff, value, src) + local dam = value * eff.power / 100 + DamageType:get(DamageType.BLIGHT).projector(eff.src or self, self.x, self.y, DamageType.BLIGHT, dam) + return {value=0} + end, + activate = function(self, eff) + eff.particle = self:addParticles(Particles.new("circle", 1, {oversize=0.7, a=90, appear=8, speed=-2, img="necromantic_circle", radius=0})) + end, + deactivate = function(self, eff) + self:removeParticles(eff.particle) + end, +} diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua index e0df7d189c..fcff508d5c 100644 --- a/game/modules/tome/data/timed_effects/physical.lua +++ b/game/modules/tome/data/timed_effects/physical.lua @@ -513,7 +513,7 @@ newEffect{ newEffect{ name = "SLOW", image = "talents/slow.png", desc = "Slow", - long_desc = function(self, eff) return ("Reduces global action speed by %d%%."):format( eff.power * 100) end, + long_desc = function(self, eff) return ("Reduces global action speed by %d%%."):format(eff.power * 100) end, type = "physical", subtype = { slow=true }, status = "detrimental", diff --git a/game/modules/tome/data/zones/mark-spellblaze/grids.lua b/game/modules/tome/data/zones/mark-spellblaze/grids.lua index 7268f5fc1f..29a577b817 100644 --- a/game/modules/tome/data/zones/mark-spellblaze/grids.lua +++ b/game/modules/tome/data/zones/mark-spellblaze/grids.lua @@ -35,8 +35,8 @@ newEntity{ base = "ALTAR", who:removeObject(inven, item, true) local o = game.zone:makeEntityByName(game.level, "object", "CORRUPTED_SANDQUEEN_HEART", true) o:identify(true) - who:addObject(inven, o) - who:sortInven(inven) + who:addObject(who.INVEN_INVEN, o) + who:sortInven(who.INVEN_INVEN) game.log("#GREEN#You put the heart on the altar. The heart shrivels and shakes, vibrating with new corrupt forces.") end, "Cancel", "Corrupt", nil, true) end, diff --git a/game/modules/tome/data/zones/sandworm-lair/objects.lua b/game/modules/tome/data/zones/sandworm-lair/objects.lua index 05877ad722..687bd22c78 100644 --- a/game/modules/tome/data/zones/sandworm-lair/objects.lua +++ b/game/modules/tome/data/zones/sandworm-lair/objects.lua @@ -35,7 +35,8 @@ newEntity{ type = "corpse", subtype = "heart", image = "object/artifact/queen_heart.png", name = "Heart of the Sandworm Queen", unique=true, unided_name="pulsing organ", display = "*", color=colors.VIOLET, - desc = [[The heart of the Sandworm Queen, ripped from her dead body. You could ... consume it, should you feel mad enough.]], + desc = [[The heart of the Sandworm Queen, ripped from her dead body. +You could ... consume it, should you feel mad enough or you could try to corrupt it somewhere.]], cost = 3000, quest = 1, diff --git a/src/core_lua.c b/src/core_lua.c index b5047a9e43..08fbbdc04a 100644 --- a/src/core_lua.c +++ b/src/core_lua.c @@ -429,7 +429,7 @@ static int lua_key_get_clipboard(lua_State *L) if (str) { lua_pushstring(L, str); - free(str); + SDL_free(str); } else lua_pushnil(L); @@ -786,7 +786,7 @@ static int sdl_surface_drawstring_newsurface_aa(lua_State *L) return 1; } -static font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_separator, int id_real_line, char *line_data, int line_data_size, bool direct_uid_draw, int realsize) +static void font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_separator, int id_real_line, char *line_data, int line_data_size, bool direct_uid_draw, int realsize) { lua_createtable(L, 0, 9); @@ -1018,7 +1018,7 @@ static int sdl_font_draw(lua_State *L) } } // Extra data - else if ((*(next+1) == '&')) { + else if (*(next+1) == '&') { line_data = next + 2; line_data_size = codestop - (next+2); } diff --git a/src/map.c b/src/map.c index 5202556784..432c6e3db5 100644 --- a/src/map.c +++ b/src/map.c @@ -57,6 +57,7 @@ static int lua_is_hex(lua_State *L) lua_settable(L, LUA_REGISTRYINDEX); lua_pushnumber(L, 0); } + return 1; } static int map_object_new(lua_State *L) diff --git a/src/music.c b/src/music.c index e8b137fc17..4f3a60d33c 100644 --- a/src/music.c +++ b/src/music.c @@ -76,7 +76,7 @@ void openal_get_devices() char *defaultDevice=NULL; char *deviceList=NULL; - if (alcIsExtensionPresent(NULL, (ALubyte*)"ALC_ENUMERATION_EXT") == AL_TRUE) + if (alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE) { // try out enumeration extension deviceList = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER); diff --git a/src/web.c b/src/web.c index 6dcef3f459..21cf4d183a 100644 --- a/src/web.c +++ b/src/web.c @@ -369,6 +369,8 @@ static void handle_event(WebEvent *event) { lua_pop(he_L, 1); } break; + case TE4_WEB_EVENT_DELETE_TEXTURE: + break; } } -- GitLab