refactor: damage -> harm
This commit is contained in:
parent
21fb634e69
commit
6e952983c7
8
TODO.md
8
TODO.md
|
@ -1,10 +1,14 @@
|
|||
# TODO
|
||||
|
||||
- ✔ React UI
|
||||
- ❌ Multiple rooms
|
||||
- ✔ Send relevant entity URIs to client; cache and use instead of full transfer
|
||||
- ✔ Forget remembered entities after a while
|
||||
- ✔ Optimize informed and Packer::pack: don't use .map on immutables
|
||||
- ✔ Optimize Damaging::tick
|
||||
- ✔ Optimize Harmful::tick
|
||||
- ✔ Manual state sync
|
||||
- ✔ Informed tracks seen entities (etc?), responsible for upgrading updates
|
||||
- ❌ Multiple rooms
|
||||
- ✔ Refactor input to send serial actions
|
||||
- ✔ "use" action
|
||||
- ❌ chat
|
||||
|
||||
|
|
|
@ -448,8 +448,8 @@ export class App extends decorate(class {}) {
|
|||
}
|
||||
|
||||
renderIntoDom(node) {
|
||||
// Maintain damage element.
|
||||
const promise = this.stage.findUiElement('.damage');
|
||||
// Maintain harm element.
|
||||
const promise = this.stage.findUiElement('.harm');
|
||||
promise.then((inner) => {
|
||||
const innerStyles = () => {
|
||||
const {realOffset} = this.stage.camera;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {Packet} from '@avocado/net';
|
||||
|
||||
export class DamagePacket extends Packet {
|
||||
export class HarmPacket extends Packet {
|
||||
|
||||
static get schema() {
|
||||
return {
|
||||
|
@ -8,11 +8,11 @@ export class DamagePacket extends Packet {
|
|||
data: [
|
||||
{
|
||||
amount: 'varuint',
|
||||
damageSpec: {
|
||||
harmSpec: {
|
||||
affinity: 'uint8',
|
||||
},
|
||||
from: 'uint32',
|
||||
isDamage: 'bool',
|
||||
isHarm: 'bool',
|
||||
},
|
||||
]
|
||||
}
|
|
@ -7,66 +7,65 @@ import {fromRad, normalizeAngleRange, Vector} from '@avocado/math';
|
|||
import {AFFINITY_PHYSICAL} from './constants';
|
||||
|
||||
const decorate = compose(
|
||||
StateProperty('isDamaging'),
|
||||
StateProperty('isHarmful'),
|
||||
);
|
||||
|
||||
export class Damaging extends decorate(Trait) {
|
||||
export class Harmful extends decorate(Trait) {
|
||||
|
||||
static defaultParams() {
|
||||
return {
|
||||
damagingSound: '',
|
||||
damageSpecs: [],
|
||||
harmfulSound: '',
|
||||
harmSpecs: [],
|
||||
};
|
||||
}
|
||||
|
||||
static defaultState() {
|
||||
return {
|
||||
isDamaging: true,
|
||||
isHarmful: true,
|
||||
};
|
||||
}
|
||||
|
||||
static type() {
|
||||
return 'damaging';
|
||||
return 'harmful';
|
||||
}
|
||||
|
||||
constructor(entity, params, state) {
|
||||
super(entity, params, state);
|
||||
this._doesNotDamage = [];
|
||||
const damageSpecsJSON = this.params.damageSpecs;
|
||||
this._damageSpecs = damageSpecsJSON.map((damageSpec) => {
|
||||
this._doesNotHarm = [];
|
||||
const harmSpecsJSON = this.params.harmSpecs;
|
||||
this._harmSpecs = harmSpecsJSON.map((harmSpec) => {
|
||||
return {
|
||||
affinity: AFFINITY_PHYSICAL,
|
||||
lock: 0.1,
|
||||
power: 0,
|
||||
variance: 0.2,
|
||||
...damageSpec,
|
||||
...harmSpec,
|
||||
};
|
||||
});
|
||||
this._damagingSound = this.params.damagingSound;
|
||||
this._harmfulSound = this.params.harmfulSound;
|
||||
}
|
||||
|
||||
doesNotDamageEntity(entity) {
|
||||
if (!this.entity.isDamaging) {
|
||||
doesNotHarmEntity(entity) {
|
||||
if (!this.entity.isHarmful) {
|
||||
return true;
|
||||
}
|
||||
return -1 !== this._doesNotDamage.indexOf(entity);
|
||||
return -1 !== this._doesNotHarm.indexOf(entity);
|
||||
}
|
||||
|
||||
get damageSpecs() {
|
||||
return this._damageSpecs;
|
||||
get harmSpecs() {
|
||||
return this._harmSpecs;
|
||||
}
|
||||
|
||||
get damagingSound() {
|
||||
return this._damagingSound;
|
||||
get harmfulSound() {
|
||||
return this._harmfulSound;
|
||||
}
|
||||
|
||||
tryDamagingEntity(entity) {
|
||||
if (this.doesNotDamageEntity(entity)) {
|
||||
tryHarmfulEntity(entity) {
|
||||
if (this.doesNotHarmEntity(entity)) {
|
||||
return;
|
||||
}
|
||||
if (entity.is('vulnerable')) {
|
||||
if (!entity.isInvulnerable) {
|
||||
entity.takeDamageFrom(this.entity);
|
||||
entity.takeHarmFrom(this.entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +75,7 @@ export class Damaging extends decorate(Trait) {
|
|||
|
||||
particles: () => {
|
||||
return {
|
||||
damaging: {
|
||||
harmful: {
|
||||
traits: {
|
||||
emitted: {
|
||||
params: {
|
||||
|
@ -115,7 +114,7 @@ export class Damaging extends decorate(Trait) {
|
|||
const listeners = {};
|
||||
if (AVOCADO_SERVER) {
|
||||
listeners.collisionStart = (other) => {
|
||||
this.tryDamagingEntity(other);
|
||||
this.tryHarmfulEntity(other);
|
||||
};
|
||||
}
|
||||
return listeners;
|
||||
|
@ -124,14 +123,14 @@ export class Damaging extends decorate(Trait) {
|
|||
methods() {
|
||||
return {
|
||||
|
||||
emitDamagingParticles: (other, json = {}) => {
|
||||
emitHarmfulParticles: (other, json = {}) => {
|
||||
const diff = Vector.sub(this.entity.position, other.position);
|
||||
const velocityAngle = Vector.toAngle(Vector.normalize(diff));
|
||||
const [fromAngle, toAngle] = normalizeAngleRange(
|
||||
velocityAngle - Math.PI / 8,
|
||||
velocityAngle + Math.PI / 8,
|
||||
);
|
||||
this.entity.emitParticle('damaging', merge(
|
||||
this.entity.emitParticle('harmful', merge(
|
||||
{},
|
||||
{
|
||||
traits: {
|
||||
|
@ -153,16 +152,16 @@ export class Damaging extends decorate(Trait) {
|
|||
));
|
||||
},
|
||||
|
||||
setDoesDamage: (entity) => {
|
||||
const index = this._doesNotDamage.indexOf(entity);
|
||||
setDoesHarm: (entity) => {
|
||||
const index = this._doesNotHarm.indexOf(entity);
|
||||
if (-1 !== index) {
|
||||
this._doesNotDamage.splice(index, 1);
|
||||
this._doesNotHarm.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
setDoesNotDamage: (entity) => {
|
||||
if (-1 === this._doesNotDamage.indexOf(entity)) {
|
||||
this._doesNotDamage.push(entity);
|
||||
setDoesNotHarm: (entity) => {
|
||||
if (-1 === this._doesNotHarm.indexOf(entity)) {
|
||||
this._doesNotHarm.push(entity);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -174,7 +173,7 @@ export class Damaging extends decorate(Trait) {
|
|||
if (this.entity.is('collider')) {
|
||||
const isCollidingWith = this.entity.isCollidingWith;
|
||||
for (let i = 0; i < isCollidingWith.length; i++) {
|
||||
this.tryDamagingEntity(isCollidingWith[i]);
|
||||
this.tryHarmfulEntity(isCollidingWith[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,27 +5,27 @@ import {
|
|||
buildTraversal,
|
||||
Context,
|
||||
} from '@avocado/behavior';
|
||||
import {iterateForEach} from '@avocado/core';
|
||||
import {flatten, invokeHookFlat, iterateForEach} from '@avocado/core';
|
||||
import {hasGraphics, TextNodeRenderer} from '@avocado/graphics';
|
||||
import {randomNumber, Vector} from '@avocado/math';
|
||||
|
||||
import {DamagePacket} from './damage.packet';
|
||||
import {HarmPacket} from './harm.packet';
|
||||
|
||||
export class Vulnerable extends Trait {
|
||||
|
||||
static defaultParams() {
|
||||
const emitDamage = buildInvoke(['entity', 'emitDamageParticles'], [
|
||||
buildTraversal(['damage']),
|
||||
const emitHarm = buildInvoke(['entity', 'emitHarmParticles'], [
|
||||
buildTraversal(['harm']),
|
||||
]);
|
||||
const playDamagingSound = buildInvoke(['damage', 'from', 'playSound'], [
|
||||
buildTraversal(['damage', 'from', 'damagingSound']),
|
||||
const playHarmfulSound = buildInvoke(['harm', 'from', 'playSound'], [
|
||||
buildTraversal(['harm', 'from', 'harmfulSound']),
|
||||
]);
|
||||
return {
|
||||
tookDamageActions: {
|
||||
tookHarmActions: {
|
||||
type: 'actions',
|
||||
traversals: [
|
||||
emitDamage,
|
||||
playDamagingSound,
|
||||
emitHarm,
|
||||
playHarmfulSound,
|
||||
],
|
||||
},
|
||||
modifiers: undefined,
|
||||
|
@ -38,55 +38,55 @@ export class Vulnerable extends Trait {
|
|||
|
||||
constructor(entity, params, state) {
|
||||
super(entity, params, state);
|
||||
this.damageTickingPromises = [];
|
||||
this.damages = [];
|
||||
this.harmTickingPromises = [];
|
||||
this.harms = [];
|
||||
this._isInvulnerable = false;
|
||||
this.locks = new Map();
|
||||
this._tookDamageActions = behaviorItemFromJSON(
|
||||
this.params.tookDamageActions
|
||||
this._tookHarmActions = behaviorItemFromJSON(
|
||||
this.params.tookHarmActions
|
||||
);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.locks.clear();
|
||||
this.damageTickingPromises = [];
|
||||
this.harmTickingPromises = [];
|
||||
}
|
||||
|
||||
acceptDamage(damage) {
|
||||
acceptHarm(harm) {
|
||||
const context = new Context({
|
||||
damage,
|
||||
harm,
|
||||
entity: this.entity,
|
||||
});
|
||||
const tickingPromise = this._tookDamageActions.tickingPromise(context);
|
||||
const tickingPromise = this._tookHarmActions.tickingPromise(context);
|
||||
tickingPromise.then(() => {
|
||||
context.destroy();
|
||||
});
|
||||
this.damageTickingPromises.push(tickingPromise);
|
||||
if (damage.from) {
|
||||
damage.from.emitDamagingParticles(this.entity);
|
||||
this.harmTickingPromises.push(tickingPromise);
|
||||
if (harm.from) {
|
||||
harm.from.emitHarmfulParticles(this.entity);
|
||||
}
|
||||
}
|
||||
|
||||
acceptPacket(packet) {
|
||||
if (packet instanceof DamagePacket) {
|
||||
if (packet instanceof HarmPacket) {
|
||||
for (let i = 0; i < packet.data.length; ++i) {
|
||||
const damage = packet.data[i];
|
||||
const harm = packet.data[i];
|
||||
if (this.entity.is('listed') && this.entity.list) {
|
||||
damage.from = this.entity.list.findEntity(damage.from);
|
||||
harm.from = this.entity.list.findEntity(harm.from);
|
||||
}
|
||||
else {
|
||||
damage.from = undefined;
|
||||
harm.from = undefined;
|
||||
}
|
||||
this.acceptDamage(damage);
|
||||
this.acceptHarm(harm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanPackets() {
|
||||
this.damages = [];
|
||||
this.harms = [];
|
||||
}
|
||||
|
||||
damageTextSize(amount) {
|
||||
harmTextSize(amount) {
|
||||
const biggest = 16;
|
||||
const smallest = biggest / 2;
|
||||
const step = biggest / 6;
|
||||
|
@ -113,8 +113,8 @@ export class Vulnerable extends Trait {
|
|||
}
|
||||
|
||||
packets(informed) {
|
||||
if (this.damages.length > 0) {
|
||||
return new DamagePacket(this.damages);
|
||||
if (this.harms.length > 0) {
|
||||
return new HarmPacket(this.harms);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ export class Vulnerable extends Trait {
|
|||
|
||||
particles: () => {
|
||||
return {
|
||||
damage: {
|
||||
harm: {
|
||||
traits: {
|
||||
darkened: {
|
||||
params: {
|
||||
|
@ -242,9 +242,9 @@ export class Vulnerable extends Trait {
|
|||
this._isInvulnerable = isDying;
|
||||
},
|
||||
|
||||
tookDamage: (damage) => {
|
||||
tookHarm: (harm) => {
|
||||
if (AVOCADO_SERVER) {
|
||||
this.damages.push(damage);
|
||||
this.harms.push(harm);
|
||||
this.setDirty();
|
||||
}
|
||||
},
|
||||
|
@ -255,10 +255,10 @@ export class Vulnerable extends Trait {
|
|||
methods() {
|
||||
return {
|
||||
|
||||
emitDamageParticles: (damage) => {
|
||||
const {amount, isDamage} = damage;
|
||||
const fill = isDamage ? '#FF0000' : '#00FF77';
|
||||
this.entity.emitParticle('damage', {
|
||||
emitHarmParticles: (harm) => {
|
||||
const {amount, isHarm} = harm;
|
||||
const fill = isHarm ? '#FF0000' : '#00FF77';
|
||||
this.entity.emitParticle('harm', {
|
||||
traits: {
|
||||
textual: {
|
||||
state: {
|
||||
|
@ -266,7 +266,7 @@ export class Vulnerable extends Trait {
|
|||
textStyle: {
|
||||
fill,
|
||||
fontFamily: 'joystix',
|
||||
fontSize: this.damageTextSize(amount),
|
||||
fontSize: this.harmTextSize(amount),
|
||||
strokeThickness: 2,
|
||||
},
|
||||
},
|
||||
|
@ -279,23 +279,23 @@ export class Vulnerable extends Trait {
|
|||
});
|
||||
},
|
||||
|
||||
takeDamageFrom: (entity) => {
|
||||
const damageSpecs = entity.damageSpecs;
|
||||
for (let i = 0; i < damageSpecs.length; ++i) {
|
||||
const damageSpec = damageSpecs[i];
|
||||
if (this.locks.has(damageSpec)) {
|
||||
takeHarmFrom: (entity) => {
|
||||
const harmSpecs = entity.harmSpecs;
|
||||
for (let i = 0; i < harmSpecs.length; ++i) {
|
||||
const harmSpec = harmSpecs[i];
|
||||
if (this.locks.has(harmSpec)) {
|
||||
continue;
|
||||
}
|
||||
this.locks.set(damageSpec, damageSpec.lock);
|
||||
let power = damageSpec.power;
|
||||
this.locks.set(harmSpec, harmSpec.lock);
|
||||
let power = harmSpec.power;
|
||||
// Check if vulnerable to this affinity.
|
||||
if (this.params.modifiers) {
|
||||
if (damageSpec.affinity in this.params.modifiers) {
|
||||
power *= this.params.modifiers[damageSpec.affinity];
|
||||
if (harmSpec.affinity in this.params.modifiers) {
|
||||
power *= this.params.modifiers[harmSpec.affinity];
|
||||
}
|
||||
}
|
||||
// Give any knockback.
|
||||
if (damageSpec.knockback) {
|
||||
if (harmSpec.knockback) {
|
||||
if (
|
||||
this.entity.is('mobile')
|
||||
&& this.entity.is('positioned')
|
||||
|
@ -306,35 +306,35 @@ export class Vulnerable extends Trait {
|
|||
entity.position,
|
||||
);
|
||||
const unit = Vector.normalize(difference)
|
||||
const knockback = Vector.scale(unit, damageSpec.knockback);
|
||||
const knockback = Vector.scale(unit, harmSpec.knockback);
|
||||
this.entity.applyMovement(knockback);
|
||||
}
|
||||
}
|
||||
const variance = Math.random() * damageSpec.variance * 2 - damageSpec.variance;
|
||||
const variance = Math.random() * harmSpec.variance * 2 - harmSpec.variance;
|
||||
const difference = power * variance;
|
||||
// Account for variance past 0, so track if it's damage or not.
|
||||
// Account for variance past 0, so track if it's harm or not.
|
||||
let amount = Math.round(power + difference);
|
||||
let isDamage;
|
||||
let isHarm;
|
||||
if (power < 0) {
|
||||
isDamage = false;
|
||||
isHarm = false;
|
||||
if (amount > 0) {
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
isDamage = true;
|
||||
isHarm = true;
|
||||
if (amount < 0) {
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
amount = Math.abs(amount);
|
||||
const damage = {
|
||||
isDamage,
|
||||
const harm = {
|
||||
isHarm,
|
||||
amount,
|
||||
damageSpec,
|
||||
harmSpec,
|
||||
from: entity.numericUid,
|
||||
};
|
||||
this.entity.emit('tookDamage', damage);
|
||||
this.entity.emit('tookHarm', harm);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -342,8 +342,8 @@ export class Vulnerable extends Trait {
|
|||
}
|
||||
|
||||
tick(elapsed) {
|
||||
for (let i = 0; i < this.damageTickingPromises.length; ++i) {
|
||||
this.damageTickingPromises[i].tick(elapsed);
|
||||
for (let i = 0; i < this.harmTickingPromises.length; ++i) {
|
||||
this.harmTickingPromises[i].tick(elapsed);
|
||||
}
|
||||
if (AVOCADO_SERVER) {
|
||||
iterateForEach(this.locks.keys(), (key) => {
|
||||
|
|
|
@ -7,7 +7,7 @@ export function blueFireJSON() {
|
|||
const json = fireJSON();
|
||||
json.traits.animated.params.animations.idle.uri = '/blue-fire.animation.json';
|
||||
json.traits.existent.state.name = 'Blue fire';
|
||||
json.traits.damaging.params.damageSpecs[0].power = -15;
|
||||
json.traits.harmful.params.harmSpecs[0].power = -15;
|
||||
json.traits.audible.params.sounds.fire.uri = '/blue-fire.sound.json';
|
||||
return json;
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ export function fireJSON() {
|
|||
isSensor: true,
|
||||
},
|
||||
},
|
||||
damaging: {
|
||||
harmful: {
|
||||
params: {
|
||||
damagingSound: 'fire',
|
||||
damageSpecs: [
|
||||
harmfulSound: 'fire',
|
||||
harmSpecs: [
|
||||
{
|
||||
affinity: AFFINITY_FIRE,
|
||||
lock: 0.15,
|
||||
|
|
|
@ -67,14 +67,17 @@ export function kittyFireJSON() {
|
|||
// for (let i = 0; i < 30; ++i) {
|
||||
// addEntityWithRandomPosition('/flower-barrel.entity.json');
|
||||
// }
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
addEntityWithRandomPosition('/mama-kitty-spawner.entity.json');
|
||||
// for (let i = 0; i < 15; ++i) {
|
||||
// addEntityWithRandomPosition('/mama-kitty-spawner.entity.json');
|
||||
// }
|
||||
for (let i = 0; i < 50; ++i) {
|
||||
addEntityWithRandomPosition('/kitty.entity.json');
|
||||
}
|
||||
// for (let i = 0; i < 50; ++i) {
|
||||
// for (let i = 0; i < 150; ++i) {
|
||||
// addEntityWithRandomPosition('/fire.entity.json');
|
||||
// }
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
addEntityWithRandomPosition('/blue-fire.entity.json');
|
||||
}
|
||||
// for (let i = 0; i < 5; ++i) {
|
||||
// addEntityWithRandomPosition('/blue-fire.entity.json');
|
||||
// }
|
||||
return roomJSON;
|
||||
}
|
||||
|
|
|
@ -125,6 +125,18 @@ export function kittyJSON() {
|
|||
uri: '/yarn-ball.entity.json',
|
||||
},
|
||||
},
|
||||
{
|
||||
perc: 80,
|
||||
json: {
|
||||
uri: '/yarn-ball.entity.json',
|
||||
},
|
||||
},
|
||||
{
|
||||
perc: 90,
|
||||
json: {
|
||||
uri: '/yarn-ball.entity.json',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -4,7 +4,7 @@ import {AFFINITY_NONE} from '../../common/combat/constants';
|
|||
|
||||
// Healing potion.
|
||||
export function potionJSON() {
|
||||
const causeHealing = buildInvoke(['wielder', 'takeDamageFrom'], [
|
||||
const causeHealing = buildInvoke(['wielder', 'takeHarmFrom'], [
|
||||
buildTraversal(['item']),
|
||||
]);
|
||||
const decrement = buildInvoke(
|
||||
|
@ -15,9 +15,9 @@ export function potionJSON() {
|
|||
);
|
||||
return {
|
||||
traits: {
|
||||
damaging: {
|
||||
harmful: {
|
||||
params: {
|
||||
damageSpecs: [
|
||||
harmSpecs: [
|
||||
{
|
||||
affinity: AFFINITY_NONE,
|
||||
lock: 0,
|
||||
|
|
|
@ -4,7 +4,7 @@ import {AFFINITY_NONE} from '../../common/combat/constants';
|
|||
|
||||
// Projectile rock.
|
||||
export function rockProjectileJSON() {
|
||||
// Set as not damaging to user.
|
||||
// Set as not harmful to user.
|
||||
const setDoesNotCollideWith = buildInvoke(
|
||||
['entity', 'setDoesNotCollideWith'],
|
||||
[
|
||||
|
@ -44,8 +44,8 @@ export function rockProjectileJSON() {
|
|||
['entity', 'isColliding'],
|
||||
false,
|
||||
);
|
||||
const setIsNotDamaging = buildTraversal(
|
||||
['entity', 'isDamaging'],
|
||||
const setIsNotHarmful = buildTraversal(
|
||||
['entity', 'isHarmful'],
|
||||
false,
|
||||
);
|
||||
const fadeOutAndSlowDown = buildInvoke(
|
||||
|
@ -114,7 +114,7 @@ export function rockProjectileJSON() {
|
|||
type: 'actions',
|
||||
traversals: [
|
||||
setIsNotColliding,
|
||||
setIsNotDamaging,
|
||||
setIsNotHarmful,
|
||||
afterImpact,
|
||||
destroy,
|
||||
],
|
||||
|
@ -149,9 +149,9 @@ export function rockProjectileJSON() {
|
|||
isSensor: true,
|
||||
},
|
||||
},
|
||||
damaging: {
|
||||
harmful: {
|
||||
params: {
|
||||
damageSpecs: [
|
||||
harmSpecs: [
|
||||
{
|
||||
affinity: AFFINITY_NONE,
|
||||
knockback: 500,
|
||||
|
@ -170,7 +170,7 @@ export function rockProjectileJSON() {
|
|||
emitter: {
|
||||
params: {
|
||||
particles: {
|
||||
damaging: {
|
||||
harmful: {
|
||||
rate: 0.0125,
|
||||
count: 5,
|
||||
traits: {
|
||||
|
|
Loading…
Reference in New Issue
Block a user