From 8457312f6329dff990c990c916291d9b8f7df7d5 Mon Sep 17 00:00:00 2001 From: Thayol Date: Sat, 18 Jan 2025 12:00:12 +0900 Subject: [PATCH] display buffs in the client --- public/client.js | 23 +++++++++++++++++++++-- public/index.html | 33 +++++++++++++++++++++++++++++++++ src/ability.js | 8 ++++---- src/entity.js | 35 +++++++++++++++++++++++------------ src/index.js | 18 +++++++++--------- 5 files changed, 90 insertions(+), 27 deletions(-) diff --git a/public/client.js b/public/client.js index 4c6008c..2aeeeaf 100644 --- a/public/client.js +++ b/public/client.js @@ -247,7 +247,7 @@ function connectWebSocket() { } } - console.log(state) + // console.log(state) if (state.width != null && state.height != null && (ground.geometry.attributes.width != state.width || ground.geometry.attributes.height != state.height)) { ground.geometry = new THREE.PlaneGeometry(state.width / 100, state.height / 100) @@ -294,6 +294,14 @@ function connectWebSocket() { teamMarker.layers.set(1) entity.add(teamMarker) + const buffMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, transparent: true, opacity: 0.4 }) + const buffMarker = new THREE.Mesh(new THREE.CylinderGeometry((e.visualRadius + 10) / 100, (e.visualRadius + 10) / 100, 1), buffMaterial) + const buffMarkerSize = 400 + buffMarker.scale.y = e.height / buffMarkerSize + buffMarker.layers.set(1) + buffMarker.visible = false + entity.add(buffMarker) + if (e.id == playerId) { const rangeMaterial = teamMaterials['range'] const rangeSize = (state.abilities.find((it) => it.id == e.abilities?.a)?.range ?? 0) + e.radius @@ -308,6 +316,8 @@ function connectWebSocket() { entities[e.id] = entity } + entity.children.at(2).visible = e.buffs.some((it) => it.id == 'exposed') // TODO: only works for Exposed now + entity.userData.flaggedForRemoval = false positionTweens[entity.id] = new Tween(entity.position).to({ x: e.position.x / 100, y: e.position.y / 100, z: e.height / 100 }, tweenDuration).start() @@ -422,6 +432,15 @@ function connectWebSocket() { } } + let buffs = `` + player.buffs.forEach((b) => { + buffs += `
${state.buffs.find((it) => it.id == b.id).name}
` + }) + + if (document.getElementById('buffs').innerHTML != buffs) { + document.getElementById('buffs').innerHTML = buffs + } + let castIndicatorDisplay = 'none' if (player.casting != null) { castIndicatorDisplay = 'block' @@ -441,7 +460,7 @@ function connectWebSocket() { } } - // document.getElementById('state').innerHTML = JSON.stringify(stateUpdates, null, 2) + document.getElementById('state').innerHTML = JSON.stringify(stateUpdates, null, 2) } } diff --git a/public/index.html b/public/index.html index 08c97ee..7275edf 100644 --- a/public/index.html +++ b/public/index.html @@ -132,6 +132,38 @@ height: 20px; padding: 2px; } + + .buffs { + position: fixed; + display: flex; + gap: 10px; + inset: auto 0 120px calc(50vw - 165px); + width: fit-content; + } + + .buff { + flex: 1 0 0; + width: 30px; + height: 30px; + background-color: black; + /* border: 1px solid gray; */ + border-right: 1px solid gray; + color: white; + overflow: hidden; + } + + .buff:hover { + overflow: visible; + z-index: 3; + } + + .buff-body { + border: 1px solid gray; + padding: 5px; + background-color: black; + width: fit-content; + height: 100%; + } @@ -168,6 +200,7 @@
+
diff --git a/src/ability.js b/src/ability.js index e1d0c80..04a232d 100644 --- a/src/ability.js +++ b/src/ability.js @@ -42,7 +42,7 @@ export default class Ability { if (collidingEntity == null) { return } if (collidingEntity.team == (projectile.owner?.team ?? 'unknown')) { return } - collidingEntity.damage(ability.damage) + collidingEntity.damage(ability.damage, caster) projectile.despawn() } @@ -77,7 +77,7 @@ export default class Ability { if (target == null) { return } const rangedAttackAfter = function rangedAttackAfter() { - target.damage(ability.damage) + target.damage(ability.damage, caster) } const projectile = new Projectile({ @@ -108,7 +108,7 @@ export default class Ability { const target = caster.game?.entities.find((it) => it.id == targetId) if (target == null) { return } - target.damage(ability.damage) + target.damage(ability.damage, caster) caster.cooldown(ability.id) }, }) @@ -185,7 +185,7 @@ export default class Ability { if (collidingEntity == null) { return } if (collidingEntity.team == (projectile.owner?.team ?? 'unknown')) { return } - collidingEntity.applyBuff(Buff.exposed.id) + collidingEntity.applyBuff(Buff.exposed.id, caster.id) projectile.despawn() } diff --git a/src/entity.js b/src/entity.js index 2ae2f53..48c0c9e 100644 --- a/src/entity.js +++ b/src/entity.js @@ -153,14 +153,17 @@ export default class Entity { ) } - applyBuff(id) { + applyBuff(id, sourceId = null) { const index = this.buffs.findIndex((it) => it.id == id) + const source = sourceId ?? this.id const timestamp = this.game?.currentTick ?? 0 + if (index > -1) { this.buffs[index].timestamp = timestamp + this.buffs[index].source = source } else { - this.buffs.push({ id, timestamp }) + this.buffs.push({ id, source, timestamp }) } } @@ -191,11 +194,14 @@ export default class Entity { .reduce((e1, e2) => (e1?.distanceTo(cursor) ?? Infinity) < e2.distanceTo(cursor) ? e1 : e2, null) } - damage(amount) { + damage(amount, source = null) { let damage = amount if (this.hasBuff(Buff.exposed.id)) { - damage *= 3 // TODO: move to buff, make generic - this.removeBuff(Buff.exposed.id) + const buff = this.getBuff(Buff.exposed.id) + if (buff.source == source.id) { + damage *= 3 // TODO: move to Buff class to make generic + this.removeBuff(Buff.exposed.id) + } } this.health = Math.min(Math.max(0, this.health - damage), this.maxHealth) @@ -209,6 +215,16 @@ export default class Entity { return this.position.distanceTo(cursor) } + getBuff(id) { + const entityBuff = this.buffs.find((it) => it.id == id) + if (entityBuff == null) { return } + + const buffDefinition = this.game?.buffs.find((it) => it.id == entityBuff.id) + if (buffDefinition == null) { return } + + return { ...buffDefinition, ...entityBuff } + } + hasBuff(id) { return this.buffs.some((it) => it.id == id) } @@ -405,13 +421,8 @@ export default class Entity { } #tickBuff(index) { - const entityBuff = this.buffs[index] - if (entityBuff == null) { return } - - const buffDefinition = this.game?.buffs.find((it) => it.id == entityBuff.id) - if (buffDefinition == null) { return } - - const buff = { ...buffDefinition, ...entityBuff } + if (this.buffs[index] == null) { return } + const buff = this.getBuff(this.buffs[index].id) const duration = this.game?.secToTick(buff.duration) ?? 0 const currentTick = this.game?.currentTick ?? 0 diff --git a/src/index.js b/src/index.js index f168982..ffdfb56 100644 --- a/src/index.js +++ b/src/index.js @@ -121,17 +121,17 @@ function laneScenario() { game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: redRoute }))) } } - // game.logic = gameLogic + game.logic = gameLogic - player2.teleport(new Vector2(100, 100)) - player2.logic = function patrolLogic() { - const entity = this - if (entity.position.x < 100) { entity.memory.patrolReverse = false } - if (entity.position.x > 1900) { entity.memory.patrolReverse = true } - const goal = entity.memory.patrolReverse ? new Vector2(50, 100) : new Vector2(1950, 100) + // player2.teleport(new Vector2(100, 100)) + // player2.logic = function patrolLogic() { + // const entity = this + // if (entity.position.x < 100) { entity.memory.patrolReverse = false } + // if (entity.position.x > 1900) { entity.memory.patrolReverse = true } + // const goal = entity.memory.patrolReverse ? new Vector2(50, 100) : new Vector2(1950, 100) - entity.moveAction(goal) - } + // entity.moveAction(goal) + // } // player1.abilities[0] = 'melee_attack' }