Skip to content
Snippets Groups Projects
Commit 29e06b08 authored by DarkGod's avatar DarkGod
Browse files

welcome to Suslik in the credits

Added a graphical effect for healing and regen effects to most of those effects
parent 3b834812
No related branches found
No related tags found
No related merge requests found
Showing
with 226 additions and 21 deletions
......@@ -28,6 +28,7 @@ Lore:
Graphics:
- Shockbolt (Raymond Gaustadnes) http://shockbolt.deviantart.com
- Rexorcorum (Assen Kanev)
- Suslik (Alex Sannikov) for his awesome shaders
Musics:
- "A lomos del dragón blanco" by Carlos Saura (http://www.jamendo.com/en/artist/carlosaura)
......
......@@ -191,6 +191,7 @@ end
--- Removes a particles emitter following the entity
function _M:removeParticles(ps)
if not ps then return end
self.__particles[ps] = nil
ps:dieDisplay()
if self.x and self.y and game.level and game.level.map then
......
......@@ -21,6 +21,7 @@ require "engine.class"
require "engine.Mouse"
require "engine.DebugConsole"
require "engine.dialogs.ShowErrorStack"
local Shader = require "engine.Shader"
--- Represent a game
-- A module should subclass it and initialize anything it needs to play inside
......@@ -240,6 +241,8 @@ function _M:tick()
end
end
Shader:cleanup()
if self.cleanSounds then self:cleanSounds() end
self:onTickEndExecute()
......
......@@ -34,6 +34,15 @@ function core.shader.allow(kind)
return config.settings['shaders_kind_'..kind] and core.shader.active(4)
end
function _M:cleanup()
local time = os.time()
local todel = {}
for name, s in pairs(self.progs) do
if s.dieat < time then todel[name] = true end
end
for name, _ in pairs(todel) do self.progs[name] = nil end
end
--- Make a shader
function _M:init(name, args)
self.args = args or {}
......@@ -65,11 +74,14 @@ function _M:init(name, args)
end
end
function _M:makeTotalName()
function _M:makeTotalName(add)
local str = {}
for k, v in pairs(self.args) do
local args = self.args
if add then args = table.clone(add) table.merge(args, self.args) end
for k, v in pairs(args) do
if type(v) == "function" then v = v(self) end
if type(v) == "number" then
str[#str+1] = v
str[#str+1] = k.."="..tostring(v)
elseif type(v) == "table" then
if v.texture then
if v.is3d then str[#str+1] = k.."=tex3d("..v.texture..")"
......@@ -83,6 +95,7 @@ function _M:makeTotalName()
end
end
end
table.sort(str)
return self.name.."["..table.concat(str,",").."]"
end
......@@ -135,12 +148,12 @@ function _M:createProgram(def)
end
function _M:loaded()
if _M.progs[self.totalname] then
self.shad = _M.progs[self.totalname]
if _M.progs[self.totalname] and not _M.progsreset[self.totalname] then
-- print("[SHADER] using cached shader "..self.totalname)
self.shad = _M.progs[self.totalname]
self.shad = _M.progs[self.totalname].shad
_M.progs[self.totalname].dieat = os.time() + 120
else
print("[SHADER] Loading from /data/gfx/shaders/"..self.name..".lua")
-- print("[SHADER] Loading from /data/gfx/shaders/"..self.name..".lua")
local f, err = loadfile("/data/gfx/shaders/"..self.name..".lua")
if not f and err then error(err) end
setfenv(f, setmetatable(self.args or {}, {__index=_G}))
......@@ -153,10 +166,19 @@ function _M:loaded()
if not core.shader.allow(def.require_kind) then return end
end
_M.progs[self.totalname] = self:createProgram(def)
_M.progsreset[self.totalname] = def.resetargs
if def.resetargs then
self.totalname = self:makeTotalName(def.resetargs)
end
-- print("[SHADER] Loaded shader with totalname", self.totalname)
if not _M.progs[self.totalname] then
_M.progs[self.totalname] = {shad=self:createProgram(def), dieat=def.resetargs and (os.time() + 3) or (os.time() + 120)}
_M.progsreset[self.totalname] = def.resetargs
else
_M.progs[self.totalname].dieat = def.resetargs and (os.time() + 3) or (os.time() + 120)
end
self.shad = _M.progs[self.totalname]
self.shad = _M.progs[self.totalname].shad
if self.shad then
for k, v in pairs(def.args) do
self:setUniform(k, v)
......
......@@ -734,6 +734,8 @@ function core.display.virtualImage(path, data)
virtualimages[path] = data
end
if not core.game.getFrameTime then core.game.getFrameTime = core.game.getTime end
local oldloadimage = core.display.loadImage
function core.display.loadImage(path)
if virtualimages[path] then return core.display.loadImageMemory(virtualimages[path]) end
......
......@@ -1243,11 +1243,8 @@ end
-- Note: There can be up to a 1 tick delay in displaying log information
function _M:displayDelayedLogDamage()
if not self.uiset or not self.uiset.logdisplay then return end
local newmessage = false --debugging
for src, tgts in pairs(self.delayed_log_damage) do
newmessage = true -- debugging
for target, dams in pairs(tgts) do
local healmsg
if #dams.descs > 1 then
game.uiset.logdisplay(self:logMessage(src, dams.srcSeen, target, dams.tgtSeen, "#Source# hits #Target# for %s (%0.0f total damage)%s.", table.concat(dams.descs, ", "), dams.total, dams.healing<0 and (" #LIGHT_GREEN#[%0.0f healing]#LAST#"):format(-dams.healing) or ""))
else
......@@ -1268,7 +1265,7 @@ newmessage = true -- debugging
self.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, rng.float(-2.5, -1.5), ("Kill (%d)!"):format(dams.total), {255,0,255}, true)
self:delayedLogMessage(target, nil, "death", self:logMessage(src, dams.srcSeen, target, dams.tgtSeen, "#{bold}##Source# killed #Target#!#{normal}#"))
end
else
elseif dams.total > 0 or dams.healing == 0 then
if dams.tgtSeen and (rsrc == self.player or self.party:hasMember(rsrc)) then
self.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, rng.float(-3, -2), tostring(-math.ceil(dams.total)), {0,255,dams.is_crit and 200 or 0}, dams.is_crit)
elseif dams.tgtSeen and (rtarget == self.player or self.party:hasMember(rtarget)) then
......
......@@ -40,7 +40,7 @@ return {
r = 1, rv = 0, ra = 0,
g = 1, gv = 0, ga = 0,
b = 1, bv = 0, ba = 0,
a = 1, av = 0, aa = 0,
a = a or 1, av = 0, aa = 0,
}
end, },
function(self)
......
......@@ -28,7 +28,7 @@ local first = false
return { generator = function()
return {
trail = 0,
life = 15,
life = life or 15,
size = 2*38 * (size_factor or 1), sizev = sizev or 0, sizea = sizea or 0,
x = (x or 0) * 64, xv = 0, xa = 0,
......@@ -39,7 +39,7 @@ return { generator = function()
r = r, rv = 0, ra = 0,
g = g, gv = 0, ga = 0,
b = b, bv = 0, ba = 0,
a = a, av = -0.04, aa = 0.005,
a = a, av = -0.2 / life, aa = -0.002,
}
end, },
function(self)
......
game/modules/tome/data/gfx/particles_images/healarcane.png

17.8 KiB

game/modules/tome/data/gfx/particles_images/healcelestial.png

16.9 KiB

game/modules/tome/data/gfx/particles_images/healdark.png

20.1 KiB

game/modules/tome/data/gfx/particles_images/healgreen.png

19.6 KiB

game/modules/tome/data/gfx/particles_images/healparadox.png

18.2 KiB

......@@ -27,7 +27,6 @@ return {
oscillationSpeed = oscillationSpeed or 1.0, --oscillation between ellipsoidal and spherical form
},
resetargs = {
tick_start = function() return core.game.getTime() end,
tick_start = function() return core.game.getFrameTime() end,
},
clone = false,
}
......@@ -29,7 +29,7 @@ return {
flap = flap or 0.0,
},
resetargs = {
tick_start = function() return core.game.getTime() end,
tick_start = function() return core.game.getFrameTime() end,
},
clone = false,
}
uniform sampler2D tex;
uniform float tick;
uniform float tick_start;
uniform float time_factor;
uniform float noup;
uniform float circleRotationSpeed;
uniform float circleDescendSpeed;
uniform float beamsCount;
uniform vec4 beamColor1;
uniform vec4 beamColor2;
uniform vec4 circleColor;
vec2 Rotate(vec2 point, float ang)
{
return vec2(
point.x * cos(ang) - point.y * sin(ang),
point.x * sin(ang) + point.y * cos(ang));
}
vec4 Uberblend(vec4 col0, vec4 col1)
{
// return vec4((1.0 - col0.a) * (col1.rgb) + col0.a * (col1.rgb * col1.a + col0.rgb * (1.0 - col1.a)), min(1.0, col0.a + col1.a));
// return vec4((1.0 - col1.a) * (col0.rgb) + col1.a * (col1.rgb * col1.a + col0.rgb * (1.0 - col1.a)), min(1.0, col0.a + col1.a));
return vec4(
(1.0 - col0.a) * (1.0 - col1.a) * (col0.rgb * col0.a + col1.rgb * col1.a) / (col0.a + col1.a + 1e-1) +
(1.0 - col0.a) * (0.0 + col1.a) * (col1.rgb) +
(0.0 + col0.a) * (1.0 - col1.a) * (col0.rgb * (1.0 - col1.a) + col1.rgb * col1.a) +
(0.0 + col0.a) * (0.0 + col1.a) * (col1.rgb),
min(1.0, col0.a + col1.a));
}
void main(void)
{
float baseRadius = 0.35;
float beamWidth = 0.025;
float beamHeight = 1.0;
float beamDescend = 0.5;
float scaledTime = 25.0 * tick / time_factor;
float firstBeamNum = floor(scaledTime);
float verticalAngle = 0.2;
vec2 spritePoint = (gl_TexCoord[0].xy - vec2(0.5, 1.0)).xy * vec2(1.0, -1.0);
float topCirclePos = 1.0 - verticalAngle * baseRadius;
float bottomCirclePos = verticalAngle * baseRadius;
float posScale = 0.0;
if(circleDescendSpeed > 0.0)
posScale = clamp(1.0 - (tick - tick_start) / time_factor * circleDescendSpeed, 0.0, 1.0);
vec3 planePoint = vec3(0.0, topCirclePos * posScale + bottomCirclePos * (1.0 - posScale), 0.0);
vec2 planarPoint = vec2(spritePoint.x, (spritePoint.y - planePoint.y) / verticalAngle);
vec4 resultColor = vec4(0.0, 0.0, 0.0, 0.0);
float circleIntersection = (spritePoint.y - planePoint.y) / verticalAngle;
vec4 circleColorSample = vec4(0.0, 0.0, 0.0, 0.0);
if(!((noup == 1.0 && planarPoint.y > 0.0) || (noup == 2.0 && planarPoint.y < 0.0)))
{
if(length(planarPoint) < 0.5)
{
planarPoint = Rotate(planarPoint, scaledTime * 0.1 * circleRotationSpeed);
circleColorSample = texture2D(tex, planarPoint + vec2(0.5, 0.5)) * circleColor;
circleColorSample.a *= (1.0 - posScale);
//resultColor.rgb *= resultColor.a;
//resultColor.rgb = circleColor.rgb;
}
}
vec4 beamFrontColor = vec4(0.0, 0.0, 0.0, 0.0);
vec4 beamRearColor = vec4(0.0, 0.0, 0.0, 0.0);
float beamTime;
int i;
int ibeamsCount = (int)beamsCount;
for(i = 0; i < ibeamsCount; i++)
{
float beamIndex = floor(scaledTime) - float(i);
float beamPhase = (scaledTime - beamIndex) / float(ibeamsCount);
float beamVerticalOffset = 0.02;
float heightPhase = 1.0 - pow(1.0 - beamPhase, 3.0);
float height = beamHeight * (1.0 - heightPhase) * (1.0 - 2.0 * verticalAngle * baseRadius - beamVerticalOffset) + heightPhase * 0.1;
float beamColorScale = sin(beamIndex * 20.0) * 0.5 + 0.5;
float beamAng = (sin(beamIndex * 10.0) + sin(beamIndex * 7.0)) * 3.14159265;
if((sin(beamAng) > 0.0) && noup == 1.0) continue;
if((sin(beamAng) <= 0.0) && noup == 2.0) continue;
vec3 beamBase = vec3(cos(beamAng), (sin(beamAng) + 1.0) * verticalAngle, sin(beamAng)) * baseRadius * beamPhase +
vec3(0.0, height * 0.5 + beamVerticalOffset, 0.0);
float zMult = (1.0 - (sin(beamAng) + 1.0) / 2.0) * 0.5 + 0.5;
vec2 screenDelta = spritePoint - beamBase.xy;
vec4 beamColor = vec4(zMult, zMult, zMult, 1.0) * (beamColor1 * beamColorScale + beamColor2 * (1.0 - beamColorScale));
float verticalScale = clamp(screenDelta.y / height + 0.5, 0.0, 1.0);
beamColor.a *=
(1.0 - pow(clamp(2.0 * abs(screenDelta.x / beamWidth ), 0.0, 1.0), 2.0)) *
(1.0 - pow(1.0 - verticalScale, 4.0)) * (1.0 - pow(verticalScale, 1.0)) *
(1.0 - pow((1.0 - beamPhase), 8.0)) * (1.0 - pow(beamPhase, 2.0)) * 4.0;
beamColor.rgb *= beamColor.a;
if(beamBase.z > circleIntersection)
beamRearColor += beamColor;
else
beamFrontColor += beamColor;
}
beamRearColor.rgb /= (beamRearColor.a + 1e-5);
beamFrontColor.rgb /= (beamFrontColor.a + 1e-5);
//if(beamColorSample.a > 1.0) beamColorSample /= beamColorSample.a;
beamRearColor.r = clamp(beamRearColor.r, 0.0, 0.99);
beamRearColor.g = clamp(beamRearColor.g, 0.0, 0.99);
beamRearColor.b = clamp(beamRearColor.b, 0.0, 0.99);
beamRearColor.a = clamp(beamRearColor.a, 0.0, 0.99);
beamFrontColor.r = clamp(beamFrontColor.r, 0.0, 0.99);
beamFrontColor.g = clamp(beamFrontColor.g, 0.0, 0.99);
beamFrontColor.b = clamp(beamFrontColor.b, 0.0, 0.99);
beamFrontColor.a = clamp(beamFrontColor.a, 0.0, 0.99);
resultColor = Uberblend(Uberblend(beamRearColor, circleColorSample), beamFrontColor);
resultColor.a *= gl_Color.a;
gl_FragColor = resultColor;
}
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
return {
frag = "healing",
vert = nil,
args = {
tex = { texture = 0 },
time_factor = time_factor or 1000,
beamColor1 = beamColor1 or {0x50/255, 0x9e/255, 0x01/255, 1.0},
beamColor2 = beamColor2 or {0xa7/255, 0xe8/255, 0x01/255, 1.0},
circleColor = circleColor or {1.0, 1.0, 1.0, 1.0},
circleRotationSpeed = circleRotationSpeed or 1,
circleDescendSpeed = circleDescendSpeed or 0,
beamsCount = beamsCount or 20,
noup = noup or 0,
},
resetargs = circleDescendSpeed and {
tick_start = function() return core.game.getFrameTime() end,
},
clone = false,
}
......@@ -31,7 +31,7 @@ return {
ellipsoidalFactor = {1.0, 1.0}, --1 is perfect circle, >1 is ellipsoidal
},
resetargs = {
tick_start = function() return core.game.getTime() end,
tick_start = function() return core.game.getFrameTime() end,
},
clone = false,
}
......@@ -32,6 +32,10 @@ newTalent{
self:attr("allow_on_heal", 1)
self:heal(self:spellCrit(t.getHeal(self, t)), self)
self:attr("allow_on_heal", -1)
if core.shader.active(4) then
self:addParticles(Particles.new("shader_shield_temp", 1, {size_factor=1.5, y=-0.3, img="healcelestial", life=25}, {type="healing", time_factor=2000, beamsCount=20, noup=2.0, beamColor1={0xd8/255, 0xff/255, 0x21/255, 1}, beamColor2={0xf7/255, 0xff/255, 0x9e/255, 1}, circleDescendSpeed=3}))
self:addParticles(Particles.new("shader_shield_temp", 1, {size_factor=1.5, y=-0.3, img="healcelestial", life=25}, {type="healing", time_factor=2000, beamsCount=20, noup=1.0, beamColor1={0xd8/255, 0xff/255, 0x21/255, 1}, beamColor2={0xf7/255, 0xff/255, 0x9e/255, 1}, circleDescendSpeed=3}))
end
game:playSoundNear(self, "talents/heal")
return true
end,
......
......@@ -169,6 +169,10 @@ newTalent{
action = function(self, t)
self:attr("allow_on_heal", 1)
self:heal(self:spellCrit(t.getHeal(self, t)), self)
if core.shader.active(4) then
self:addParticles(Particles.new("shader_shield_temp", 1, {size_factor=1.5, y=-0.3, img="healparadox", life=25}, {type="healing", time_factor=3000, beamsCount=15, noup=2.0, beamColor1={0xb6/255, 0xde/255, 0xf3/255, 1}, beamColor2={0x5c/255, 0xb2/255, 0xc2/255, 1}}))
self:addParticles(Particles.new("shader_shield_temp", 1, {size_factor=1.5, y=-0.3, img="healparadox", life=25}, {type="healing", time_factor=3000, beamsCount=15, noup=1.0, beamColor1={0xb6/255, 0xde/255, 0xf3/255, 1}, beamColor2={0x5c/255, 0xb2/255, 0xc2/255, 1}}))
end
self:attr("allow_on_heal", -1)
local target = self
......
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