Page 1 of 1

Issues with creating new damage shield types

Posted: Mon Jul 28, 2014 1:22 pm
by Razakai
I have a spell that applies a damage shield to the player, Crimson Barrier. While the shield holds, they gain a number of bonuses. This was working fine, until a player noticed that if they used a shielding rune with a shorter duration while the spell was active, once the rune expired the game would lock up. This appears to be because damage shields have the 'self.damage_shield_absorb = nil' line when they expire, so despite there being another damage shield active, the value would be set to nil causing the UIset to freak out.
So I'm looking for advice on what would be the best way to fix it. Creating a brand new type of damage shield along the lines of Time Shield, which sounds like it'd be very difficult via addon? I'm leaning towards just preventing the use of other shielding while Crimson Barrier is active and visa versa, but I'm unsure how to best implement that. I've included the code for the timed effect below.

Code: Select all

newEffect{
	name = "CRIMSON_BARRIER", image = "talents/crimson_barrier.png",
	desc = "Crimson Barrier",
	long_desc = function(self, eff) return ("The target is surrounded by a shield of blood, absorbing %d/%d damage, increasing healing factor by %d%% and draining %0.2f life from attackers."):format(self.damage_shield_absorb, eff.power, eff.heal, eff.dam) end,
	type = "magical",
	subtype = { arcane=true, shield=true },
	status = "beneficial",
	parameters = { power=100, healing=1, dam=1, empower=0 },
	on_gain = function(self, err) return "A bloody shield forms around #target#.", "+Shield" end,
	on_lose = function(self, err) return "The bloody shield around #target# crumbles.", "-Shield" end,
	on_aegis = function(self, eff, aegis)
		self.damage_shield_absorb = self.damage_shield_absorb + eff.power * aegis / 100
		if core.shader.active(4) then
			self:removeParticles(eff.particle)
			local bc = {0.4, 0.7, 1.0, 1.0}
			local ac = {0x21/255, 0x9f/255, 0xff/255, 1}
			if eff.color then
				bc = table.clone(eff.color) bc[4] = 1
				ac = table.clone(eff.color) ac[4] = 1
			end
			eff.particle = self:addParticles(Particles.new("shader_shield", 1, {size_factor=1.3, img="runicshield"}, {type="runicshield", shieldIntensity=0.14, ellipsoidalFactor=1.2, time_factor=5000, bubbleColor=bc, auraColor=ac}))
		end		
	end,
	damage_feedback = function(self, eff, src, value)
		if eff.particle and eff.particle._shader and eff.particle._shader.shad and src and src.x and src.y then
			local r = -rng.float(0.2, 0.4)
			local a = math.atan2(src.y - self.y, src.x - self.x)
			eff.particle._shader:setUniform("impact", {math.cos(a) * r, math.sin(a) * r})
			eff.particle._shader:setUniform("impact_tick", core.game.getTime())
		end
	end,
	activate = function(self, eff)
		if self:attr("shield_factor") then eff.power = eff.power * (100 + self:attr("shield_factor")) / 100 end
		if self:attr("shield_dur") then eff.dur = eff.dur + self:attr("shield_dur") end
		eff.tmpid = self:addTemporaryValue("damage_shield", eff.power)
		self.damage_shield_absorb = eff.power
		self.damage_shield_absorb_max = eff.power
		eff.healid = self:addTemporaryValue("healing_factor", eff.heal/100)
		eff.leechid = self:addTemporaryValue("on_melee_hit", {[DamageType.DEVOUR_LIFE]=eff.dam})
		if core.shader.active(4) then
			eff.particle = self:addParticles(Particles.new("shader_shield", 1, nil, {type="shield", shieldIntensity=0.2, color=eff.color or {0.4, 0.7, 1.0}}))
		else
			eff.particle = self:addParticles(Particles.new("damage_shield", 1))
		end
	end,
	deactivate = function(self, eff)
		self:removeParticles(eff.particle)
		self:removeTemporaryValue("damage_shield", eff.tmpid)
		self.damage_shield_absorb = nil
		self.damage_shield_absorb_max = nil
		self:removeTemporaryValue("healing_factor", eff.healid) 
		self:removeTemporaryValue("on_melee_hit", eff.leechid) 		
	end,
	on_timeout = function(self, eff)
		if eff.empower == 1 then
			self:project({type="ball", range=0, friendlyfire=false, radius=3}, self.x, self.y, function(px, py)
				local target = game.level.map(px, py, Map.ACTOR)
				if not target then return end
						if self:reactionToward(target) < 0 then
							DamageType:get(DamageType.DEVOUR_LIFE).projector(self, target.x, target.y, DamageType.DEVOUR_LIFE, eff.dam*2)
						end
			end)
		end
	end,
} 

Re: Issues with creating new damage shield types

Posted: Mon Jul 28, 2014 1:39 pm
by grayswandir
I stuck my not-a-damage-shield in the Actor:takeHit hook instead of using the existing damage shield system. You could do something like that.

Simplified version of mine for reference:

Code: Select all

-- Actor:takeHit
hook = function(self, data)
	local value = data.value
	local src = data.src
	local damtype = table.get(data, 'death_note', 'damtype')

	-- Jagged Body
	if value > 0 and self:knowTalent('T_JAGGED_BODY') then
		local blocked = math.min(self.jaggedbody, value)
		self.jaggedbody = self.jaggedbody - blocked
		value = value - blocked
		game:delayedLogDamage(
			src, self, 0, ('#SLATE#(%d absorbed)#LAST#'):format(blocked), false)
	end

	data.value = value
	return true
end
class:bindHook('Actor:takeHit', hook)

Re: Issues with creating new damage shield types

Posted: Wed Jul 30, 2014 12:02 pm
by Razakai
Got it working, thanks.