Draft: Add a shield effect and make blood barrier give a shield Closes #1894 and #1672 See merge request Isleward/isleward!579merge-requests/579/merge
@@ -105,7 +105,7 @@ define([ | |||
}); | |||
if (stats) | |||
stats.updateHpSprite(); | |||
stats.updateBars(); | |||
}, | |||
updateVisibility: function () { | |||
@@ -138,10 +138,8 @@ define([ | |||
if (this.nameSprite) | |||
this.nameSprite.visible = (visible && config.showNames); | |||
if (!visible && this.stats && this.stats.hpSprite && this.stats.hpSprite.visible) { | |||
this.stats.hpSprite.visible = false; | |||
this.stats.hpSpriteInner.visible = false; | |||
} | |||
if (!visible && this.stats) | |||
this.stats.updateBarVisibility(false); | |||
this.components.forEach(c => { | |||
if (c.setVisible) | |||
@@ -260,7 +260,7 @@ define([ | |||
obj.setSpritePosition(); | |||
if (obj.stats) | |||
obj.stats.updateHpSprite(); | |||
obj.stats.updateBars(); | |||
} | |||
}, | |||
@@ -0,0 +1,52 @@ | |||
define([ | |||
], function ( | |||
) { | |||
const shieldEffect = { | |||
bar: null, | |||
visible: true, | |||
amount: 1, | |||
maxAmount: 1, | |||
init: function () { | |||
if (this.obj.stats) { | |||
this.bar = this.obj.stats.addBar({ | |||
color: 0x533399, | |||
innerColor: 0xa24eff, | |||
calcPercent: () => (this.amount / this.maxAmount), | |||
isVisible: () => this.visible | |||
}); | |||
this.obj.stats.updateBars(); | |||
} | |||
}, | |||
extend: function (data) { | |||
this.amount = data.amount; | |||
this.maxAmount = data.maxAmount; | |||
if (this.obj.stats) | |||
this.obj.stats.updateBars(); | |||
}, | |||
destroy: function () { | |||
if (this.bar && this.obj.stats) | |||
this.obj.stats.removeBar(this.bar); | |||
}, | |||
setVisible: function (visible) { | |||
this.visible = visible; | |||
if (this.obj.stats) | |||
this.obj.stats.updateBars(); | |||
} | |||
}; | |||
return { | |||
templates: { | |||
shield: shieldEffect | |||
} | |||
}; | |||
}); |
@@ -5,16 +5,15 @@ define([ | |||
events, | |||
renderer | |||
) { | |||
const hpBarPadding = scaleMult; | |||
const hpBarHeight = scaleMult; | |||
const barPadding = scaleMult; | |||
const barHeight = scaleMult; | |||
return { | |||
type: 'stats', | |||
values: null, | |||
hpSprite: null, | |||
hpSpriteInner: null, | |||
bars: [], | |||
init: function (blueprint) { | |||
if (this.obj.self) | |||
@@ -25,66 +24,125 @@ define([ | |||
let obj = this.obj; | |||
this.hpSprite = renderer.buildRectangle({ | |||
this.addBar({ | |||
color: 0x802343, | |||
innerColor: 0xd43346, | |||
calcPercent: () => (this.values.hp / this.values.hpMax), | |||
isVisible: () => (this.values.hp < this.values.hpMax) && (!obj.sprite || obj.sprite.visible) | |||
}); | |||
this.updateBars(); | |||
}, | |||
addBar: function (config) { | |||
let obj = this.obj; | |||
let { color, innerColor, calcPercent, isVisible } = config; | |||
let sprite = renderer.buildRectangle({ | |||
layerName: 'effects', | |||
x: obj.x * scale, | |||
y: obj.y * scale, | |||
w: 1, | |||
h: 1, | |||
color: 0x802343 | |||
color: color | |||
}); | |||
this.hpSpriteInner = renderer.buildRectangle({ | |||
x: 0, | |||
y: 0, | |||
let spriteInner = renderer.buildRectangle({ | |||
layerName: 'effects', | |||
x: obj.x, | |||
y: obj.y, | |||
w: 1, | |||
h: 1, | |||
layerName: 'effects', | |||
color: 0xd43346 | |||
color: innerColor | |||
}); | |||
let bar = { | |||
sprite: sprite, | |||
spriteInner: spriteInner, | |||
calcPercent: calcPercent, | |||
isVisible: isVisible | |||
}; | |||
this.bars.push(bar); | |||
return bar; | |||
}, | |||
removeBar: function (bar) { | |||
this.removeSprites(this.bars.find(b => b === bar)); | |||
this.bars.spliceFirstWhere(b => b === bar); | |||
}, | |||
removeSprites: function (bar) { | |||
renderer.destroyObject({ | |||
sprite: bar.sprite, | |||
layerName: 'effects' | |||
}); | |||
this.updateHpSprite(); | |||
renderer.destroyObject({ | |||
sprite: bar.spriteInner, | |||
layerName: 'effects' | |||
}); | |||
}, | |||
updateHpSprite: function () { | |||
updateBars: function () { | |||
const { obj: { x, y, dead, sprite } } = this; | |||
if (dead) | |||
return; | |||
let barIndex = 0; | |||
//By default, hp sprites are 10px higher than the owner object's sprite. Keeping in | |||
// mind that bigger sprites always have their 'origin' in the bottom middle tile | |||
const spriteHeight = sprite ? sprite.height : scale; | |||
const spriteWidth = sprite ? sprite.width : scale; | |||
this.bars.forEach(bar => { | |||
const percent = bar.calcPercent(); | |||
const xOffset = -(spriteWidth - scale) / 2; | |||
const yOffset = -(spriteHeight - scale) - (scaleMult * 2); | |||
//By default, hp sprites are 10px higher than the owner object's sprite. Keeping in | |||
// mind that bigger sprites always have their 'origin' in the bottom middle tile | |||
const spriteHeight = sprite ? sprite.height : scale; | |||
const spriteWidth = sprite ? sprite.width : scale; | |||
const hpBarWidth = spriteWidth - (hpBarPadding * 2); | |||
const xOffset = -(spriteWidth - scale) / 2; | |||
const yOffset = -(spriteHeight - scale) - ((barIndex + 1) * scaleMult * 2); | |||
const newX = (x * scale) + hpBarPadding + xOffset; | |||
const newY = (y * scale) + yOffset; | |||
const barWidth = spriteWidth - (barPadding * 2); | |||
renderer.moveRectangle({ | |||
sprite: this.hpSprite, | |||
x: newX, | |||
y: newY, | |||
w: hpBarWidth, | |||
h: hpBarHeight | |||
}); | |||
const newX = (x * scale) + barPadding + xOffset; | |||
const newY = (y * scale) + yOffset; | |||
renderer.moveRectangle({ | |||
sprite: bar.sprite, | |||
x: newX, | |||
y: newY, | |||
w: barWidth, | |||
h: barHeight | |||
}); | |||
renderer.moveRectangle({ | |||
sprite: bar.spriteInner, | |||
x: newX, | |||
y: newY, | |||
w: percent * barWidth, | |||
h: barHeight | |||
}); | |||
const isVisible = bar.isVisible ? bar.isVisible() : true; | |||
renderer.moveRectangle({ | |||
sprite: this.hpSpriteInner, | |||
x: newX, | |||
y: newY, | |||
w: (this.values.hp / this.values.hpMax) * hpBarWidth, | |||
h: hpBarHeight | |||
if (isVisible) | |||
barIndex++; | |||
bar.sprite.visible = isVisible; | |||
bar.spriteInner.visible = isVisible; | |||
}); | |||
}, | |||
const isVisible = (this.values.hp < this.values.hpMax) && (!sprite || sprite.visible); | |||
updateBarVisibility: function (visible) { | |||
this.bars.forEach(bar => { | |||
const isVisible = (visible !== undefined) ? visible : bar.isVisible(); | |||
this.hpSprite.visible = isVisible; | |||
this.hpSpriteInner.visible = isVisible; | |||
bar.sprite.visible = isVisible; | |||
bar.spriteInner.visible = isVisible; | |||
}); | |||
}, | |||
extend: function (blueprint) { | |||
@@ -101,18 +159,12 @@ define([ | |||
if (this.obj.has('serverId')) | |||
events.emit('onGetPartyStats', this.obj.serverId, this.values); | |||
this.updateHpSprite(); | |||
this.updateBars(); | |||
}, | |||
destroy: function () { | |||
renderer.destroyObject({ | |||
sprite: this.hpSprite, | |||
layerName: 'effects' | |||
}); | |||
renderer.destroyObject({ | |||
sprite: this.hpSpriteInner, | |||
layerName: 'effects' | |||
this.bars.forEach(bar => { | |||
this.removeSprites(bar); | |||
}); | |||
} | |||
}; | |||
@@ -152,7 +152,7 @@ module.exports = { | |||
//If there is no existing effect or the effect is not stackable, make a new effect | |||
if (!oldEffect || !oldEffect.shouldStack) | |||
return this.buildEffect(options); | |||
//If the effect is stackable and the new effect should stack, stack with the old effect | |||
let shouldStack = oldEffect.shouldStack(options); | |||
if (shouldStack && oldEffect.incrementStack) { | |||
@@ -184,18 +184,18 @@ module.exports = { | |||
buildEffect: function (options) { | |||
let builtEffect = this.getTypeTemplate(options.type); | |||
for (let p in options) | |||
for (let p in options) | |||
builtEffect[p] = options[p]; | |||
builtEffect.obj = this.obj; | |||
builtEffect.id = this.nextId++; | |||
builtEffect.silent = options.silent; | |||
this.effects.push(builtEffect); | |||
if (builtEffect.init) | |||
builtEffect.init(options.source); | |||
this.effects.push(builtEffect); | |||
if (!options.silent) | |||
this.obj.syncer.setArray(false, 'effects', 'addEffects', builtEffect.simplify()); | |||
@@ -204,7 +204,7 @@ module.exports = { | |||
return builtEffect; | |||
}, | |||
syncExtend: function (id, data) { | |||
syncExtend: function (id, data, self) { | |||
let effect = this.effects.find(e => e.id === id); | |||
if (!effect) | |||
return; | |||
@@ -213,7 +213,7 @@ module.exports = { | |||
if (effect.silent) | |||
return; | |||
this.obj.syncer.setArray(true, 'effects', 'extendEffects', { | |||
this.obj.syncer.setArray(self, 'effects', 'extendEffects', { | |||
id, | |||
data | |||
}); | |||
@@ -241,7 +241,7 @@ module.exports = { | |||
this.destroyEffect(effect); | |||
this.syncRemove(effect.id); | |||
this.effects.spliceWhere(e => e.id === id); | |||
}, | |||
@@ -227,6 +227,10 @@ module.exports = { | |||
extends: 'effects', | |||
path: 'server/clientComponents/effects/auras.js' | |||
}); | |||
config.clientComponents.push({ | |||
extends: 'effects', | |||
path: 'server/clientComponents/effects/shield.js' | |||
}); | |||
events.emit('onBeforeGetClientConfig', config); | |||
@@ -0,0 +1,33 @@ | |||
module.exports = { | |||
type: 'shield', | |||
amount: 0, | |||
maxAmount: 0, | |||
init: function () { | |||
this.syncExtend({ | |||
amount: this.amount, | |||
maxAmount: this.maxAmount | |||
}); | |||
}, | |||
events: { | |||
beforeTakeDamage: function (damage, source) { | |||
if (this.amount > 0) { | |||
let mitigatedAmount = Math.min(damage.amount, this.amount); | |||
damage.amount -= mitigatedAmount; | |||
this.amount -= mitigatedAmount; | |||
//Sync new values to client | |||
this.syncExtend({ | |||
amount: this.amount, | |||
maxAmount: this.maxAmount | |||
}); | |||
} | |||
if (this.amount <= 0) | |||
this.destroyed = true; | |||
} | |||
} | |||
}; |
@@ -1,7 +1,11 @@ | |||
module.exports = { | |||
syncExtend: function (data) { | |||
let effects = this.obj.effects; | |||
effects.syncExtend(this.id, data); | |||
effects.syncExtend(this.id, data, false); | |||
}, | |||
syncExtendSelf: function (data) { | |||
let effects = this.obj.effects; | |||
effects.syncExtend(this.id, data, true); | |||
}, | |||
isFirstOfType: function () { | |||
@@ -34,5 +38,5 @@ module.exports = { | |||
id: this.id, | |||
type: this.type | |||
}; | |||
} | |||
} | |||
}; |
@@ -39,8 +39,12 @@ module.exports = { | |||
obj.stats.takeDamage(damage, 0, obj); | |||
amount = amount * this.shieldMultiplier; | |||
const heal = { amount }; | |||
target.stats.getHp(heal, obj); | |||
target.effects.addEffect({ | |||
type: 'shield', | |||
ttl: this.frenzyDuration, | |||
amount: amount, | |||
maxAmount: amount | |||
}); | |||
//Only reset the first spell's cooldown if it's an auto attack and not a spell | |||
const firstSpell = target.spellbook.spells[0]; | |||