Merge branch 'combos'

This commit is contained in:
ntr 2019-02-21 15:03:21 +11:00
commit 9b68fd0a09
30 changed files with 1388 additions and 588 deletions

View File

@ -28,8 +28,8 @@ function registerEvents(registry, events, tutorial) {
registry.set('activeSkill', skill); registry.set('activeSkill', skill);
} }
function setItems(items) { function setVbox(items) {
registry.set('itemList', items); registry.set('vbox', items);
} }
function setZone(zone) { function setZone(zone) {
@ -177,7 +177,7 @@ function registerEvents(registry, events, tutorial) {
setActiveSkill, setActiveSkill,
setCryps, setCryps,
setGame, setGame,
setItems, setVbox,
setWs, setWs,
setGameList, setGameList,
setZone, setZone,

View File

@ -85,9 +85,9 @@ class CrypImage extends Phaser.GameObjects.Image {
scene.add.text(nameX, nameY, cryp.name, TEXT.NORMAL).setOrigin(team, 0); scene.add.text(nameX, nameY, cryp.name, TEXT.NORMAL).setOrigin(team, 0);
// Add cryp stat bars // Add cryp stat bars
this.health = scene.add.existing(new StatBar(scene, this, 'HP')); this.health = scene.add.existing(new StatBar(scene, this, 'HP'));
this.armour = scene.add.existing(new StatBar(scene, this, 'Armour')); this.red_shield = scene.add.existing(new StatBar(scene, this, 'Red Shield'));
this.blue_shield = scene.add.existing(new StatBar(scene, this, 'Blue Shield'));
this.evasion = scene.add.existing(new StatBar(scene, this, 'Evasion')); this.evasion = scene.add.existing(new StatBar(scene, this, 'Evasion'));
this.spellShield = scene.add.existing(new StatBar(scene, this, 'Spell Shield'));
this.effects = scene.add.existing(new Effects(scene, team, iter)); this.effects = scene.add.existing(new Effects(scene, team, iter));
this.statusText = scene.add.text(statusX, statusY, '', TEXT.NORMAL); this.statusText = scene.add.text(statusX, statusY, '', TEXT.NORMAL);
@ -116,9 +116,9 @@ class CrypImage extends Phaser.GameObjects.Image {
reduceDefense(amount, type) { reduceDefense(amount, type) {
if (type === 'PhysDmg') { if (type === 'PhysDmg') {
this.armour.takeDamage(amount); this.red_shield.takeDamage(amount);
} else if (type === 'SpellDmg') { } else if (type === 'BlueDmg') {
this.spellShield.takeDamage(amount); this.blue_shield.takeDamage(amount);
} }
} }

View File

@ -17,8 +17,8 @@ const itemListWidth = () => Math.floor(CANVAS_WIDTH * 0.5);
const itemListHeight = () => Math.floor(CANVAS_HEIGHT * 0.5); const itemListHeight = () => Math.floor(CANVAS_HEIGHT * 0.5);
const itemListX = () => 0; const itemListX = () => 0;
const itemListY = () => Math.floor(CANVAS_HEIGHT * 0.5); const itemListY = () => Math.floor(CANVAS_HEIGHT * 0.5);
const itemBlockWidth = () => Math.floor(itemListWidth() * 0.1); const itemBlockWidth = () => Math.floor(itemListWidth() * 0.075);
const itemBlockHeight = () => Math.floor(itemListHeight() * 0.16); const itemBlockHeight = () => Math.floor(itemListHeight() * 0.12);
const menuNavigationWidth = () => Math.floor(CANVAS_WIDTH * 0.5); const menuNavigationWidth = () => Math.floor(CANVAS_WIDTH * 0.5);
const menuNavigationHeight = () => Math.floor(CANVAS_HEIGHT * 0.3); const menuNavigationHeight = () => Math.floor(CANVAS_HEIGHT * 0.3);
@ -162,31 +162,31 @@ module.exports = {
[ { name: 'Amplify', [ { name: 'Amplify',
description: 'increase the magic damage dealt by a cryp' }, description: 'increase the magic damage dealt by a cryp' },
{ name: 'Attack', { name: 'Attack',
description: 'a fast physical attack with phys dmg' }, description: 'a fast attack with red damage' },
{ name: 'Banish', { name: 'Banish',
description: description:
'target cryp is prevented from casting any skills and taking any damage' }, 'target cryp is prevented from casting any skills and taking any damage' },
{ name: 'Blast', { name: 'Blast',
description: 'blast the target with magic damage' }, description: 'blast the target with magic damage' },
{ name: 'Block', { name: 'Block',
description: 'decreases incoming physical damage for 1T' }, description: 'decreases incoming red damage for 1T' },
{ name: 'Curse', { name: 'Curse',
description: 'target cryp takes increased magic damage' }, description: 'target cryp takes increased magic damage' },
{ name: 'Decay', { name: 'Decay',
description: description:
'afflict a cryp with a spell damage based damage over time debuff' }, 'afflict a cryp with a blue damage based damage over time debuff' },
{ name: 'Drain', { name: 'Siphon',
description: 'drain hp from target cryp with a spell damage based debuff' }, description: 'siphon hp from target cryp with a blue damage based debuff' },
{ name: 'Empower', { name: 'Empower',
description: 'increase the physical damage dealt by a cryp' }, description: 'increase the red damage dealt by a cryp' },
{ name: 'Haste', { name: 'Haste',
description: 'magical skill that increases speed of target cryp' }, description: 'magical skill that increases speed of target cryp' },
{ name: 'Heal', description: 'heal a cryp with spell dmg' }, { name: 'Heal', description: 'heal a cryp with blue damage' },
{ name: 'Hex', { name: 'Hex',
description: description:
'magical based skill that prevents target cryp from using any skills' }, 'magical based skill that prevents target cryp from using any skills' },
{ name: 'Parry', { name: 'Parry',
description: 'prevents all physical damage for 1T' }, description: 'prevents all red damage for 1T' },
{ name: 'Purge', { name: 'Purge',
description: 'remove magical buffs from target cryp' }, description: 'remove magical buffs from target cryp' },
{ name: 'Purify', { name: 'Purify',
@ -198,14 +198,14 @@ module.exports = {
{ name: 'Slow', { name: 'Slow',
description: 'magical skill that reduces speed of target cryp' }, description: 'magical skill that reduces speed of target cryp' },
{ name: 'Snare', { name: 'Snare',
description: 'prevents physical skills from being used for 2T' }, description: 'prevents red skills from being used for 2T' },
{ name: 'Stun', { name: 'Stun',
description: description:
'physical skill that prevents target cryp from using any skills' }, 'red skill that prevents target cryp from using any skills' },
{ name: 'Throw', { name: 'Throw',
description: 'stuns and makes the target take increased physical damage' }, description: 'stuns and makes the target take increased red damage' },
{ name: 'Triage', { name: 'Triage',
description: 'grants a spell dmg based healing over time buff' } description: 'grants a blue damage based healing over time buff' }
] ]
}, },
}; };

View File

@ -29,7 +29,7 @@ function renderCryps() {
}, },
}, },
scene: [ scene: [
Background, // Background,
Header, Header,
], ],
}; };

View File

@ -24,22 +24,23 @@ class StatBar extends Phaser.GameObjects.Graphics {
super(scene); super(scene);
this.crypObj = cryp; this.crypObj = cryp;
this.type = type; this.type = type;
console.log(type);
if (type === 'HP') { if (type === 'HP') {
this.val = this.crypObj.cryp.hp.base; this.val = this.crypObj.cryp.hp.base;
this.max = this.crypObj.cryp.stamina.base; this.max = this.crypObj.cryp.hp.base;
this.margin = 0; this.margin = 0;
} else if (type === 'Armour') { } else if (type === 'Red Shield') {
this.val = this.crypObj.cryp.armour.base; this.val = this.crypObj.cryp.red_shield.base;
this.max = this.crypObj.cryp.armour.base; this.max = this.crypObj.cryp.red_shield.base;
this.margin = 1; this.margin = 1;
} else if (type === 'Blue Shield') {
this.val = this.crypObj.cryp.blue_shield.base;
this.max = this.crypObj.cryp.blue_shield.base;
this.margin = 2;
} else if (type === 'Evasion') { } else if (type === 'Evasion') {
this.val = this.crypObj.cryp.evasion.base; this.val = this.crypObj.cryp.evasion.base;
this.max = this.crypObj.cryp.evasion.base; this.max = this.crypObj.cryp.evasion.base;
this.margin = 2;
} else if (type === 'Spell Shield') {
this.val = this.crypObj.cryp.spell_shield.base;
this.max = this.crypObj.cryp.spell_shield.base;
this.margin = 3; this.margin = 3;
} }
const { statTextX, statTextY } = statTextCoord(cryp.team, cryp.iter, this.margin); const { statTextX, statTextY } = statTextCoord(cryp.team, cryp.iter, this.margin);

View File

@ -5,23 +5,36 @@ const {
COLOURS, COLOURS,
} = require('../constants'); } = require('../constants');
function FindColour(item) {
// Future add skills and use a constants lookup file ??
switch (item) {
case 'Green': return 0x61B329;
case 'Red': return 0xCC3333;
case 'Blue': return 0x6633FF;
default: return 0x222222;
}
}
class Item extends Phaser.GameObjects.Container { class Item extends Phaser.GameObjects.Container {
constructor(scene, action, count, x, y, width, height) { constructor(scene, item, index, x, y, width, height) {
super(scene, x, y); super(scene, x, y);
this.state = 'deselect'; this.state = 'deselect';
this.action = action;
this.scene = scene; this.scene = scene;
this.item = item;
this.index = index;
this.origX = x; this.origX = x;
this.origY = y; this.origY = y;
this.width = width;
this.height = height;
this.colour = FindColour(item);
this.box = scene.add this.box = scene.add
.rectangle(0, 0, width, height, 0x222222); .rectangle(0, 0, width, height, this.colour);
this.text = scene.add this.text = scene.add
// .text(0, 0, `${action} x${count}`, TEXT.NORMAL) // .text(0, 0, `${action} x${count}`, TEXT.NORMAL)
.text(0, 0, `x${count}`, TEXT.NORMAL) .text(0, 0, `${item}`, TEXT.NORMAL)
.setOrigin(0.5, 0.5); .setOrigin(0.5, 0.5);
this.add(this.box); this.add(this.box);
@ -31,10 +44,15 @@ class Item extends Phaser.GameObjects.Container {
this.setInteractive(); this.setInteractive();
} }
changeOrigin(x, y) {
this.origX = x + this.width / 2;
this.origY = y + this.height / 2;
}
clickHandler() { clickHandler() {
this.scene.activeItem = this; this.scene.activeItem = this;
// Set the main context to display the item info // Set the main context to display the item info
this.scene.registry.set('itemInfo', this.action); this.scene.registry.set('itemInfo', this.item);
this.select(); this.select();
} }
@ -42,7 +60,7 @@ class Item extends Phaser.GameObjects.Container {
this.scene.children.list.forEach((item) => { this.scene.children.list.forEach((item) => {
if (item.state === 'select') item.deselect(); if (item.state === 'select') item.deselect();
}); });
this.box.setFillStyle(COLOURS.SELECT); // this.box.setFillStyle(COLOURS.SELECT);
this.state = 'select'; this.state = 'select';
} }
@ -50,12 +68,12 @@ class Item extends Phaser.GameObjects.Container {
this.scene.children.list.forEach((item) => { this.scene.children.list.forEach((item) => {
if (item.state === 'select') item.deselect(); if (item.state === 'select') item.deselect();
}); });
this.box.setFillStyle(0xff0000); this.box.setFillStyle(0x222222);
this.state = 'activate'; this.state = 'activate';
} }
deselect() { deselect() {
this.box.setFillStyle(0x222222); this.box.setFillStyle(this.colour);
this.state = 'deselect'; this.state = 'deselect';
} }
} }

View File

@ -16,15 +16,34 @@ const ITEM_WIDTH = ITEM_LIST.itemWidth();
const ITEM_HEIGHT = ITEM_LIST.itemHeight(); const ITEM_HEIGHT = ITEM_LIST.itemHeight();
const INV_X = X + ITEM_WIDTH * 0.325; const INV_X = X + ITEM_WIDTH * 0.325;
const INV_Y = Y + ITEM_HEIGHT * 1.5; const INV_Y = Y + ITEM_HEIGHT;
const INV_ROWS = 3; const INV_ROWS = 3;
const INV_COLUMNS = 5; const INV_COLUMNS = 3;
const COMB_X = INV_X + ITEM_WIDTH * 6.75; const COMB_X = INV_X + ITEM_WIDTH * 5.75;
const COMB_Y = INV_Y; const COMB_Y = INV_Y;
const COMB_ROWS = 2; const COMB_ROWS = 2;
const COMB_COLUMNS = 2; const COMB_COLUMNS = 2;
const BOX_X = X + ITEM_WIDTH * 2;
const BOX_Y = Y + ITEM_HEIGHT * 5;
const BOX_ROWS = 3;
const BOX_COLUMNS = 6;
const drawVbox = (graphics) => {
const boxDrawX = BOX_X - ITEM_WIDTH * 0.05;
const boxDrawY = BOX_Y - ITEM_HEIGHT * 0.05;
for (let i = 0; i <= BOX_COLUMNS; i += 1) {
const x = boxDrawX + i * ITEM_WIDTH * 1.1;
graphics.lineBetween(x, boxDrawY, x, boxDrawY + ITEM_HEIGHT * 1.1 * BOX_ROWS);
}
for (let i = 0; i <= BOX_ROWS; i += 1) {
const y = boxDrawY + i * ITEM_HEIGHT * 1.1;
graphics.lineBetween(boxDrawX, y, boxDrawX + ITEM_WIDTH * 1.1 * BOX_COLUMNS, y);
}
};
const drawInventory = (graphics) => { const drawInventory = (graphics) => {
const invDrawX = INV_X - ITEM_WIDTH * 0.05; const invDrawX = INV_X - ITEM_WIDTH * 0.05;
const invDrawY = INV_Y - ITEM_HEIGHT * 0.05; const invDrawY = INV_Y - ITEM_HEIGHT * 0.05;
@ -55,16 +74,40 @@ class CombinerHitBox extends Phaser.GameObjects.Rectangle {
constructor(scene, x, y, i) { constructor(scene, x, y, i) {
super(scene, x, y, ITEM_WIDTH, ITEM_HEIGHT, 0x000000); super(scene, x, y, ITEM_WIDTH, ITEM_HEIGHT, 0x000000);
this.setOrigin(0); this.setOrigin(0);
this.x = x;
this.y = y;
this.slot = i; this.slot = i;
this.item = false;
this.itemSelect = () => this.setFillStyle(0x222222); this.itemSelect = () => this.setFillStyle(0x222222);
this.itemDeselect = () => this.setFillStyle(0x000000); this.itemDeselect = () => this.setFillStyle(0x000000);
} }
allocate(item) {
if (this.item) this.deallocate();
item.setPosition(this.x + item.width / 2, this.y + item.height / 2);
this.item = item;
}
deallocate() {
if (this.item) this.item.setPosition(this.item.origX, this.item.origY);
this.item = false;
}
} }
class DeleteHitBox extends Phaser.GameObjects.Rectangle {
constructor(scene, x, y) {
super(scene, x, y, ITEM_WIDTH * 1.25, ITEM_HEIGHT * 1.25, 0x222222);
this.setOrigin(0);
this.itemSelect = () => this.setFillStyle(0xff0000);
this.itemDeselect = () => this.setFillStyle(0x222222);
}
}
const itemCheckHitbox = (scene, pointer) => { const itemCheckHitbox = (scene, pointer) => {
const { list } = scene.scene.get('MenuCrypList').children; const { list } = scene.scene.get('MenuCrypList').children;
const hitboxes = list.filter(c => c.cryp) const hitboxes = list.filter(c => c.cryp)
.concat(scene.children.list.filter(c => c instanceof CombinerHitBox)); .concat(scene.children.list.filter(c => c instanceof CombinerHitBox || c instanceof DeleteHitBox));
let found; let found;
for (let i = 0; i < hitboxes.length; i += 1) { for (let i = 0; i < hitboxes.length; i += 1) {
@ -84,77 +127,165 @@ class ItemList extends Phaser.Scene {
} }
updateData(parent, key, data) { updateData(parent, key, data) {
if (key === 'itemList') { if (key === 'vbox') {
this.registry.events.off('changedata', this.updateData, this); this.registry.events.off('changedata', this.updateData, this);
this.registry.events.off('setdata', this.updateData, this); this.registry.events.off('setdata', this.updateData, this);
this.scene.restart(data); this.scene.restart(data);
} }
} }
create(itemList) { create(vbox) {
if (!itemList) return false;
this.registry.events.on('changedata', this.updateData, this); this.registry.events.on('changedata', this.updateData, this);
this.registry.events.on('setdata', this.updateData, this); this.registry.events.on('setdata', this.updateData, this);
this.addStatic(); if (!vbox.bound) return false;
this.addItems(itemList); this.combinerItems = this.registry.get('combinerItems');
this.addClickHandlers(itemList); if (!this.combinerItems || vbox.bound.length < this.registry.get('boundLength')) {
return this; this.combinerItems = [-1, -1, -1];
} }
this.registry.set('boundLength', vbox.bound.length);
const ws = this.registry.get('ws');
addStatic() { // Static Elements
const graphics = this.add.graphics(); const graphics = this.add.graphics();
graphics.lineStyle(5, 0x808080, 1.0); graphics.lineStyle(5, 0x808080, 1.0);
drawCombiner(graphics); drawCombiner(graphics);
drawInventory(graphics); drawInventory(graphics);
this.add.text(X + WIDTH / 4, Y + HEIGHT / 8, 'Inventory', TEXT.HEADER); drawVbox(graphics);
this.add.text(X + WIDTH * 3 / 4, Y + HEIGHT / 8, 'Combiner', TEXT.HEADER);
}
addItems(itemList) { this.add.text(X + WIDTH * 0.1, Y, 'Inventory', TEXT.HEADER);
const actions = countBy(itemList, i => i.action); this.add.text(X + WIDTH * 0.47, Y, 'Combiner', TEXT.HEADER);
this.add.text(X + WIDTH * 0.35, Y + HEIGHT / 2, 'Varibox', TEXT.HEADER);
for (let i = 0; i < (COMB_COLUMNS * COMB_ROWS); i += 1) { const reroll = this.add
const ITEM_X = ITEM_WIDTH * 1.1 * (i % COMB_COLUMNS) + INV_X + ITEM_WIDTH * 6.75; .rectangle(WIDTH * 0.01, Y + HEIGHT * 0.775, ITEM_WIDTH * 1.25, ITEM_HEIGHT * 1.25, 0x222222)
const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / COMB_COLUMNS) + INV_Y; .setInteractive()
.setOrigin(0)
.on('pointerdown', () => this.registry.get('ws').sendVboxDiscard(vbox.game));
this.add.text(reroll.getCenter().x, reroll.getCenter().y, 'Reroll', TEXT.HEADER)
.setOrigin(0.5, 0.5);
const combine = this.add
.rectangle(ITEM_WIDTH * 1.1 + COMB_X, ITEM_HEIGHT * 1.1 + COMB_Y, ITEM_WIDTH, ITEM_HEIGHT, 0x222222)
.setInteractive()
.setOrigin(0)
.on('pointerdown', () => {
ws.sendVboxCombine(vbox.game, this.combinerItems);
this.combinerItems = [-1, -1, -1];
this.children.list.filter(obj => obj instanceof CombinerHitBox).forEach(cBox => cBox.deallocate());
});
this.add.text(combine.getCenter().x, combine.getCenter().y, 'C', TEXT.HEADER)
.setOrigin(0.5, 0.5);
for (let i = 0; i < 3; i += 1) {
const ITEM_X = ITEM_WIDTH * 1.1 * (i % COMB_COLUMNS) + COMB_X;
const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / COMB_COLUMNS) + COMB_Y;
this.add.existing(new CombinerHitBox(this, ITEM_X, ITEM_Y, i)); this.add.existing(new CombinerHitBox(this, ITEM_X, ITEM_Y, i));
} }
const del = this.add.existing(new DeleteHitBox(this, WIDTH * 0.01, Y + HEIGHT * 0.6));
this.add.text(del.getCenter().x, del.getCenter().y, 'Del', TEXT.HEADER)
.setOrigin(0.5, 0.5);
Object.keys(actions).forEach((action, i) => { // Generate Items
vbox.bound.forEach((action, i) => {
const ITEM_X = ITEM_WIDTH * 1.1 * (i % INV_COLUMNS) + INV_X + ITEM_WIDTH * 0.5; const ITEM_X = ITEM_WIDTH * 1.1 * (i % INV_COLUMNS) + INV_X + ITEM_WIDTH * 0.5;
const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / INV_COLUMNS) + INV_Y + ITEM_HEIGHT * 0.5; const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / INV_COLUMNS) + INV_Y + ITEM_HEIGHT * 0.5;
const itemBox = new Item(this, action, actions[action], ITEM_X, ITEM_Y, ITEM_WIDTH, ITEM_HEIGHT); const itemBox = new Item(this, action, i, ITEM_X, ITEM_Y, ITEM_WIDTH, ITEM_HEIGHT);
this.input.setDraggable(itemBox); this.input.setDraggable(itemBox);
this.add.existing(itemBox); this.add.existing(itemBox);
}); });
}
addClickHandlers(itemList) { vbox.free.forEach((action, i) => {
const ws = this.registry.get('ws'); const ITEM_X = ITEM_WIDTH * 1.1 * (i % BOX_COLUMNS) + BOX_X + ITEM_WIDTH * 0.5;
this.input.on('dragstart', (pointer, box) => { const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / BOX_COLUMNS) + BOX_Y + ITEM_HEIGHT * 0.5;
if (!(box instanceof Item)) return false; const itemBox = new Item(this, action, i, ITEM_X, ITEM_Y, ITEM_WIDTH, ITEM_HEIGHT);
box.clickHandler(); itemBox
.setInteractive()
.on('pointerdown', () => {
ws.sendVboxAccept(vbox.game, i);
});
this.add.existing(itemBox);
});
// Restore previous combiner item slots
this.combinerItems.forEach((index, i) => {
if (index === -1) return false;
const item = this.children.list.filter(obj => obj instanceof Item).find(it => it.index === index);
const hitBox = this.children.list.filter(obj => obj instanceof CombinerHitBox).find(hb => hb.slot === i);
hitBox.allocate(item);
return true; return true;
}); });
this.input.on('drag', (pointer, box, dragX, dragY) => { // allocation functions
if (!(box instanceof Item)) return false; const allocate = (item, hitBox) => {
box.setPosition(dragX, dragY); hitBox.allocate(item);
this.combinerItems[hitBox.slot] = item.index;
this.registry.set('combinerItems', this.combinerItems);
};
const deallocate = (item) => {
const clearIndex = this.combinerItems.indexOf(item.index);
if (clearIndex !== -1) {
this.children.list.filter(obj => obj instanceof CombinerHitBox)
.forEach((cBox) => {
if (cBox.item === item) cBox.deallocate();
});
this.combinerItems[clearIndex] = -1;
}
item.setPosition(item.origX, item.origY);
};
const findUnallocated = () => {
for (let i = 0; i <= 2; i += 1) {
if (this.combinerItems[i] === -1) {
return this.children.list.filter(obj => obj instanceof CombinerHitBox).find(hb => hb.slot === i);
}
} return false;
};
// Add Handlers
this.input.on('dragstart', (pointer, item) => {
if (!(item instanceof Item)) return false;
item.clickHandler();
return true;
});
this.input.on('drag', (pointer, item, dragX, dragY) => {
if (!(item instanceof Item)) return false;
item.setPosition(dragX, dragY);
const hitBox = itemCheckHitbox(this, pointer); const hitBox = itemCheckHitbox(this, pointer);
if (hitBox) hitBox.itemSelect(); if (hitBox) hitBox.itemSelect();
return true; return true;
}); });
this.input.on('dragend', (pointer, box) => { this.input.on('dragend', (pointer, item) => {
if (!(box instanceof Item)) return false; if (!(item instanceof Item)) return false;
box.deselect();
item.deselect();
// Allocate to combiner if clicked without movement form inventory (return 0)
if (!Math.hypot(item.x - item.origX, item.y - item.origY)) {
const cBox = findUnallocated();
if (cBox) allocate(item, cBox);
return true;
}
// Check for hitboxes
const hitBox = itemCheckHitbox(this, pointer); const hitBox = itemCheckHitbox(this, pointer);
box.setPosition(box.origX, box.origY); if (hitBox) {
if (!hitBox) return false; hitBox.itemDeselect();
if (hitBox instanceof CombinerHitBox) console.log(`Moved item into slot ${hitBox.slot}`); // Allocate to specific combiner slot
else ws.sendItemUse(itemList.find(li => li.action === box.action).id, hitBox.cryp.id); if (hitBox instanceof CombinerHitBox) {
hitBox.itemDeselect(); allocate(item, hitBox);
return true;
}
// Allocate to cryp hitbox
if (hitBox instanceof DeleteHitBox) ws.sendVboxDrop(vbox.game, item.index);
else ws.sendVboxApply(vbox.game, hitBox.cryp.id, item.index);
}
// If the item hasn't been allocated deallocate the item
// Scene will restart if there is vbox change
deallocate(item);
return true; return true;
}); });
return this;
} }
cleanUp() { cleanUp() {

View File

@ -113,10 +113,10 @@ class MenuCrypList extends Phaser.Scene {
.setOrigin(0.5, 0.5)); .setOrigin(0.5, 0.5));
const CRYP_STATS = [ const CRYP_STATS = [
cryp.stamina, cryp.stamina,
cryp.armour, cryp.red_shield,
cryp.spell_shield, cryp.blue_shield,
cryp.phys_dmg, cryp.red_damage,
cryp.spell_dmg, cryp.blue_damage,
cryp.speed, cryp.speed,
]; ];
CRYP_STATS.forEach((stat, j) => crypStat(stat, j, crypInfo)); CRYP_STATS.forEach((stat, j) => crypStat(stat, j, crypInfo));

View File

@ -25,6 +25,7 @@ const MAIN_MENU_SCENES = [
'ItemInfo', 'ItemInfo',
]; ];
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
class Menu extends Phaser.Scene { class Menu extends Phaser.Scene {
constructor() { constructor() {
@ -37,7 +38,7 @@ class Menu extends Phaser.Scene {
// When we load the menu request the latest items // When we load the menu request the latest items
// Item list will restart when the data comes in // Item list will restart when the data comes in
this.registry.get('ws').sendAccountItems(); this.registry.get('ws').sendVboxState(NULL_UUID);
this.scene.manager.add('MenuCrypList', MenuCrypList, true); this.scene.manager.add('MenuCrypList', MenuCrypList, true);
this.scene.manager.add('MenuNavigation', MenuNavigation, true); this.scene.manager.add('MenuNavigation', MenuNavigation, true);

View File

@ -2,79 +2,79 @@ const passiveNodes = [
{ x: 860, y: 1011, id: 'CMED1', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Slow Effect'}, { x: 860, y: 1011, id: 'CMED1', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Slow Effect'},
{ x: 905, y: 970, id: 'CSTAT7', alloc: false, text: '+2 Chaos Stat'}, { x: 905, y: 970, id: 'CSTAT7', alloc: false, text: '+2 Chaos Stat'},
{ x: 940, y: 917.5, id: 'CSTAT8', alloc: false, text: '+2 Chaos Stat'}, { x: 940, y: 917.5, id: 'CSTAT8', alloc: false, text: '+2 Chaos Stat'},
{ x: 950, y: 1172.5, id: 'CMED2', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Speed for Healing Skills'}, { x: 950, y: 1172.5, id: 'CMED2', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Speed for Healing Skills'},
{ x: 955, y: 1120, id: 'CSDMG1', alloc: false, text: '+5% Increased Spell Damage'}, { x: 955, y: 1120, id: 'CSDMG1', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 965, y: 1082.5, id: 'CSDMG2', alloc: false, text: '+5% Increased Spell Damage'}, { x: 965, y: 1082.5, id: 'CSDMG2', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 970, y: 872.5, id: 'CSTAT9', alloc: false, text: '+2 Chaos Stat'}, { x: 970, y: 872.5, id: 'CSTAT9', alloc: false, text: '+2 Chaos Stat'},
{ x: 975, y: 1012.5, id: 'CSTAT6', alloc: false, text: '+2 Chaos Stat'}, { x: 975, y: 1012.5, id: 'CSTAT6', alloc: false, text: '+2 Chaos Stat'},
{ x: 995, y: 1062.5, id: 'CSDMG3', alloc: false, text: '+5% Increased Spell Damage'}, { x: 995, y: 1062.5, id: 'CSDMG3', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1000, y: 1150, id: 'CHEAL1', alloc: false, text: '+5% Increased Healing'}, { x: 1000, y: 1150, id: 'CHEAL1', alloc: false, text: '+5% Increased Healing'},
{ x: 1005, y: 812.5, id: 'CMED20', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'}, { x: 1005, y: 812.5, id: 'CMED20', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'},
{ x: 1024.5, y: 1122.5, id: 'CHEAL2', alloc: false, text: '+5% Increased Healing'}, { x: 1024.5, y: 1122.5, id: 'CHEAL2', alloc: false, text: '+5% Increased Healing'},
{ x: 1036.5, y: 896.5, id: 'CMED19', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'}, { x: 1036.5, y: 896.5, id: 'CMED19', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'},
{ x: 1036.5, y: 1042.5, id: 'CMED18', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Speed for Healing Skills'}, { x: 1036.5, y: 1042.5, id: 'CMED18', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Speed for Healing Skills'},
{ x: 1036.5, y: 1082.5, id: 'CHEAL3', alloc: false, text: '+5% Increased Healing'}, { x: 1036.5, y: 1082.5, id: 'CHEAL3', alloc: false, text: '+5% Increased Healing'},
{ x: 1041.5, y: 772.5, id: 'CSTAT10', alloc: false, text: '+2 Chaos Stat'}, { x: 1041.5, y: 772.5, id: 'CSTAT10', alloc: false, text: '+2 Chaos Stat'},
{ x: 1055, y: 1327.5, id: 'CMED3', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Speed for Banish Skills'}, { x: 1055, y: 1327.5, id: 'CMED3', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Speed for Banish Skills'},
{ x: 1066.5, y: 939.5, id: 'CHEAL5', alloc: false, text: '+5% Increased Healing'}, { x: 1066.5, y: 939.5, id: 'CHEAL5', alloc: false, text: '+5% Increased Healing'},
{ x: 1067.5, y: 995, id: 'CHEAL4', alloc: false, text: '+5% Increased Healing'}, { x: 1067.5, y: 995, id: 'CHEAL4', alloc: false, text: '+5% Increased Healing'},
{ x: 1070, y: 1250, id: 'CSTAT4', alloc: false, text: '+2 Chaos Stat'}, { x: 1070, y: 1250, id: 'CSTAT4', alloc: false, text: '+2 Chaos Stat'},
{ x: 1072.5, y: 840.5, id: 'CHEAL8', alloc: false, text: '+5% Increased Healing'}, { x: 1072.5, y: 840.5, id: 'CHEAL8', alloc: false, text: '+5% Increased Healing'},
{ x: 1087.5, y: 700, id: 'CSTAT11', alloc: false, text: '+2 Chaos Stat'}, { x: 1087.5, y: 700, id: 'CSTAT11', alloc: false, text: '+2 Chaos Stat'},
{ x: 1097.5, y: 1052.5, id: 'CSDMG4', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1097.5, y: 1052.5, id: 'CSDMG4', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1102.5, y: 1140, id: 'CSTAT5', alloc: false, text: '+2 Chaos Stat'}, { x: 1102.5, y: 1140, id: 'CSTAT5', alloc: false, text: '+2 Chaos Stat'},
{ x: 1102.5, y: 917.5, id: 'CHEAL6', alloc: false, text: '+5% Increased Healing'}, { x: 1102.5, y: 917.5, id: 'CHEAL6', alloc: false, text: '+5% Increased Healing'},
{ x: 1115, y: 1332.5, id: 'CSTAT1', alloc: false, text: '+2 Chaos Stat'}, { x: 1115, y: 1332.5, id: 'CSTAT1', alloc: false, text: '+2 Chaos Stat'},
{ x: 1115, y: 875, id: 'CHEAL7', alloc: false, text: '+5% Increased Healing'}, { x: 1115, y: 875, id: 'CHEAL7', alloc: false, text: '+5% Increased Healing'},
{ x: 1130, y: 640, id: 'CSTAT12', alloc: false, text: '+2 Chaos Stat'}, { x: 1130, y: 640, id: 'CSTAT12', alloc: false, text: '+2 Chaos Stat'},
{ x: 1145, y: 1287.5, id: 'CSTAT3', alloc: false, text: '+2 Chaos Stat'}, { x: 1145, y: 1287.5, id: 'CSTAT3', alloc: false, text: '+2 Chaos Stat'},
{ x: 1145, y: 1057.5, id: 'CSDMG5', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1145, y: 1057.5, id: 'CSDMG5', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1175, y: 1332.5, id: 'CSTAT2', alloc: false, text: '+2 Chaos Stat'}, { x: 1175, y: 1332.5, id: 'CSTAT2', alloc: false, text: '+2 Chaos Stat'},
{ x: 1180, y: 1247.5, id: 'CMED10', alloc: false, text: '5% Increased Speed for Banish Spells, 5% Increased Stamina'}, { x: 1180, y: 1247.5, id: 'CMED10', alloc: false, text: '5% Increased Speed for Banish Blues, 5% Increased Stamina'},
{ x: 1180, y: 950, id: 'CMED14', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Speed for Banish Skills'}, { x: 1180, y: 950, id: 'CMED14', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Speed for Banish Skills'},
{ x: 1195, y: 875, id: 'CHEAL9', alloc: false, text: '+5% Increased Healing'}, { x: 1195, y: 875, id: 'CHEAL9', alloc: false, text: '+5% Increased Healing'},
{ x: 1196.5, y: 635, id: 'CMED21', alloc: false, text: '5% Increased Effect of Slow, 5% Increased Stamina'}, { x: 1196.5, y: 635, id: 'CMED21', alloc: false, text: '5% Increased Effect of Slow, 5% Increased Stamina'},
{ x: 1205, y: 1062.5, id: 'CSDMG6', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1205, y: 1062.5, id: 'CSDMG6', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1212.5, y: 1200, id: 'CHEAL14', alloc: false, text: '+5% Increased Healing'}, { x: 1212.5, y: 1200, id: 'CHEAL14', alloc: false, text: '+5% Increased Healing'},
{ x: 1231.5, y: 590, id: 'CSTAT14', alloc: false, text: '+2 Chaos Stat'}, { x: 1231.5, y: 590, id: 'CSTAT14', alloc: false, text: '+2 Chaos Stat'},
{ x: 1235, y: 772.5, id: 'CHEAL12', alloc: false, text: '+5% Increased Healing'}, { x: 1235, y: 772.5, id: 'CHEAL12', alloc: false, text: '+5% Increased Healing'},
{ x: 1240, y: 1225, id: 'CPHYS1', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1240, y: 1225, id: 'CPHYS1', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1240, y: 1322.5, id: 'CMED4', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Stamina'}, { x: 1240, y: 1322.5, id: 'CMED4', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Stamina'},
{ x: 1258.5, y: 1107.5, id: 'CHEAL15', alloc: false, text: '+5% Increased Healing'}, { x: 1258.5, y: 1107.5, id: 'CHEAL15', alloc: false, text: '+5% Increased Healing'},
{ x: 1260, y: 917.5, id: 'CHEAL10', alloc: false, text: '+5% Increased Healing'}, { x: 1260, y: 917.5, id: 'CHEAL10', alloc: false, text: '+5% Increased Healing'},
{ x: 1263, y: 520, id: 'CLRG4', alloc: false, text: 'Damaging spells have a 20% chance to inflict slow'}, { x: 1263, y: 520, id: 'CLRG4', alloc: false, text: 'Damaging blues have a 20% chance to inflict slow'},
{ x: 1273.5, y: 1057.5, id: 'CMED13', alloc: false, text: '5% Increased Speed for Banish Spells, 5% Increased Speed for Damaging Spells'}, { x: 1273.5, y: 1057.5, id: 'CMED13', alloc: false, text: '5% Increased Speed for Banish Blues, 5% Increased Speed for Damaging Blues'},
{ x: 1275, y: 1167.5, id: 'CMED11', alloc: false, text: '5% Increased Speed for Banish Spells, 5% Increased Stamina'}, { x: 1275, y: 1167.5, id: 'CMED11', alloc: false, text: '5% Increased Speed for Banish Blues, 5% Increased Stamina'},
{ x: 1275, y: 947.5, id: 'CMED15', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Speed for Damaging Spells'}, { x: 1275, y: 947.5, id: 'CMED15', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Speed for Damaging Blues'},
{ x: 1277.5, y: 872.5, id: 'CMED16', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Speed for Healing Skills'}, { x: 1277.5, y: 872.5, id: 'CMED16', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Speed for Healing Skills'},
{ x: 1278.5, y: 812.5, id: 'CHEAL11', alloc: false, text: '+5% Increased Healing'}, { x: 1278.5, y: 812.5, id: 'CHEAL11', alloc: false, text: '+5% Increased Healing'},
{ x: 1280, y: 732.5, id: 'CHEAL13', alloc: false, text: '+5% Increased Healing'}, { x: 1280, y: 732.5, id: 'CHEAL13', alloc: false, text: '+5% Increased Healing'},
{ x: 1281.5, y: 1002.5, id: 'CSDMG7', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1281.5, y: 1002.5, id: 'CSDMG7', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1284, y: 640, id: 'CSTAT15', alloc: false, text: '+2 Chaos Stat'}, { x: 1284, y: 640, id: 'CSTAT15', alloc: false, text: '+2 Chaos Stat'},
{ x: 1298.5, y: 1107.5, id: 'CPHYS4', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1298.5, y: 1107.5, id: 'CPHYS4', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1302.5, y: 917.5, id: 'CSDMG8', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1302.5, y: 917.5, id: 'CSDMG8', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1305, y: 1307.5, id: 'CPHYS2', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1305, y: 1307.5, id: 'CPHYS2', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1306, y: 1347.5, id: 'CSDMG10', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1306, y: 1347.5, id: 'CSDMG10', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1315, y: 762.5, id: 'CMED17', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'}, { x: 1315, y: 762.5, id: 'CMED17', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'},
{ x: 1326.5, y: 590, id: 'CSTAT16', alloc: false, text: '+2 Chaos Stat'}, { x: 1326.5, y: 590, id: 'CSTAT16', alloc: false, text: '+2 Chaos Stat'},
{ x: 1346.5, y: 635, id: 'CMED22', alloc: false, text: '5% Increased Effect of Slow, 5% Increased Stamina'}, { x: 1346.5, y: 635, id: 'CMED22', alloc: false, text: '5% Increased Effect of Slow, 5% Increased Stamina'},
{ x: 1348.5, y: 535, id: 'CSTAT13', alloc: false, text: '+2 Chaos Stat'}, { x: 1348.5, y: 535, id: 'CSTAT13', alloc: false, text: '+2 Chaos Stat'},
{ x: 1355, y: 1322.5, id: 'CMED5', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Stamina'}, { x: 1355, y: 1322.5, id: 'CMED5', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Stamina'},
{ x: 1360, y: 1002.5, id: 'CSDMG9', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1360, y: 1002.5, id: 'CSDMG9', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1399.5, y: 1107.5, id: 'CPHYS5', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1399.5, y: 1107.5, id: 'CPHYS5', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1400, y: 807.5, id: 'CMED24', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Speed for Healing Skills'}, { x: 1400, y: 807.5, id: 'CMED24', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Speed for Healing Skills'},
{ x: 1409.5, y: 1312.5, id: 'CPHYS3', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1409.5, y: 1312.5, id: 'CPHYS3', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1410, y: 1347.5, id: 'CSDMG11', alloc: false, text: '+5% Increased Spell Damage'}, { x: 1410, y: 1347.5, id: 'CSDMG11', alloc: false, text: '+5% Increased Blue Damage'},
{ x: 1410, y: 532.5, id: 'CMED23', alloc: false, text: '5% Increased Speed for Banish Spells, 5% Increased Effect of Slow'}, { x: 1410, y: 532.5, id: 'CMED23', alloc: false, text: '5% Increased Speed for Banish Blues, 5% Increased Effect of Slow'},
{ x: 1420, y: 732.5, id: 'CSTAT19', alloc: false, text: '+2 Chaos Stat'}, { x: 1420, y: 732.5, id: 'CSTAT19', alloc: false, text: '+2 Chaos Stat'},
{ x: 1430, y: 1205, id: 'CPHYS7', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1430, y: 1205, id: 'CPHYS7', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1447.5, y: 765, id: 'CMED25', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Speed for Healing Skills'}, { x: 1447.5, y: 765, id: 'CMED25', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Speed for Healing Skills'},
{ x: 1452.5, y: 1322.5, id: 'CMED6', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Stamina'}, { x: 1452.5, y: 1322.5, id: 'CMED6', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Stamina'},
{ x: 1455, y: 1267.5, id: 'CSTAT33', alloc: false, text: '+2 Chaos Stat'}, { x: 1455, y: 1267.5, id: 'CSTAT33', alloc: false, text: '+2 Chaos Stat'},
{ x: 1455, y: 1147.5, id: 'CMED12', alloc: false, text: '5% Increased Speed for Banish Spells, 5% Increased Stamina'}, { x: 1455, y: 1147.5, id: 'CMED12', alloc: false, text: '5% Increased Speed for Banish Blues, 5% Increased Stamina'},
{ x: 1455, y: 1042.5, id: 'CSTAT35', alloc: false, text: '+2 Chaos Stat'}, { x: 1455, y: 1042.5, id: 'CSTAT35', alloc: false, text: '+2 Chaos Stat'},
{ x: 1457.5, y: 975, id: 'CSTAT37', alloc: false, text: '+2 Chaos Stat'}, { x: 1457.5, y: 975, id: 'CSTAT37', alloc: false, text: '+2 Chaos Stat'},
{ x: 1462.5, y: 825, id: 'CLRG3', alloc: false, text: '20% critical strike chance for spells'}, { x: 1462.5, y: 825, id: 'CLRG3', alloc: false, text: '20% critical strike chance for blues'},
{ x: 1485, y: 640, id: 'CSTAT17', alloc: false, text: '+2 Chaos Stat'}, { x: 1485, y: 640, id: 'CSTAT17', alloc: false, text: '+2 Chaos Stat'},
{ x: 1500, y: 1110, id: 'CPHYS6', alloc: false, text: '+2% Reduced Physical Damage Taken'}, { x: 1500, y: 1110, id: 'CPHYS6', alloc: false, text: '+2% Reduced Physical Damage Taken'},
{ x: 1505, y: 1242.5, id: 'CSTAT32', alloc: false, text: '+2 Chaos Stat'}, { x: 1505, y: 1242.5, id: 'CSTAT32', alloc: false, text: '+2 Chaos Stat'},
@ -85,8 +85,8 @@ const passiveNodes = [
{ x: 1555, y: 732.5, id: 'CSTAT18', alloc: false, text: '+2 Chaos Stat'}, { x: 1555, y: 732.5, id: 'CSTAT18', alloc: false, text: '+2 Chaos Stat'},
{ x: 1597.5, y: 827.5, id: 'CSTAT21', alloc: false, text: '+2 Chaos Stat'}, { x: 1597.5, y: 827.5, id: 'CSTAT21', alloc: false, text: '+2 Chaos Stat'},
{ x: 1607.5, y: 1277.5, id: 'CSTAT30', alloc: false, text: '+2 Chaos Stat'}, { x: 1607.5, y: 1277.5, id: 'CSTAT30', alloc: false, text: '+2 Chaos Stat'},
{ x: 1612.5, y: 1137.5, id: 'CLRG1', alloc: false, text: 'When you take physical damage there is a 20% chance to heal for 150% of physical damage taken'}, { x: 1612.5, y: 1137.5, id: 'CLRG1', alloc: false, text: 'When you take red damage there is a 20% chance to heal for 150% of red damage taken'},
{ x: 1612.5, y: 955, id: 'CLRG2', alloc: false, text: 'Your healing spells have a 20% chance to increase ally speed by 100%'}, { x: 1612.5, y: 955, id: 'CLRG2', alloc: false, text: 'Your healing blues have a 20% chance to increase ally speed by 100%'},
{ x: 1657.5, y: 822.5, id: 'CSTAT22', alloc: false, text: '+2 Chaos Stat'}, { x: 1657.5, y: 822.5, id: 'CSTAT22', alloc: false, text: '+2 Chaos Stat'},
{ x: 1657.5, y: 1312.5, id: 'CSTAT29', alloc: false, text: '+2 Chaos Stat'}, { x: 1657.5, y: 1312.5, id: 'CSTAT29', alloc: false, text: '+2 Chaos Stat'},
{ x: 1685, y: 1187.5, id: 'CSTAT27', alloc: false, text: '+2 Chaos Stat'}, { x: 1685, y: 1187.5, id: 'CSTAT27', alloc: false, text: '+2 Chaos Stat'},
@ -94,7 +94,7 @@ const passiveNodes = [
{ x: 1690, y: 1117.5, id: 'CSTAT26', alloc: false, text: '+2 Chaos Stat'}, { x: 1690, y: 1117.5, id: 'CSTAT26', alloc: false, text: '+2 Chaos Stat'},
{ x: 1705, y: 960, id: 'CSTAT24', alloc: false, text: '+2 Chaos Stat'}, { x: 1705, y: 960, id: 'CSTAT24', alloc: false, text: '+2 Chaos Stat'},
{ x: 1712.5, y: 850, id: 'CMED9', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'}, { x: 1712.5, y: 850, id: 'CMED9', alloc: false, text: '5% Increased Speed for Healing skills, 5% Increased Stamina'},
{ x: 1717.5, y: 1267.5, id: 'CMED7', alloc: false, text: '5% Increased Speed for Damaging Spells, 5% Increased Stamina'}, { x: 1717.5, y: 1267.5, id: 'CMED7', alloc: false, text: '5% Increased Speed for Damaging Blues, 5% Increased Stamina'},
{ x: 1725, y: 1222.5, id: 'CSTAT28', alloc: false, text: '+2 Chaos Stat'}, { x: 1725, y: 1222.5, id: 'CSTAT28', alloc: false, text: '+2 Chaos Stat'},
{ x: 1727.5, y: 1062.5, id: 'CMED8', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Speed for Banish Skills'}, { x: 1727.5, y: 1062.5, id: 'CMED8', alloc: false, text: '5% Increased Speed for Chaos Slow skills, 5% Increased Speed for Banish Skills'},
{ x: 1737.5, y: 917.5, id: 'CSTAT23', alloc: false, text: '+2 Chaos Stat'}, { x: 1737.5, y: 917.5, id: 'CSTAT23', alloc: false, text: '+2 Chaos Stat'},

View File

@ -66,11 +66,11 @@ class StatSheet extends Phaser.Scene {
const CRYP_STATS = [ const CRYP_STATS = [
cryp.stamina, cryp.stamina,
cryp.armour, cryp.red_shield,
cryp.spell_shield, cryp.blue_shield,
cryp.evasion, cryp.evasion,
cryp.phys_dmg, cryp.red_damage,
cryp.spell_dmg, cryp.blue_damage,
cryp.speed, cryp.speed,
]; ];

View File

@ -1,6 +1,7 @@
const toast = require('izitoast'); const toast = require('izitoast');
const cbor = require('borc'); const cbor = require('borc');
const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://cryps.gg/ws' : 'ws://localhost:40000'; const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://cryps.gg/ws' : 'ws://localhost:40000';
function errorToast(err) { function errorToast(err) {
@ -44,10 +45,6 @@ function createSocket(events) {
send({ method: 'account_cryps', params: {} }); send({ method: 'account_cryps', params: {} });
} }
function sendAccountItems() {
send({ method: 'account_items', params: {} });
}
function sendAccountZone() { function sendAccountZone() {
send({ method: 'account_zone', params: {} }); send({ method: 'account_zone', params: {} });
} }
@ -88,6 +85,31 @@ function createSocket(events) {
send({ method: 'cryp_unspec', params: { id, spec } }); send({ method: 'cryp_unspec', params: { id, spec } });
} }
function sendVboxState(gameId) {
send({ method: 'vbox_state', params: { game_id: gameId } });
}
function sendVboxAccept(gameId, i) {
send({ method: 'vbox_accept', params: { game_id: gameId, index: i } });
}
function sendVboxApply(gameId, crypId, index) {
send({ method: 'vbox_apply', params: { game_id: gameId, cryp_id: crypId, index } });
}
function sendVboxDiscard(gameId) {
send({ method: 'vbox_discard', params: { game_id: gameId } });
}
function sendVboxCombine(gameId, indices) {
send({ method: 'vbox_combine', params: { game_id: gameId, indices } });
}
function sendVboxDrop(gameId, index) {
send({ method: 'vbox_drop', params: { game_id: gameId, index } });
}
function sendPressR() { function sendPressR() {
send({ method: 'press_r', params: { } }); send({ method: 'press_r', params: { } });
@ -110,10 +132,6 @@ function createSocket(events) {
events.setActiveSkill(null); events.setActiveSkill(null);
} }
function sendItemUse(item, target) {
send({ method: 'item_use', params: { item, target } });
}
function sendZoneCreate() { function sendZoneCreate() {
send({ method: 'zone_create', params: {} }); send({ method: 'zone_create', params: {} });
} }
@ -136,7 +154,7 @@ function createSocket(events) {
account = login; account = login;
events.setAccount(login); events.setAccount(login);
sendAccountCryps(); sendAccountCryps();
sendGameJoinableList(); // sendGameJoinableList();
} }
function accountCryps(response) { function accountCryps(response) {
@ -162,16 +180,17 @@ function createSocket(events) {
const [structName, game] = response; const [structName, game] = response;
} }
function accountItems(response) {
const [structName, items] = response;
events.setItems(items);
}
function zoneState(response) { function zoneState(response) {
const [structName, zone] = response; const [structName, zone] = response;
events.setZone(zone); events.setZone(zone);
} }
function vboxState(response) {
const [structName, vbox] = response;
console.log(vbox);
events.setVbox(vbox);
}
// ------------- // -------------
// Setup // Setup
// ------------- // -------------
@ -188,11 +207,10 @@ function createSocket(events) {
account_login: accountLogin, account_login: accountLogin,
account_create: accountLogin, account_create: accountLogin,
account_cryps: accountCryps, account_cryps: accountCryps,
account_items: accountItems,
zone_create: res => console.log(res), zone_create: res => console.log(res),
zone_state: zoneState, zone_state: zoneState,
zone_close: res => console.log(res), zone_close: res => console.log(res),
vbox_state: vboxState,
}; };
function errHandler(error) { function errHandler(error) {
@ -268,7 +286,6 @@ function createSocket(events) {
sendAccountCreate, sendAccountCreate,
sendAccountDemo, sendAccountDemo,
sendAccountCryps, sendAccountCryps,
sendAccountItems,
sendAccountZone, sendAccountZone,
sendGameState, sendGameState,
sendGamePve, sendGamePve,
@ -280,11 +297,16 @@ function createSocket(events) {
sendCrypSpawn, sendCrypSpawn,
sendCrypLearn, sendCrypLearn,
sendCrypForget, sendCrypForget,
sendItemUse,
sendSpecForget, sendSpecForget,
sendZoneCreate, sendZoneCreate,
sendZoneJoin, sendZoneJoin,
sendZoneClose, sendZoneClose,
sendVboxState,
sendVboxAccept,
sendVboxApply,
sendVboxDrop,
sendVboxCombine,
sendVboxDiscard,
connect, connect,
}; };
} }

View File

@ -19,7 +19,7 @@ This homepage shows your cryps, joinable online games, PVE options and your item
If you have no cryps yet, press SPAWN and give your cryp a name to create one. If you have no cryps yet, press SPAWN and give your cryp a name to create one.
Once you have made a cryp, click on them to visit their stat page and teach them some SKILLS. Once you have made a cryp, click on them to visit their stat page and teach them some SKILLS.
The stat page also has descriptions of each skill and their effects. The stat page also has descriptions of each skill and their effects.
cryps have 3 basic stats: stamina, physical damage and magic damage. cryps have 3 basic stats: stamina, red damage and magic damage.
Toggle whether a cryp is selected for your team by clicking the coloured stripes next to the cryp or press 1,2,3. Toggle whether a cryp is selected for your team by clicking the coloured stripes next to the cryp or press 1,2,3.
Once you have a team ready press the New PVE Game button to start playing. Once you have a team ready press the New PVE Game button to start playing.
`; `;
@ -29,7 +29,7 @@ A cryps battle has two main phases. This first phase is called the SKILL PHASE.
Your cryps are positioned on the left, your opponent's are on the right. Your cryps are positioned on the left, your opponent's are on the right.
In the centre are your cryps' SKILLS, grayed out SKILLS are currently ON COOLDOWN. In the centre are your cryps' SKILLS, grayed out SKILLS are currently ON COOLDOWN.
A skill's cooldown reduces on every turn that cryp does not use a skill with a cooldown. A skill's cooldown reduces on every turn that cryp does not use a skill with a cooldown.
For the moment, drag ATTACK onto the opponent team to have your cryps attack them with physical damage. For the moment, drag ATTACK onto the opponent team to have your cryps attack them with red damage.
`; `;
// const TARGET_PHASE_MESSAGE = ` // const TARGET_PHASE_MESSAGE = `

View File

@ -1,15 +0,0 @@
exports.up = async knex => {
return knex.schema.createTable('items', table => {
table.uuid('id').primary();
table.uuid('account').notNullable()
table.foreign('account')
.references('id')
.inTable('accounts')
.onDelete('CASCADE');
table.binary('data').notNullable();
table.index('id');
table.index('account');
});
};
exports.down = async () => {};

View File

@ -0,0 +1,36 @@
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
exports.up = async knex => {
await knex.schema.createTable('vbox', table => {
table.timestamps();
table.uuid('id').primary();
table.uuid('account').notNullable()
table.uuid('game').notNullable()
table.binary('data').notNullable();
table.foreign('game')
.references('id')
.inTable('games')
.onDelete('CASCADE');
table.foreign('account')
.references('id')
.inTable('accounts')
.onDelete('CASCADE');
table.index('id');
table.index('account');
table.unique(['account', 'game']);
});
// not really sure if this is a good idea
await knex('games').insert({
id: NULL_UUID,
data: 'INVALID',
joinable: false,
});
return true;
};
exports.down = async () => {};

View File

@ -11,9 +11,6 @@
"author": "", "author": "",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"ascii-tree": "^0.3.0",
"cli-ascii-tree": "0.0.4",
"inquirer": "^6.2.0",
"knex": "^0.15.2", "knex": "^0.15.2",
"pg": "^7.4.3" "pg": "^7.4.3"
} }

View File

@ -55,43 +55,43 @@ Debuff `Base enemy debuff - reduce enemy speed`
# Nature Type (red) # # Nature Type (red) #
Bite - (Attack + 3R) Deal significant `Red` damage Bite - (Attack RR) Deal significant `Red` damage
Strangle - (Stun + 3R) - Applies stun and physical dot Strangle - (Stun RR) - Applies stun and physical dot
Regenerate - (Buff + 3R) Restore red defense for target ally Regenerate - (Buff RR) Restore red defense for target ally
Snare - (Debuff + 3R) Disable enemy red skills for (3?) turns Snare - (Debuff RR) Disable enemy red skills for (3?) turns
Parry - (Block + 3R) Avoid all damage for this turn Parry - (Block RR) Avoid all damage for this turn
# Destruction Type (blue) # # Destruction Type (blue) #
Blast - (Attack + 3B) Deal significant `Blue` damage Blast - (Attack BB) Deal significant `Blue` damage
Ruin - (Stun + 3B) - AOE stun on the enemy team for remaind of turn Ruin - (Stun BB) - AOE stun on the enemy team for remaind of turn
Amplify - (Buff + 3B) Increased blue damage dealt by target ally Amplify - (Buff BB) Increased blue damage dealt by target ally
Curse - (Debuff + 3B) Decrease damage dealt by target enemy Curse - (Debuff BB) Decrease damage dealt by target enemy
Plague Shield - (Block + 3B) Apply dot debuff to attackers Plague Shield - (Block BB) Apply dot debuff to attackers
# Non-Violence Type (green) # # Non-Violence Type (green) #
Heal - (Attack + 3G) Heal ally for X Heal - (Attack GG) Heal ally for X
Throw - (Stun + 3G) - Disable target and increase damage taken Throw - (Stun GG) - Disable target and increase damage taken
Triage - (Buff + 3G) Buff which heals ally for X over Y turns Triage - (Buff GG) Buff which heals ally for X over Y turns
Purge - (Debuff + 3G) - Remove all enemy target buffs Purge - (Debuff GG) - Remove all enemy target buffs
Reflect - (Block + 3G) - Will use targetted attacks on source Reflect - (Block GG) - Will use targetted attacks on source
# Chaos Type (red / blue) # # Chaos Type (red / blue) #
Bannish - (Attack + 1R + 2B) - deal `Hybrid Red & Blue` + enemy can't attack or be attacked 3 turns Bannish - (Attack RB) - deal `Hybrid Red & Blue` + enemy can't attack or be attacked 3 turns
Hex - (Stun + 2R + 1B) - enemy stunned for 3 turns Hex - (Stun RB) - enemy stunned for 3 turns
Haste - (Buff + 2R + 1B) - significantly increase ally speed Haste - (Buff RB) - significantly increase ally speed
Slow - (Debuff + 1R + 2B) - significantly decrease enemy speed Slow - (Debuff RB) - significantly decrease enemy speed
Taunt - (Block + 2B + 1R) - Redirect all enemy targetted skills Taunt - (Block RB) - Redirect all enemy targetted skills
# Purity Type (red / green) # # Purity Type (red / green) #
Slay - (Attack + 1G + 2R) - deal `Red` damage. Bonus damage if the target has blue defense Slay - (Attack + 1G + 1R) - deal `Red` damage. Bonus damage if the target has blue defense
Silence - (Stun + 2G + 1R) - enemy can't use blue skills for 3 turns Silence - (Stun + 2G + 1R) - enemy can't use blue skills for 3 turns
Purify - (Buff + 2G + 1R) - remove all debuffs from target Purify - (Buff + 2G + 1R) - remove all debuffs from target
Empower - (Buff + 1G + 2R) - Increased red damage dealt by target ally Empower - (Buff + 1G + 1R) - Increased red damage dealt by target ally
???? - (Debuff + 1R + 2B) - ??? ???? - (Debuff RB) - ???
Shield - (Block + 2G + 1R) - Take no blue damage for the next 3 turns Shield - (Block + 2G + 1R) - Take no blue damage for the next 3 turns
# Technology Type (green / blue) type - ??? maybe rework and rename # # Technology Type (green / blue) type - ??? maybe rework and rename #

View File

@ -6,16 +6,16 @@
Rare `Increased Stamina` Rare `Increased Stamina`
Common `Increased Evasion rating` Common `Increased Evasion rating`
Common `Increased Spell Shield rating` Common `Increased Blue Shield rating`
Common `Increased Armour rating` Common `Increased RedShield rating`
Common `Increased Healing done` Common `Increased Healing done`
Common `Increased Healing received` Common `Increased Healing received`
Common `Increased Spell Damage` Common `Increased Blue Damage`
Common `Increased Physical Damage` Common `Increased Red Damage`
Uncommon `Reduced hp loss penalty to evade chance` Uncommon `Reduced hp loss penalty to evade chance`
Uncommon `Increased base evasion chance per X evasion rating` Uncommon `Increased base evasion chance per X evasion rating`
Uncommon `Increased % mitigation from armour` Uncommon `Increased % mitigation from red_shield`
Uncommon `Increased % mitigation from spell shield` Uncommon `Increased % mitigation from spell shield`
Uncommon `Increased damage over time` Uncommon `Increased damage over time`
@ -30,11 +30,11 @@ Rare `25% hex for blast`
Rare `cooldown reduction` Rare `cooldown reduction`
Rare `effect duration` Rare `effect duration`
Rare `increased phys dmg, 0 spell damage` Rare `increased phys damage, 0 spell damage`
Rare `increased spell dmg, 0 phys damage` Rare `increased spell damage, 0 phys damage`
Rare `increased phys dmg, silenced` Rare `increased phys damage, silenced`
Rare `increased spell dmg, snared` Rare `increased spell damage, snared`
Rare `increased speed, increased durations` Rare `increased speed, increased durations`
Rare `increased speed, increased cooldowns` Rare `increased speed, increased cooldowns`

View File

@ -21,11 +21,11 @@ resolve phase:
2.2 <- attack (normal resolve) 2.2 <- attack (normal resolve)
1.1 <- hexed (no skills for the rest of this turn and next) 1.1 <- hexed (no skills for the rest of this turn and next)
## Dmg Chart ## Damage Chart
| Physical | Magic | Modifiers | | Red | Magic | Modifiers |
| ------ | ------ | ------ | | ------ | ------ | ------ |
| dmg | dmg | speed | | damage | damage | speed |
| evasion | resistance | cooldowns | | evasion | resistance | cooldowns |
| reduction | absorption? | durations | | reduction | absorption? | durations |

166
server/SPECS.md Executable file
View File

@ -0,0 +1,166 @@
### Specs ###
Numbers are placeholder
`Specs get a bonus dependent on the total of Red / Green / Blue in team skills`
# Example to meet 5 red tag bonus
In your team Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `Snare`
- RR skill `Strike` contributes 2 red tags to the total red tags (2 total)
- RG skill `Slay` contributes 1 red tag to the total red tags (3 total)
- GG skill `Heal` contirubes 0 red tags to the total red tags (3 total)
- RR skill `Snare` contirubes 2 red tags to the total red tags (5 total)
# Specs also have `Class points`
Basic specs (Damage / Health / Defense) will generate class points
Advanced specs (Skill Specific Damage, Cooldown reduction, Increased durations, etc) will consume class points
### Generic Specs
(Base white skills not upgraded count as have 1 tag basic ?)
# Basic Damage
`Base` -> 10% inc basic damage
`Bonus` -> 3 basic tags -> +10% // 6 basic tags -> +15% // 12 basic tags -> +25%
Maximum 60% inc basic damage
# Basic % Life
`Base` -> 5% inc life
`Bonus` -> 3 basic tags -> +5% // 6 basic tags -> +10% // 12 basic tags -> +15%
Maximum 35% inc life
# Basic Speed
`Base` -> 5% inc speed
`Bonus` -> 3 basic tags -> +10% // 6 basic tags -> +15% // 12 basic tags -> +20%
Maximum 50% inc speed
# Basic Class Spec
`Base` -> +2 all class points
`Bonus` -> 3 basic tags -> +2 // 6 basic tags -> +4 // 12 basic tags -> +6
Maximum +14 all class points
# Basic Duration
### Increased Damage Combos ###
Generate by combining `Generic Spec (Basic Damage)` with respective RGB
# Red Damage (Dmg + RR)
Add 5 `Nature` Class Points
`Base` -> 10% inc red dmg
`Bonus` 5 red tags -> +10% // 10 red tags -> +15% // 20 red tags -> +25%
Maximum +60% red damage
# Blue Damage (Dmg + BB) #
Add 5 `Destruction` Class Points
`Base` -> 10% inc blue dmg
`Bonus` 5 blue tags -> +10% // 10 blue tags -> +15% // 20 blue tags -> +25%
Maximum +60% blue damage
# Healing (Dmg + GG) #
Add 5 `Non-Violence` Class Points
`Base` -> 10% inc healing
`Bonus` 5 green tags -> +10% // 10 green tags -> +15% // 20 green tags -> +25%
Maximum +60% inc healing
# Red damage and healing (Dmg + RG)
Add 5 `Purity` Class Points
`Base` -> 5% inc red damage and 5% inc healing
`Bonus` (2R + 2G tags) -> +5% + 5% // (5R + 5G tags) -> +10% + 10% % // (10R + 10G) tags -> +15% + 15%
Maximum +35% inc red damage and 35% inc healing
# Red and blue damage (Dmg + RB)
Add 5 `Chaos` Class Points
`Base` -> 5% inc red damage and 5% inc healing
`Bonus` (2 red + 2 green tags) -> +5% + 5% // (5 red + 5 green tags) -> +10% + 10% % // 20 green tags -> +15% + 15%
Maximum +35% inc damage and 35% inc healing
# Blue damage and healing (Dmg + BG)
Add 5 `??????` Class Points
`Base` -> 5% inc blue damage and 5% inc healing
`Bonus` (2B + 2G tags) -> +5% + 5% // (5B + 5G tags) -> +10% + 10% % // (10B + 10G) tags -> +15% + 15%
Maximum +35% inc blue damage and 35% inc healing
### Increased Life Combos ###
Generate by combining `Generic Spec (Basic Life)` with respective RGB
# Increased % Red Shield (Basic %HP + 2R)
Add 5 Nature Class Points
`Base` -> 10% inc red shield
`Bonus` 5 red tags -> +10% // 10 red tags -> +15% // 20 red tags -> +20%
Maximum +55% inc red shield
# Increased % Red Shield and Life (Basic %HP + 1R1G)
Add 5 Purity Class Points
`Base` -> 5% inc red shield and 5% inc life
`Bonus` (2R + 2G tags) -> +5% + 5% // (5R + 5G tags) -> +10% + 10% % // (10R + 10G) tags -> +15% + 15%
Maximum +35% inc red shield and 35% inc life
# Increased % Blue Shield (Basic %HP + 2B)
Add 5 Destruction Class Points
`Base` -> 10% inc red shield
`Bonus` 5 blue tags -> +10% // 10 blue tags -> +15% // 20 blue tags -> +20%
Maximum +55% inc blue shield
# Increased % Blue Shield and Life (Basic %HP + 1B1G)
Add 5 ??? Class Points
`Base` -> 5% inc red shield and 5% inc life
`Bonus` (2B + 2G tags) -> +5% + 5% // (5B + 5G tags) -> +10% + 10% % // (10B + 10G) tags -> +15% + 15%
Maximum +35% inc blue shield and 35% inc life
# Increased % Life (Basic %HP + 2G)
Add 5 Non-Violence Class Points
`Base` -> 10% inc hp
`Bonus` 5 green tags -> +10% // 10 green tags -> +15% // 20 green tags -> +20%
Maximum +55% inc hp
# Increased % Blue and Red Shield (Basic %HP + 1B1R)
Add 5 Chaos Class Points
`Base` -> 5% inc red shield and 5% inc life
`Bonus` (2B + 2R tags) -> +5% + 5% // (5B + 5R tags) -> +10% + 10% % // (10B + 10R) tags -> +15% + 15%
Maximum +35% inc blue shield and 35% inc red shield
## Upgraded Attack Spec Combos
# Increased Strike Damage (Combine Strike + Red Damage Spec x 2)
Consumes 15 Nature Class Points
`Base` -> 15% increased strike damage
`Bonus` 5 red tags -> +15% // 10 red tags -> +20% // 20 red tags -> +30%
Maximum 80% increased strike damage
# Improved Heal (Combine Heal + Healing Spec x 2)
Consumes 15 Non-Violence Class Points
`Base` -> 15% increased heal healing
`Bonus` 5 green tags -> +15% // green red tags -> +20% // green red tags -> +30%
Maximum 80% increased heal healing
# Increased Blast Damage (Combine Blast + Blue Spec x 2)
Consumes 15 Destruction Class Points
`Base` -> 15% increased blast damage
`Bonus` 5 blue tags -> +15% // 10 blue tags -> +20% // 20 blue tags -> +30%
Maximum 80% increased blast damage
# Increased Slay Damage (Combine Slay + Red Damage Spec + Healing Spec)
Consumes 15 Purity Class Points
`Base` -> 15% increased slay damage
`Bonus` (2R + 2G) tags -> +15% // (5R + 5G) tags -> +20% // (10R + 10G) tags -> +30%
Maximum 80% increased slay damage
# Increased Banish Damage (Combine Slay + Red Damage Spec + Blue Damage Spec)
Consumes 15 Chaos Class Points
`Base` -> 15% increased slay damage
`Bonus` (2R + 2B) tags -> +15% // (5R + 5B) tags -> +20% // (10R + 10B) tags -> +30%
Maximum 80% increased banish damage
## Other Combos
# Increased % Red Speed (Basic Speed + 2R)
Add 5 Nature Class Points
`Base` -> 15% inc red speed
`Bonus` 5 red tags -> +15% // 10 red tags -> +20% // 20 red tags -> +25%
Maximum 80% inc red speed
# Nature Affinity (Basic Class spec + 2R)
`Base` -> 10 Nature Class Points
`Bonus` 5 red tags -> +10 // 10 red tags -> +15 // 20 red tags -> +20
Maximum 45 Nature Class Points

View File

@ -30,7 +30,7 @@
* phys is faster and chaotic * phys is faster and chaotic
* spells are slow and reliable * spells are slow and reliable
* defensives are implicit * defensives are implicit
* armour is restored, not gained * red_shield is restored, not gained
* players can feel aggressive * players can feel aggressive
# ask sam # ask sam
@ -56,38 +56,6 @@ taunt
## NOW ## NOW
inventory + drops table
id
data
game
drops_buy(game_id, index)
drops_get()
inventory_get()
reduce balance
move drop into inventory
drops_update()
inventory_update()
-> inventory
inventory_combine(game_id, [indices])
inventory_get()
new item =
match base item
match modifiers
update inventory[base_index]
inventory_update()
-> inventory
## SOON ## SOON
* clean up categories * clean up categories
* why is the text fucked? * why is the text fucked?

View File

@ -45,14 +45,14 @@ pub enum Stat {
Hp, Hp,
Speed, Speed,
Stamina, Stamina,
PhysicalDamage, RedDamage,
PhysicalDamageTaken, RedDamageTaken,
SpellDamage, BlueDamage,
SpellDamageTaken, BlueDamageTaken,
Healing, Healing,
HealingTaken, HealingTaken,
Armour, RedShield,
SpellShield, BlueShield,
Evasion, Evasion,
} }
@ -136,13 +136,13 @@ pub struct CrypRecover {
pub struct Cryp { pub struct Cryp {
pub id: Uuid, pub id: Uuid,
pub account: Uuid, pub account: Uuid,
pub phys_dmg: CrypStat, pub red_damage: CrypStat,
pub spell_dmg: CrypStat, pub red_shield: CrypStat,
pub blue_shield: CrypStat,
pub blue_damage: CrypStat,
pub speed: CrypStat, pub speed: CrypStat,
pub stamina: CrypStat, pub stamina: CrypStat,
pub hp: CrypStat, pub hp: CrypStat,
pub armour: CrypStat,
pub spell_shield: CrypStat,
pub evasion: CrypStat, pub evasion: CrypStat,
pub xp: u64, pub xp: u64,
pub lvl: u8, pub lvl: u8,
@ -164,13 +164,13 @@ impl Cryp {
return Cryp { return Cryp {
id, id,
account: id, account: id,
phys_dmg: CrypStat { base: 0, value: 0, stat: Stat::PhysicalDamage }, red_damage: CrypStat { base: 0, value: 0, stat: Stat::RedDamage },
spell_dmg: CrypStat { base: 0, value: 0, stat: Stat::SpellDamage }, red_shield: CrypStat { base: 0, value: 0, stat: Stat::RedShield },
blue_damage: CrypStat { base: 0, value: 0, stat: Stat::BlueDamage },
blue_shield: CrypStat { base: 0, value: 0, stat: Stat::BlueShield },
speed: CrypStat { base: 0, value: 0, stat: Stat::Speed }, speed: CrypStat { base: 0, value: 0, stat: Stat::Speed },
stamina: CrypStat { base: 0, value: 0, stat: Stat::Stamina }, stamina: CrypStat { base: 0, value: 0, stat: Stat::Stamina },
hp: CrypStat { base: 0, value: 0, stat: Stat::Hp }, hp: CrypStat { base: 0, value: 0, stat: Stat::Hp },
armour: CrypStat { base: 0, value: 0, stat: Stat::Armour },
spell_shield: CrypStat { base: 0, value: 0, stat: Stat::SpellShield },
evasion: CrypStat { base: 0, value: 0, stat: Stat::Evasion }, evasion: CrypStat { base: 0, value: 0, stat: Stat::Evasion },
lvl: 0, lvl: 0,
xp: 0, xp: 0,
@ -238,15 +238,15 @@ impl Cryp {
let evasion_max = 5; let evasion_max = 5;
match stat { match stat {
Stat::PhysicalDamage => self.phys_dmg.set(rng.gen_range(stat_min, stat_max), &self.specs), Stat::RedDamage => self.red_damage.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::SpellDamage => self.spell_dmg.set(rng.gen_range(stat_min, stat_max), &self.specs), Stat::BlueDamage => self.blue_damage.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Speed => self.speed.set(rng.gen_range(stat_min, stat_max), &self.specs), Stat::Speed => self.speed.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Stamina => { Stat::Stamina => {
self.stamina.set(rng.gen_range(stam_min, stam_max), &self.specs); self.stamina.set(rng.gen_range(stam_min, stam_max), &self.specs);
self.hp.set(self.stamina.base, &self.specs) self.hp.set(self.stamina.base, &self.specs)
}, },
Stat::SpellShield => self.spell_shield.set(rng.gen_range(stat_min, stat_max), &self.specs), Stat::BlueShield => self.blue_shield.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Armour => self.armour.set(rng.gen_range(stat_min, stat_max), &self.specs), Stat::RedShield => self.red_shield.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Evasion => self.evasion.set(rng.gen_range(evasion_min, evasion_max), &self.specs), Stat::Evasion => self.evasion.set(rng.gen_range(evasion_min, evasion_max), &self.specs),
_ => panic!("{:?} not a rollable stat", stat), _ => panic!("{:?} not a rollable stat", stat),
}; };
@ -262,8 +262,8 @@ impl Cryp {
self.xp = xp; self.xp = xp;
self.roll_stat(Stat::PhysicalDamage); self.roll_stat(Stat::RedDamage);
self.roll_stat(Stat::SpellDamage); self.roll_stat(Stat::BlueDamage);
self.roll_stat(Stat::Speed); self.roll_stat(Stat::Speed);
self.roll_stat(Stat::Stamina); self.roll_stat(Stat::Stamina);
@ -306,7 +306,7 @@ impl Cryp {
return Ok(self.recalculate_stats()); return Ok(self.recalculate_stats());
} }
pub fn spec_remove(mut self, spec: Spec) -> Result<Cryp, Error> { pub fn spec_remove(&mut self, spec: Spec) -> Result<&mut Cryp, Error> {
let find_spec = |spec_v: &Vec<Spec>| spec_v.iter().position(|s| s.spec == spec.spec); let find_spec = |spec_v: &Vec<Spec>| spec_v.iter().position(|s| s.spec == spec.spec);
match spec.level { match spec.level {
@ -324,18 +324,18 @@ impl Cryp {
}, },
}; };
Ok(self) Ok(self.recalculate_stats())
} }
fn recalculate_stats(&mut self) -> &mut Cryp { fn recalculate_stats(&mut self) -> &mut Cryp {
self.stamina.recalculate(&self.specs); self.stamina.recalculate(&self.specs);
self.hp.recalculate(&self.specs); self.hp.recalculate(&self.specs);
self.phys_dmg.recalculate(&self.specs); self.red_damage.recalculate(&self.specs);
self.spell_dmg.recalculate(&self.specs); self.red_shield.recalculate(&self.specs);
self.blue_damage.recalculate(&self.specs);
self.blue_shield.recalculate(&self.specs);
self.evasion.recalculate(&self.specs); self.evasion.recalculate(&self.specs);
self.armour.recalculate(&self.specs);
self.spell_shield.recalculate(&self.specs);
self.speed.recalculate(&self.specs); self.speed.recalculate(&self.specs);
self self
@ -468,24 +468,24 @@ impl Cryp {
// } // }
// Stats // Stats
pub fn phys_dmg(&self) -> u64 { pub fn red_damage(&self) -> u64 {
let phys_dmg_mods = self.effects.iter() let red_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::PhysicalDamage)) .filter(|e| e.effect.modifications().contains(&Stat::RedDamage))
.map(|cryp_effect| cryp_effect.effect) .map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>(); .collect::<Vec<Effect>>();
let modified_phys_dmg = phys_dmg_mods.iter().fold(self.phys_dmg.value, |acc, m| m.apply(acc)); let modified_red_damage = red_damage_mods.iter().fold(self.red_damage.value, |acc, m| m.apply(acc));
return modified_phys_dmg; return modified_red_damage;
} }
pub fn spell_dmg(&self) -> u64 { pub fn blue_damage(&self) -> u64 {
let spell_dmg_mods = self.effects.iter() let blue_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::SpellDamage)) .filter(|e| e.effect.modifications().contains(&Stat::BlueDamage))
.map(|cryp_effect| cryp_effect.effect) .map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>(); .collect::<Vec<Effect>>();
let modified_spell_dmg = spell_dmg_mods.iter().fold(self.spell_dmg.value, |acc, m| m.apply(acc)); let modified_blue_damage = blue_damage_mods.iter().fold(self.blue_damage.value, |acc, m| m.apply(acc));
return modified_spell_dmg; return modified_blue_damage;
} }
pub fn skill_speed(&self, s: Skill) -> u64 { pub fn skill_speed(&self, s: Skill) -> u64 {
@ -518,7 +518,7 @@ impl Cryp {
ResolutionResult::Healing { ResolutionResult::Healing {
amount: 0, amount: 0,
overhealing: 0, overhealing: 0,
category: Category::PhysHeal, category: Category::RedHeal,
immunity: immunity.clone(), immunity: immunity.clone(),
}; };
} }
@ -546,12 +546,12 @@ impl Cryp {
return ResolutionResult::Healing { return ResolutionResult::Healing {
amount: healing, amount: healing,
overhealing, overhealing,
category: Category::PhysHeal, category: Category::RedHeal,
immunity, immunity,
}; };
} }
pub fn deal_phys_dmg(&mut self, skill: Skill, amount: u64) -> ResolutionResult { pub fn deal_red_damage(&mut self, skill: Skill, amount: u64) -> ResolutionResult {
let immunity = self.immune(skill); let immunity = self.immune(skill);
let immune = immunity.immune; let immune = immunity.immune;
@ -559,29 +559,29 @@ impl Cryp {
return ResolutionResult::Damage { return ResolutionResult::Damage {
amount: 0, amount: 0,
mitigation: 0, mitigation: 0,
category: Category::PhysDmg, category: Category::RedDamage,
immunity, immunity,
}; };
} }
let phys_dmg_mods = self.effects.iter() let red_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::PhysicalDamageTaken)) .filter(|e| e.effect.modifications().contains(&Stat::RedDamageTaken))
.map(|cryp_effect| cryp_effect.effect) .map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>(); .collect::<Vec<Effect>>();
// println!("{:?}", phys_dmg_mods); // println!("{:?}", red_damage_mods);
let modified_dmg = phys_dmg_mods.iter().fold(amount, |acc, m| m.apply(acc)); let modified_damage = red_damage_mods.iter().fold(amount, |acc, m| m.apply(acc));
// calculate amount of damage armour will not absorb // calculate amount of damage red_shield will not absorb
// eg 50 armour 25 dmg -> 0 remainder 25 mitigation // eg 50 red_shield 25 damage -> 0 remainder 25 mitigation
// 50 armour 100 dmg -> 50 remainder 50 mitigation // 50 red_shield 100 damage -> 50 remainder 50 mitigation
// 50 armour 5 dmg -> 0 remainder 5 mitigation // 50 red_shield 5 damage -> 0 remainder 5 mitigation
let remainder = modified_dmg.saturating_sub(self.armour.value); let remainder = modified_damage.saturating_sub(self.red_shield.value);
let mitigation = modified_dmg.saturating_sub(remainder); let mitigation = modified_damage.saturating_sub(remainder);
// reduce armour by mitigation amount // reduce red_shield by mitigation amount
self.armour.reduce(mitigation); self.red_shield.reduce(mitigation);
// deal remainder to hp // deal remainder to hp
self.hp.reduce(remainder); self.hp.reduce(remainder);
@ -589,12 +589,12 @@ impl Cryp {
return ResolutionResult::Damage { return ResolutionResult::Damage {
amount: remainder, amount: remainder,
mitigation, mitigation,
category: Category::PhysDmg, category: Category::RedDamage,
immunity, immunity,
}; };
} }
pub fn deal_spell_dmg(&mut self, skill: Skill, amount: u64) -> ResolutionResult { pub fn deal_blue_damage(&mut self, skill: Skill, amount: u64) -> ResolutionResult {
let immunity = self.immune(skill); let immunity = self.immune(skill);
let immune = immunity.immune; let immune = immunity.immune;
@ -602,29 +602,29 @@ impl Cryp {
return ResolutionResult::Damage { return ResolutionResult::Damage {
amount: 0, amount: 0,
mitigation: 0, mitigation: 0,
category: Category::SpellDmg, category: Category::BlueDamage,
immunity, immunity,
}; };
} }
let spell_dmg_mods = self.effects.iter() let blue_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::SpellDamageTaken)) .filter(|e| e.effect.modifications().contains(&Stat::BlueDamageTaken))
.map(|cryp_effect| cryp_effect.effect) .map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>(); .collect::<Vec<Effect>>();
// println!("{:?}", spell_dmg_mods); // println!("{:?}", blue_damage_mods);
let modified_dmg = spell_dmg_mods.iter().fold(amount, |acc, m| m.apply(acc)); let modified_damage = blue_damage_mods.iter().fold(amount, |acc, m| m.apply(acc));
let remainder = modified_dmg.saturating_sub(self.armour.value); let remainder = modified_damage.saturating_sub(self.blue_shield.value);
let mitigation = modified_dmg.saturating_sub(remainder); let mitigation = modified_damage.saturating_sub(remainder);
self.armour.reduce(mitigation); self.blue_shield.reduce(mitigation);
self.hp.reduce(remainder); self.hp.reduce(remainder);
return ResolutionResult::Damage { return ResolutionResult::Damage {
amount: remainder, amount: remainder,
mitigation, mitigation,
category: Category::SpellDmg, category: Category::BlueDamage,
immunity, immunity,
}; };
} }
@ -734,7 +734,7 @@ pub fn cryp_forget(params: CrypForgetParams, tx: &mut Transaction, account: &Acc
pub fn cryp_unspec(params: CrypUnspecParams, tx: &mut Transaction, account: &Account) -> Result<Cryp, Error> { pub fn cryp_unspec(params: CrypUnspecParams, tx: &mut Transaction, account: &Account) -> Result<Cryp, Error> {
let mut cryp = cryp_get(tx, params.id, account.id)?; let mut cryp = cryp_get(tx, params.id, account.id)?;
cryp = cryp.spec_remove(params.spec)?; cryp.spec_remove(params.spec)?;
return cryp_write(cryp, tx); return cryp_write(cryp, tx);
} }

View File

@ -11,7 +11,6 @@ use account::Account;
use rpc::{GameStateParams, GameSkillParams, GamePveParams, GamePvpParams, GameJoinParams}; use rpc::{GameStateParams, GameSkillParams, GamePveParams, GamePvpParams, GameJoinParams};
use cryp::{Cryp, cryp_get}; use cryp::{Cryp, cryp_get};
use skill::{Skill, Cast, ResolutionResult}; use skill::{Skill, Cast, ResolutionResult};
use item::{item_drop};
use zone::{node_finish}; use zone::{node_finish};
use mob::{generate_mob_team}; use mob::{generate_mob_team};
@ -685,12 +684,6 @@ pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> {
result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?; result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?;
if game.finished() { if game.finished() {
if let Some(t) = game.winner() {
if !t.id.is_nil() {
item_drop(tx, t.id, game.mode)?;
}
}
// check for zone update // check for zone update
if let Some((z, i)) = game.zone { if let Some((z, i)) = game.zone {
node_finish(game, z, i, tx)?; node_finish(game, z, i, tx)?;
@ -854,7 +847,7 @@ mod tests {
.learn(Skill::TestTouch) .learn(Skill::TestTouch)
.learn(Skill::TestBlock) .learn(Skill::TestBlock)
.learn(Skill::TestParry) .learn(Skill::TestParry)
.learn(Skill::TestDrain) .learn(Skill::TestSiphon)
.learn(Skill::Empower) .learn(Skill::Empower)
.learn(Skill::Stun) .learn(Skill::Stun)
.learn(Skill::Block) .learn(Skill::Block)
@ -868,7 +861,7 @@ mod tests {
.learn(Skill::TestTouch) .learn(Skill::TestTouch)
.learn(Skill::TestBlock) .learn(Skill::TestBlock)
.learn(Skill::TestParry) .learn(Skill::TestParry)
.learn(Skill::TestDrain) .learn(Skill::TestSiphon)
.learn(Skill::Empower) .learn(Skill::Empower)
.learn(Skill::Stun) .learn(Skill::Stun)
.learn(Skill::Block) .learn(Skill::Block)
@ -1014,12 +1007,12 @@ mod tests {
let x_cryp = x_team.cryps[0].clone(); let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone(); let y_cryp = y_team.cryps[0].clone();
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().phys_dmg.force(u64::max_value()); game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().red_damage.force(u64::max_value());
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().speed.force(u64::max_value()); game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().speed.force(u64::max_value());
// just in case // just in case
// remove all mitigation // remove all mitigation
game.team_by_id(x_team.id).cryp_by_id(x_cryp.id).unwrap().armour.force(0); game.team_by_id(x_team.id).cryp_by_id(x_cryp.id).unwrap().red_shield.force(0);
let _x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestStun).unwrap(); let _x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestStun).unwrap();
game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap(); game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap();
@ -1088,7 +1081,7 @@ mod tests {
} }
#[test] #[test]
fn drain_test() { fn siphon_test() {
let mut game = create_test_game(); let mut game = create_test_game();
let x_team = game.teams[0].clone(); let x_team = game.teams[0].clone();
@ -1097,7 +1090,7 @@ mod tests {
let x_cryp = x_team.cryps[0].clone(); let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone(); let y_cryp = y_team.cryps[0].clone();
let _x_drain_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestDrain).unwrap(); let _x_siphon_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestSiphon).unwrap();
let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
game.resolve_phase_start(); game.resolve_phase_start();
@ -1107,7 +1100,7 @@ mod tests {
game.resolve_phase_start(); game.resolve_phase_start();
assert!(game.resolved.iter().any(|r| r.skill == Skill::DrainTick)); assert!(game.resolved.iter().any(|r| r.skill == Skill::SiphonTick));
} }
#[test] #[test]

View File

@ -938,7 +938,7 @@ mod tests {
.learn(Skill::TestTouch) .learn(Skill::TestTouch)
.learn(Skill::TestBlock) .learn(Skill::TestBlock)
.learn(Skill::TestParry) .learn(Skill::TestParry)
.learn(Skill::TestDrain) .learn(Skill::TestSiphon)
.learn(Skill::Empower) .learn(Skill::Empower)
.learn(Skill::Block) .learn(Skill::Block)
.create(); .create();
@ -950,7 +950,7 @@ mod tests {
.learn(Skill::TestTouch) .learn(Skill::TestTouch)
.learn(Skill::TestBlock) .learn(Skill::TestBlock)
.learn(Skill::TestParry) .learn(Skill::TestParry)
.learn(Skill::TestDrain) .learn(Skill::TestSiphon)
.learn(Skill::Empower) .learn(Skill::Empower)
.learn(Skill::Block) .learn(Skill::Block)
.create(); .create();
@ -1104,7 +1104,7 @@ mod tests {
let x_cryp = x_team.cryps[0].clone(); let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone(); let y_cryp = y_team.cryps[0].clone();
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().phys_dmg.set(u64::max_value()); game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().red_damage.set(u64::max_value());
let x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestStun).unwrap(); let x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestStun).unwrap();
let y_attack_id = game.add_skill(y_team.id, y_cryp.id, Some(x_team.id), Skill::Attack).unwrap(); let y_attack_id = game.add_skill(y_team.id, y_cryp.id, Some(x_team.id), Skill::Attack).unwrap();
@ -1194,7 +1194,7 @@ mod tests {
} }
#[test] #[test]
fn drain_test() { fn siphon_test() {
let mut game = create_test_game(); let mut game = create_test_game();
let x_team = game.teams[0].clone(); let x_team = game.teams[0].clone();
@ -1203,13 +1203,13 @@ mod tests {
let x_cryp = x_team.cryps[0].clone(); let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone(); let y_cryp = y_team.cryps[0].clone();
let x_drain_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestDrain).unwrap(); let x_siphon_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestSiphon).unwrap();
let y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_team.id), Skill::TestTouch).unwrap(); let y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_team.id), Skill::TestTouch).unwrap();
game.target_phase_start(); game.target_phase_start();
game.add_target(x_team.id, x_cryp.id, y_touch_id).unwrap(); game.add_target(x_team.id, x_cryp.id, y_touch_id).unwrap();
game.add_target(y_team.id, y_cryp.id, x_drain_id).unwrap(); game.add_target(y_team.id, y_cryp.id, x_siphon_id).unwrap();
game.resolve_phase_start(); game.resolve_phase_start();
@ -1218,7 +1218,7 @@ mod tests {
game.target_phase_start(); game.target_phase_start();
assert!(game.resolved.iter().any(|r| r.skill == Skill::DrainTick)); assert!(game.resolved.iter().any(|r| r.skill == Skill::SiphonTick));
} }
#[test] #[test]

View File

@ -17,19 +17,19 @@ use spec::{Spec, SpecType};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum ItemAction { pub enum ItemAction {
RerollPhysDamage, RerollRedDamage,
RerollSpellDamage, RerollBlueDamage,
RerollSpeed, RerollSpeed,
RerollStamina, RerollStamina,
RerollArmour, RerollRedShield,
RerollSpellShield, RerollBlueShield,
RerollEvasion, RerollEvasion,
SpecPhysDmg5, SpecRedDamage5,
SpecSpellDmg5, SpecBlueDamage5,
SpecArmour5, SpecRedShield5,
SpecSpellShield5, SpecBlueShield5,
SpecSpellEvasion5, SpecBlueEvasion5,
} }
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
@ -44,24 +44,24 @@ impl Item {
pub fn new(action: ItemAction, account_id: Uuid) -> Item { pub fn new(action: ItemAction, account_id: Uuid) -> Item {
let id = Uuid::new_v4(); let id = Uuid::new_v4();
return Item { return Item {
id, id,
account: account_id, account: account_id,
action, action,
}; };
} }
fn apply(&mut self, tx: &mut Transaction, target: Uuid) -> Result<(), Error> { fn apply(&mut self, tx: &mut Transaction, target: Uuid) -> Result<(), Error> {
match self.action { match self.action {
ItemAction::RerollStamina => reroll(self, tx, target, Stat::Stamina), ItemAction::RerollStamina => reroll(self, tx, target, Stat::Stamina),
ItemAction::RerollPhysDamage => reroll(self, tx, target, Stat::PhysicalDamage), ItemAction::RerollRedDamage => reroll(self, tx, target, Stat::RedDamage),
ItemAction::RerollSpellDamage => reroll(self, tx, target, Stat::SpellDamage), ItemAction::RerollBlueDamage => reroll(self, tx, target, Stat::BlueDamage),
ItemAction::RerollSpeed => reroll(self, tx, target, Stat::Speed), ItemAction::RerollSpeed => reroll(self, tx, target, Stat::Speed),
ItemAction::RerollArmour => reroll(self, tx, target, Stat::Armour), ItemAction::RerollRedShield => reroll(self, tx, target, Stat::RedShield),
ItemAction::RerollSpellShield => reroll(self, tx, target, Stat::SpellShield), ItemAction::RerollBlueShield => reroll(self, tx, target, Stat::BlueShield),
ItemAction::RerollEvasion => reroll(self, tx, target, Stat::Evasion), ItemAction::RerollEvasion => reroll(self, tx, target, Stat::Evasion),
ItemAction::SpecPhysDmg5 => spec_add(self, tx, target, SpecType::PhysDamage5), ItemAction::SpecRedDamage5 => spec_add(self, tx, target, SpecType::RedDamage5),
ItemAction::SpecSpellDmg5 => spec_add(self, tx, target, SpecType::SpellDamage5), ItemAction::SpecBlueDamage5 => spec_add(self, tx, target, SpecType::BlueDamage5),
_ => unimplemented!(), _ => unimplemented!(),
} }
} }
@ -86,8 +86,8 @@ fn mode_drops(mode: GameMode) -> Vec<(ItemAction, usize)> {
match mode { match mode {
GameMode::Normal => vec![ GameMode::Normal => vec![
(ItemAction::RerollStamina, 1), (ItemAction::RerollStamina, 1),
(ItemAction::RerollPhysDamage, 1), (ItemAction::RerollRedDamage, 1),
(ItemAction::RerollSpellDamage, 1), (ItemAction::RerollBlueDamage, 1),
], ],
GameMode::Pvp => vec![ GameMode::Pvp => vec![
(ItemAction::RerollSpeed, 1), (ItemAction::RerollSpeed, 1),
@ -96,19 +96,19 @@ fn mode_drops(mode: GameMode) -> Vec<(ItemAction, usize)> {
GameMode::Zone2v2Caster | GameMode::Zone2v2Caster |
GameMode::Zone3v3MeleeMiniboss => vec![ GameMode::Zone3v3MeleeMiniboss => vec![
(ItemAction::RerollEvasion, 1), (ItemAction::RerollEvasion, 1),
(ItemAction::RerollArmour, 1), (ItemAction::RerollRedShield, 1),
(ItemAction::RerollSpellShield, 1), (ItemAction::RerollBlueShield, 1),
], ],
GameMode::Zone3v3HealerBoss => vec![ GameMode::Zone3v3HealerBoss => vec![
(ItemAction::RerollSpeed, 1), (ItemAction::RerollSpeed, 1),
], ],
// _ => vec![ // _ => vec![
// (ItemAction::RerollStamina, 1), // (ItemAction::RerollStamina, 1),
// (ItemAction::RerollPhysDamage, 1), // (ItemAction::RerollRedDamage, 1),
// (ItemAction::RerollSpellDamage, 1), // (ItemAction::RerollBlueDamage, 1),
// (ItemAction::RerollSpeed, 1), // (ItemAction::RerollSpeed, 1),
// (ItemAction::RerollArmour, 1), // (ItemAction::RerollRedShield, 1),
// (ItemAction::RerollSpellShield, 1), // (ItemAction::RerollBlueShield, 1),
// (ItemAction::RerollEvasion, 1), // (ItemAction::RerollEvasion, 1),
// ], // ],
} }

View File

@ -26,10 +26,12 @@ mod spec;
// mod passives; // mod passives;
mod rpc; mod rpc;
mod account; mod account;
mod item; // mod item;
mod zone; mod zone;
mod mob; mod mob;
mod vbox;
use dotenv::dotenv; use dotenv::dotenv;
use net::{start}; use net::{start};

View File

@ -18,10 +18,10 @@ use net::Db;
use cryp::{Cryp, cryp_spawn, cryp_learn, cryp_forget, cryp_unspec}; use cryp::{Cryp, cryp_spawn, cryp_learn, cryp_forget, cryp_unspec};
use game::{Game, game_state, game_pve, game_pvp, game_join, game_joinable_list, game_skill}; use game::{Game, game_state, game_pve, game_pvp, game_join, game_joinable_list, game_skill};
use account::{Account, account_create, account_login, account_from_token, account_cryps, account_zone}; use account::{Account, account_create, account_login, account_from_token, account_cryps, account_zone};
use item::{Item, ItemAction, items_list, item_use, item_create};
use skill::{Skill}; use skill::{Skill};
use zone::{Zone, zone_create, zone_join, zone_close}; use zone::{Zone, zone_create, zone_join, zone_close};
use spec::{Spec}; use spec::{Spec};
use vbox::{Vbox, vbox_state, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_drop};
pub struct Rpc; pub struct Rpc;
@ -76,11 +76,14 @@ impl Rpc {
"zone_join" => Rpc::zone_join(data, &mut tx, account.unwrap(), client), "zone_join" => Rpc::zone_join(data, &mut tx, account.unwrap(), client),
"zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client), "zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client),
"account_cryps" => Rpc::account_cryps(data, &mut tx, account.unwrap(), client), "account_cryps" => Rpc::account_cryps(data, &mut tx, account.unwrap(), client),
"account_items" => Rpc::account_items(data, &mut tx, account.unwrap(), client),
"account_zone" => Rpc::account_zone(data, &mut tx, account.unwrap(), client), "account_zone" => Rpc::account_zone(data, &mut tx, account.unwrap(), client),
"item_use" => Rpc::item_use(data, &mut tx, account.unwrap(), client),
"press_r" => Rpc::press_r(data, &mut tx, account.unwrap(), client), "vbox_state" => Rpc::vbox_state(data, &mut tx, account.unwrap(), client),
"vbox_accept" => Rpc::vbox_accept(data, &mut tx, account.unwrap(), client),
"vbox_apply" => Rpc::vbox_apply(data, &mut tx, account.unwrap(), client),
"vbox_drop" => Rpc::vbox_drop(data, &mut tx, account.unwrap(), client),
"vbox_combine" => Rpc::vbox_combine(data, &mut tx, account.unwrap(), client),
"vbox_discard" => Rpc::vbox_discard(data, &mut tx, account.unwrap(), client),
_ => Err(format_err!("unknown method - {:?}", v.method)), _ => Err(format_err!("unknown method - {:?}", v.method)),
}; };
@ -251,8 +254,6 @@ impl Rpc {
Ok(cryp_list) Ok(cryp_list)
} }
fn account_create(data: Vec<u8>, tx: &mut Transaction, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> { fn account_create(data: Vec<u8>, tx: &mut Transaction, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
match from_slice::<AccountCreateMsg>(&data) { match from_slice::<AccountCreateMsg>(&data) {
Ok(v) => Ok(RpcResponse { Ok(v) => Ok(RpcResponse {
@ -290,7 +291,7 @@ impl Rpc {
let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Decay }, tx, &account)?; cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Decay }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Blast }, tx, &account)?; cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Blast }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Drain }, tx, &account)?; cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Siphon }, tx, &account)?;
let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect();
let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?;
@ -314,13 +315,6 @@ impl Rpc {
}) })
} }
fn account_items(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
Ok(RpcResponse {
method: "account_items".to_string(),
params: RpcResult::ItemList(items_list(tx, &account)?)
})
}
fn account_zone(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> { fn account_zone(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
Ok(RpcResponse { Ok(RpcResponse {
method: "zone_state".to_string(), method: "zone_state".to_string(),
@ -328,49 +322,6 @@ impl Rpc {
}) })
} }
fn press_r(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
for action in [
ItemAction::RerollPhysDamage,
ItemAction::RerollSpellDamage,
ItemAction::RerollSpeed,
ItemAction::RerollStamina,
ItemAction::RerollArmour,
ItemAction::RerollSpellShield,
ItemAction::RerollEvasion,
ItemAction::SpecPhysDmg5,
ItemAction::SpecSpellDmg5,
].into_iter() {
let item = Item::new(*action, account.id);
item_create(item, tx, account.id)?;
}
let res = RpcResponse {
method: "account_items".to_string(),
params: RpcResult::ItemList(items_list(tx, &account)?)
};
return Ok(res);
}
fn item_use(data: Vec<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<ItemUseMsg>(&data).or(Err(err_msg("invalid params")))?;
item_use(msg.params, tx, &account)?;
Rpc::send_msg(client, RpcResponse {
method: "account_items".to_string(),
params: RpcResult::ItemList(items_list(tx, &account)?)
})?;
let cryps_list = RpcResponse {
method: "account_cryps".to_string(),
params: RpcResult::CrypList(account_cryps(tx, &account)?)
};
return Ok(cryps_list);
}
fn zone_create(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> { fn zone_create(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
// let _msg = from_slice::<ZoneCreateMsg>(&data).or(Err(err_msg("invalid params")))?; // let _msg = from_slice::<ZoneCreateMsg>(&data).or(Err(err_msg("invalid params")))?;
@ -404,6 +355,77 @@ impl Rpc {
return Ok(response); return Ok(response);
} }
fn vbox_state(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxStateMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_state(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_accept(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxAcceptMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_accept(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_discard(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxDiscardMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_discard(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_combine(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxCombineMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_combine(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_apply(data: Vec<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxApplyMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_apply(msg.params, tx, &account)?)
};
Rpc::send_msg(client, RpcResponse {
method: "account_cryps".to_string(),
params: RpcResult::CrypList(account_cryps(tx, &account)?)
})?;
return Ok(response);
}
fn vbox_drop(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxDropMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_drop(msg.params, tx, &account)?)
};
return Ok(response);
}
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
@ -422,10 +444,10 @@ pub enum RpcResult {
CrypList(Vec<Cryp>), CrypList(Vec<Cryp>),
GameState(Game), GameState(Game),
GameJoinableList(Vec<Game>), GameJoinableList(Vec<Game>),
ItemList(Vec<Item>),
ItemUse(()),
ZoneState(Zone), ZoneState(Zone),
ZoneClose(()), ZoneClose(()),
VboxState(Vbox),
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
@ -589,24 +611,6 @@ struct AccountCrypsMsg {
params: (), params: (),
} }
#[derive(Debug,Clone,Serialize,Deserialize)]
struct ItemListMsg {
method: String,
params: (),
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct ItemUseMsg {
method: String,
params: ItemUseParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct ItemUseParams {
pub item: Uuid,
pub target: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
struct ZoneCreateMsg { struct ZoneCreateMsg {
method: String, method: String,
@ -637,6 +641,76 @@ pub struct ZoneCloseParams {
pub zone_id: Uuid, pub zone_id: Uuid,
} }
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxStateMsg {
method: String,
params: VboxStateParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxStateParams {
pub game_id: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxAcceptMsg {
method: String,
params: VboxAcceptParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxAcceptParams {
pub game_id: Uuid,
pub index: usize,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxDiscardMsg {
method: String,
params: VboxDiscardParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxDiscardParams {
pub game_id: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxCombineMsg {
method: String,
params: VboxCombineParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxCombineParams {
pub game_id: Uuid,
pub indices: Vec<usize>,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxApplyMsg {
method: String,
params: VboxApplyParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxApplyParams {
pub game_id: Uuid,
pub cryp_id: Uuid,
pub index: usize,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxDropMsg {
method: String,
params: VboxDropParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxDropParams {
pub game_id: Uuid,
pub index: usize,
}
// #[cfg(test)] // #[cfg(test)]
// mod tests { // mod tests {

View File

@ -125,9 +125,9 @@ pub enum Effect {
Triage, Triage,
Decay, Decay,
Regen, Regen,
Drain, Siphon,
SpeedDrain, SpeedSiphon,
SpeedIncrease, SpeedIncrease,
Ko, Ko,
@ -137,13 +137,13 @@ impl Effect {
pub fn immune(&self, skill: Skill) -> bool { pub fn immune(&self, skill: Skill) -> bool {
match self { match self {
Effect::Parry => match skill.category() { Effect::Parry => match skill.category() {
Category::Spell => false, Category::Blue => false,
Category::Physical => true, Category::Red => true,
_ => false, _ => false,
}, },
Effect::Shield => match skill.category() { Effect::Shield => match skill.category() {
Category::Spell => true, Category::Blue => true,
Category::Physical => false, Category::Red => false,
_ => false, _ => false,
}, },
Effect::Banish => true, Effect::Banish => true,
@ -157,18 +157,18 @@ impl Effect {
Effect::Hex => true, Effect::Hex => true,
Effect::Banish => true, Effect::Banish => true,
Effect::Silence => match skill.category() { Effect::Silence => match skill.category() {
Category::Spell => true, Category::Blue => true,
Category::Physical => false, Category::Red => false,
_ => false, _ => false,
}, },
Effect::Snare => match skill.category() { Effect::Snare => match skill.category() {
Category::Spell => false, Category::Blue => false,
Category::Physical => true, Category::Red => true,
_ => false, _ => false,
}, },
Effect::Ko => match skill.category() { Effect::Ko => match skill.category() {
Category::SpellTick => false, Category::BlueTick => false,
_ => true, _ => true,
}, },
_ => false, _ => false,
@ -177,12 +177,12 @@ impl Effect {
pub fn modifications(&self) -> Vec<Stat> { pub fn modifications(&self) -> Vec<Stat> {
match self { match self {
Effect::Empower => vec![Stat::PhysicalDamage], Effect::Empower => vec![Stat::RedDamage],
Effect::Vulnerable => vec![Stat::PhysicalDamageTaken], Effect::Vulnerable => vec![Stat::RedDamageTaken],
Effect::Block => vec![Stat::PhysicalDamageTaken], Effect::Block => vec![Stat::RedDamageTaken],
Effect::Amplify => vec![Stat::SpellDamage], Effect::Amplify => vec![Stat::BlueDamage],
Effect::Curse => vec![Stat::SpellDamageTaken], Effect::Curse => vec![Stat::BlueDamageTaken],
Effect::Haste => vec![Stat::Speed], Effect::Haste => vec![Stat::Speed],
Effect::Slow => vec![Stat::Speed], Effect::Slow => vec![Stat::Speed],
@ -216,43 +216,43 @@ impl Effect {
pub fn category(&self) -> Category { pub fn category(&self) -> Category {
match self { match self {
// physical // physical
Effect::Stun => Category::PhysDebuff, Effect::Stun => Category::RedDebuff,
Effect::Block => Category::PhysBuff, Effect::Block => Category::RedBuff,
Effect::Parry => Category::PhysBuff, Effect::Parry => Category::RedBuff,
Effect::Bleed => Category::PhysDebuff, Effect::Bleed => Category::RedDebuff,
Effect::Leech => Category::PhysDebuff, Effect::Leech => Category::RedDebuff,
Effect::Airborne => Category::PhysDebuff, Effect::Airborne => Category::RedDebuff,
Effect::Untouchable => Category::PhysBuff, Effect::Untouchable => Category::RedBuff,
Effect::Deadly => Category::PhysBuff, Effect::Deadly => Category::RedBuff,
Effect::Vulnerable => Category::PhysDebuff, Effect::Vulnerable => Category::RedDebuff,
Effect::Fury => Category::PhysBuff, Effect::Fury => Category::RedBuff,
Effect::Blind => Category::PhysDebuff, Effect::Blind => Category::RedDebuff,
Effect::Snare => Category::PhysDebuff, Effect::Snare => Category::RedDebuff,
Effect::Empower => Category::PhysBuff, Effect::Empower => Category::RedBuff,
// magic // magic
Effect::Hex => Category::SpellDebuff, Effect::Hex => Category::BlueDebuff,
Effect::Curse => Category::SpellDebuff, Effect::Curse => Category::BlueDebuff,
Effect::Banish => Category::SpellDebuff, // todo randomise Effect::Banish => Category::BlueDebuff, // todo randomise
Effect::Slow => Category::SpellDebuff, Effect::Slow => Category::BlueDebuff,
Effect::Haste => Category::SpellBuff, Effect::Haste => Category::BlueBuff,
Effect::Enslave => Category::SpellDebuff, Effect::Enslave => Category::BlueDebuff,
Effect::Mesmerise => Category::SpellDebuff, Effect::Mesmerise => Category::BlueDebuff,
Effect::Amplify => Category::SpellBuff, Effect::Amplify => Category::BlueBuff,
Effect::Silence => Category::SpellDebuff, Effect::Silence => Category::BlueDebuff,
// magic immunity // magic immunity
Effect::Shield => Category::SpellBuff, Effect::Shield => Category::BlueBuff,
// effects over time // effects over time
Effect::Triage => Category::SpellBuff, Effect::Triage => Category::BlueBuff,
Effect::Decay => Category::SpellDebuff, Effect::Decay => Category::BlueDebuff,
Effect::Regen => Category::SpellBuff, Effect::Regen => Category::BlueBuff,
Effect::Drain => Category::SpellDebuff, Effect::Siphon => Category::BlueDebuff,
Effect::SpeedDrain => Category::SpellDebuff, Effect::SpeedSiphon => Category::BlueDebuff,
Effect::SpeedIncrease => Category::SpellBuff, Effect::SpeedIncrease => Category::BlueBuff,
Effect::Ko => Category::Ko, Effect::Ko => Category::Ko,
} }
@ -283,7 +283,7 @@ impl Effect {
Effect::Triage => 3, Effect::Triage => 3,
Effect::Decay => 3, Effect::Decay => 3,
Effect::Drain => 2, Effect::Siphon => 2,
_ => { _ => {
println!("{:?} does not have a duration", self); println!("{:?} does not have a duration", self);
@ -296,18 +296,18 @@ impl Effect {
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Category { pub enum Category {
Physical, Red,
PhysHeal, RedHeal,
PhysDmg, RedDamage,
PhysDebuff, RedDebuff,
PhysBuff, RedBuff,
PhysTick, RedTick,
Spell, Blue,
SpellDmg, BlueDamage,
SpellHeal, BlueHeal,
SpellDebuff, BlueDebuff,
SpellBuff, BlueBuff,
SpellTick, BlueTick,
Ko, Ko,
} }
@ -318,8 +318,8 @@ pub enum Skill {
// ----------------- // -----------------
// Nature // Nature
// ----------------- // -----------------
Block, // reduce dmg Block, // reduce damage
Parry, // avoid all dmg Parry, // avoid all damage
Snare, Snare,
Paralyse, Paralyse,
@ -345,7 +345,7 @@ pub enum Skill {
Heal, Heal,
Triage, // hot Triage, // hot
TriageTick, TriageTick,
Throw, // no dmg stun, adds vulnerable Throw, // no damage stun, adds vulnerable
Charm, Charm,
Calm, Calm,
Rez, Rez,
@ -360,8 +360,8 @@ pub enum Skill {
Amplify, Amplify,
Decay, // dot Decay, // dot
DecayTick, // dot DecayTick, // dot
Drain, Siphon,
DrainTick, SiphonTick,
Curse, Curse,
Plague, // aoe dot Plague, // aoe dot
Ruin, // aoe Ruin, // aoe
@ -389,12 +389,12 @@ pub enum Skill {
Haste, Haste,
Slow, Slow,
// used by tests, no cd, no dmg // used by tests, no cd, no damage
TestTouch, TestTouch,
TestStun, TestStun,
TestBlock, TestBlock,
TestParry, TestParry,
TestDrain, TestSiphon,
} }
impl Skill { impl Skill {
@ -405,8 +405,8 @@ impl Skill {
// ----------------- // -----------------
// Nature // Nature
// ----------------- // -----------------
Skill::Block => None, // reduce dmg Skill::Block => None, // reduce damage
Skill::Parry => None, // avoid all dmg Skill::Parry => None, // avoid all damage
Skill::Snare => Some(1), Skill::Snare => Some(1),
Skill::Paralyse => Some(1), Skill::Paralyse => Some(1),
@ -431,7 +431,7 @@ impl Skill {
Skill::Heal => None, Skill::Heal => None,
Skill::Triage => None, // hot Skill::Triage => None, // hot
Skill::TriageTick => None, Skill::TriageTick => None,
Skill::Throw => Some(1), // no dmg stun, adds vulnerable Skill::Throw => Some(1), // no damage stun, adds vulnerable
Skill::Charm => Some(1), Skill::Charm => Some(1),
Skill::Calm => None, Skill::Calm => None,
Skill::Rez => Some(2), Skill::Rez => Some(2),
@ -443,8 +443,8 @@ impl Skill {
Skill::Amplify => Some(1), Skill::Amplify => Some(1),
Skill::Decay => None, // dot Skill::Decay => None, // dot
Skill::DecayTick => None, Skill::DecayTick => None,
Skill::Drain => Some(1), Skill::Siphon => Some(1),
Skill::DrainTick => None, Skill::SiphonTick => None,
Skill::Curse => Some(1), Skill::Curse => Some(1),
Skill::Plague => Some(1), // aoe dot Skill::Plague => Some(1), // aoe dot
Skill::Ruin => Some(2), // aoe Skill::Ruin => Some(2), // aoe
@ -478,95 +478,95 @@ impl Skill {
Skill::TestTouch => None, Skill::TestTouch => None,
Skill::TestStun => None, Skill::TestStun => None,
Skill::TestBlock => None, Skill::TestBlock => None,
Skill::TestDrain => None, Skill::TestSiphon => None,
Skill::TestParry => None, Skill::TestParry => None,
} }
} }
pub fn category(&self) -> Category { pub fn category(&self) -> Category {
match self { match self {
Skill::Attack => Category::Physical, Skill::Attack => Category::Red,
// ----------------- // -----------------
// Nature // Nature
// ----------------- // -----------------
Skill::Block => Category::Physical, // reduce dmg Skill::Block => Category::Red, // reduce damage
Skill::Parry => Category::Physical, // avoid all dmg Skill::Parry => Category::Red, // avoid all damage
Skill::Snare => Category::Physical, Skill::Snare => Category::Red,
Skill::Paralyse => Category::Physical, Skill::Paralyse => Category::Red,
Skill::Strangle => Category::Physical, Skill::Strangle => Category::Red,
// Strangle // Strangle
Skill::Stun => Category::Physical, Skill::Stun => Category::Red,
// ----------------- // -----------------
// Technology // Technology
// ----------------- // -----------------
Skill::Replicate => Category::Physical, Skill::Replicate => Category::Red,
Skill::Swarm => Category::Physical, Skill::Swarm => Category::Red,
Skill::Orbit => Category::Physical, Skill::Orbit => Category::Red,
Skill::Repair => Category::Physical, Skill::Repair => Category::Red,
Skill::Scan => Category::Physical, // track? Skill::Scan => Category::Red, // track?
// ----------------- // -----------------
// Preservation // Preservation
// ----------------- // -----------------
Skill::Heal => Category::Physical, Skill::Heal => Category::Red,
Skill::Triage => Category::Spell, // hot Skill::Triage => Category::Blue, // hot
Skill::TriageTick => Category::SpellTick, // hot Skill::TriageTick => Category::BlueTick, // hot
Skill::Throw => Category::Physical, // no dmg stun, adds vulnerable Skill::Throw => Category::Red, // no damage stun, adds vulnerable
Skill::Charm => Category::Spell, Skill::Charm => Category::Blue,
Skill::Calm => Category::Physical, Skill::Calm => Category::Red,
Skill::Rez => Category::Spell, Skill::Rez => Category::Blue,
// ----------------- // -----------------
// Destruction // Destruction
// ----------------- // -----------------
Skill::Blast => Category::Spell, Skill::Blast => Category::Blue,
Skill::Amplify => Category::Spell, Skill::Amplify => Category::Blue,
Skill::Decay => Category::Spell, // dot Skill::Decay => Category::Blue, // dot
Skill::DecayTick => Category::SpellTick, // hot Skill::DecayTick => Category::BlueTick, // hot
Skill::Drain => Category::Spell, Skill::Siphon => Category::Blue,
Skill::DrainTick => Category::SpellTick, // hot Skill::SiphonTick => Category::BlueTick, // hot
Skill::Curse => Category::Spell, Skill::Curse => Category::Blue,
Skill::Plague => Category::Spell, // aoe dot Skill::Plague => Category::Blue, // aoe dot
Skill::Ruin => Category::Spell, // aoe Skill::Ruin => Category::Blue, // aoe
// ----------------- // -----------------
// Purity // Purity
// ----------------- // -----------------
// Skill::Precision => 1, // Skill::Precision => 1,
Skill::Empower => Category::Physical, Skill::Empower => Category::Red,
Skill::Slay => Category::Physical, Skill::Slay => Category::Red,
Skill::Shield => Category::Spell, Skill::Shield => Category::Blue,
Skill::Silence => Category::Spell, Skill::Silence => Category::Blue,
Skill::Inquiry => Category::Spell, Skill::Inquiry => Category::Blue,
Skill::Purify => Category::Spell, Skill::Purify => Category::Blue,
Skill::Purge => Category::Spell, Skill::Purge => Category::Blue,
// ----------------- // -----------------
// Chaos // Chaos
// ----------------- // -----------------
Skill::Banish => Category::Spell, Skill::Banish => Category::Blue,
Skill::Hex => Category::Spell, Skill::Hex => Category::Blue,
Skill::Fear => Category::Spell, Skill::Fear => Category::Blue,
Skill::Taunt => Category::Spell, Skill::Taunt => Category::Blue,
Skill::Pause => Category::Spell, // extend durations Skill::Pause => Category::Blue, // extend durations
// Skill::Lag => 2, // // Skill::Lag => 2, //
Skill::Haste => Category::Spell, Skill::Haste => Category::Blue,
Skill::Slow => Category::Spell, Skill::Slow => Category::Blue,
// ----------------- // -----------------
// Test // Test
// ----------------- // -----------------
Skill::TestTouch => Category::Physical, Skill::TestTouch => Category::Red,
Skill::TestStun => Category::Physical, Skill::TestStun => Category::Red,
Skill::TestParry => Category::Physical, Skill::TestParry => Category::Red,
Skill::TestBlock => Category::Physical, Skill::TestBlock => Category::Red,
Skill::TestDrain => Category::Spell, Skill::TestSiphon => Category::Blue,
} }
} }
@ -574,7 +574,7 @@ impl Skill {
match self { match self {
Skill::TriageTick => true, Skill::TriageTick => true,
Skill::DecayTick => true, Skill::DecayTick => true,
Skill::DrainTick => true, Skill::SiphonTick => true,
_ => false, _ => false,
} }
} }
@ -583,10 +583,10 @@ impl Skill {
match self { match self {
// defensive block // defensive block
Skill::Block => 10, // reduce dmg Skill::Block => 10, // reduce damage
Skill::Parry => 10, // avoid all dmg Skill::Parry => 10, // avoid all damage
Skill::Snare => 10, Skill::Snare => 10,
Skill::Shield => 10, // avoid magic dmg, Skill::Shield => 10, // avoid magic damage,
// fast phys combat // fast phys combat
Skill::Attack => 5, Skill::Attack => 5,
@ -607,14 +607,14 @@ impl Skill {
// general combat // general combat
Skill::DecayTick => 2, // hot Skill::DecayTick => 2, // hot
Skill::Drain => 2, Skill::Siphon => 2,
Skill::DrainTick => 2, // hot Skill::SiphonTick => 2, // hot
Skill::Hex => 2, Skill::Hex => 2,
Skill::Pause => 2, // extend durations Skill::Pause => 2, // extend durations
Skill::Plague => 2, // aoe dot Skill::Plague => 2, // aoe dot
Skill::Silence => 2, Skill::Silence => 2,
Skill::Stun => 2, Skill::Stun => 2,
Skill::Throw => 2, // no dmg stun, adds vulnerable Skill::Throw => 2, // no damage stun, adds vulnerable
Skill::TriageTick => 2, // hot Skill::TriageTick => 2, // hot
Skill::Heal => 1, Skill::Heal => 1,
@ -644,7 +644,7 @@ impl Skill {
Skill::TestStun => 5, Skill::TestStun => 5,
Skill::TestBlock => 10, Skill::TestBlock => 10,
Skill::TestParry => 10, Skill::TestParry => 10,
Skill::TestDrain => 10, Skill::TestSiphon => 10,
} }
} }
@ -664,7 +664,7 @@ impl Skill {
return resolution; return resolution;
} }
match self.category() == Category::Physical { match self.category() == Category::Red {
true => { true => {
if let Some(evasion) = target.evade(*self) { if let Some(evasion) = target.evade(*self) {
resolution.results.push(evasion); resolution.results.push(evasion);
@ -703,7 +703,7 @@ impl Skill {
Skill::Heal => heal(source, target, resolution), Skill::Heal => heal(source, target, resolution),
Skill::Triage => triage(source, target, resolution), // hot Skill::Triage => triage(source, target, resolution), // hot
Skill::TriageTick => triage_tick(source, target, resolution), // hot Skill::TriageTick => triage_tick(source, target, resolution), // hot
Skill::Throw => throw(source, target, resolution), // no dmg stun, adds vulnerable Skill::Throw => throw(source, target, resolution), // no damage stun, adds vulnerable
Skill::Charm => panic!("nyi"), // target casts random spell on teammate Skill::Charm => panic!("nyi"), // target casts random spell on teammate
Skill::Calm => panic!("nyi"), // physical fear, taunt removal Skill::Calm => panic!("nyi"), // physical fear, taunt removal
Skill::Rez => panic!("nyi"), Skill::Rez => panic!("nyi"),
@ -712,11 +712,11 @@ impl Skill {
// Destruction // Destruction
// ----------------- // -----------------
Skill::Blast => blast(source, target, resolution), Skill::Blast => blast(source, target, resolution),
Skill::Amplify => amplify(source, target, resolution), // increase magic dmg Skill::Amplify => amplify(source, target, resolution), // increase magic damage
Skill::Decay => decay(source, target, resolution), // dot Skill::Decay => decay(source, target, resolution), // dot
Skill::DecayTick => decay_tick(source, target, resolution), // dot Skill::DecayTick => decay_tick(source, target, resolution), // dot
Skill::Drain => drain(source, target, resolution), Skill::Siphon => siphon(source, target, resolution),
Skill::DrainTick => drain_tick(source, target, resolution), // hot Skill::SiphonTick => siphon_tick(source, target, resolution), // hot
Skill::Curse => curse(source, target, resolution), Skill::Curse => curse(source, target, resolution),
Skill::Plague => panic!("nyi"), // dot that spreads every turn Skill::Plague => panic!("nyi"), // dot that spreads every turn
Skill::Ruin => panic!("nyi"), // aoe version of blast Skill::Ruin => panic!("nyi"), // aoe version of blast
@ -725,9 +725,9 @@ impl Skill {
// Purity // Purity
// ----------------- // -----------------
// Skill::Precision => panic!("nyi"), // Skill::Precision => panic!("nyi"),
Skill::Empower => empower(source, target, resolution), // increased phys dmg Skill::Empower => empower(source, target, resolution), // increased phys damage
Skill::Slay => panic!("nyi"), // phys dmg mult by target magic dmg Skill::Slay => panic!("nyi"), // phys damage mult by target magic damage
Skill::Shield => shield(source, target, resolution), // target is immune to magic dmg and fx Skill::Shield => shield(source, target, resolution), // target is immune to magic damage and fx
Skill::Silence => silence(source, target, resolution), // target cannot cast spells Skill::Silence => silence(source, target, resolution), // target cannot cast spells
Skill::Inquiry => panic!("nyi"), // Skill::Inquiry => panic!("nyi"), //
Skill::Purify => purify(source, target, resolution), // dispel all debuffs Skill::Purify => purify(source, target, resolution), // dispel all debuffs
@ -751,7 +751,7 @@ impl Skill {
Skill::TestStun => stun(source, target, resolution), Skill::TestStun => stun(source, target, resolution),
Skill::TestBlock => block(source, target, resolution), Skill::TestBlock => block(source, target, resolution),
Skill::TestParry => parry(source, target, resolution), Skill::TestParry => parry(source, target, resolution),
Skill::TestDrain => drain(source, target, resolution), Skill::TestSiphon => siphon(source, target, resolution),
} }
} }
@ -780,8 +780,8 @@ impl Skill {
} }
fn attack(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn attack(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.phys_dmg(); let amount = cryp.red_damage();
resolution.results.push(target.deal_phys_dmg(Skill::Attack, amount)); resolution.results.push(target.deal_red_damage(Skill::Attack, amount));
return resolution; return resolution;
} }
@ -828,7 +828,7 @@ fn empower(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> R
} }
fn heal(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn heal(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg(); let amount = cryp.blue_damage();
resolution.results.push(target.heal(Skill::Heal, amount)); resolution.results.push(target.heal(Skill::Heal, amount));
return resolution; return resolution;
} }
@ -858,14 +858,14 @@ fn triage(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Res
} }
fn triage_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn triage_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg().wrapping_div(2); let amount = cryp.blue_damage().wrapping_div(2);
resolution.results.push(target.heal(Skill::TriageTick, amount)); resolution.results.push(target.heal(Skill::TriageTick, amount));
return resolution; return resolution;
} }
fn blast(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn blast(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg(); let amount = cryp.blue_damage();
resolution.results.push(target.deal_spell_dmg(Skill::Blast, amount)); resolution.results.push(target.deal_blue_damage(Skill::Blast, amount));
return resolution; return resolution;
} }
@ -898,8 +898,8 @@ fn decay(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Reso
} }
fn decay_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn decay_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg(); let amount = cryp.blue_damage();
resolution.results.push(target.deal_spell_dmg(Skill::DecayTick, amount)); resolution.results.push(target.deal_blue_damage(Skill::DecayTick, amount));
return resolution; return resolution;
} }
@ -915,28 +915,28 @@ fn curse(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Res
return resolution;; return resolution;;
} }
fn drain(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn siphon(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let drain = CrypEffect { let siphon = CrypEffect {
effect: Effect::Drain, effect: Effect::Siphon,
duration: Effect::Drain.duration(), duration: Effect::Siphon.duration(),
tick: Some(Cast::new_tick(cryp, target, Skill::DrainTick)), tick: Some(Cast::new_tick(cryp, target, Skill::SiphonTick)),
}; };
resolution.results.push(target.add_effect(Skill::Drain, drain)); resolution.results.push(target.add_effect(Skill::Siphon, siphon));
return resolution;; return resolution;;
} }
fn drain_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution { fn siphon_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg(); let amount = cryp.blue_damage();
let drain_dmg = target.deal_spell_dmg(Skill::DrainTick, amount); let siphon_damage = target.deal_blue_damage(Skill::SiphonTick, amount);
resolution.results.push(drain_dmg.clone()); resolution.results.push(siphon_damage.clone());
match drain_dmg { match siphon_damage {
ResolutionResult::Damage { amount, mitigation, category: _, immunity } => { ResolutionResult::Damage { amount, mitigation, category: _, immunity } => {
if !immunity.immune { if !immunity.immune {
resolution.results.push(cryp.heal(Skill::Heal, amount)); resolution.results.push(cryp.heal(Skill::Heal, amount));
} }
}, },
_ => panic!("drain tick dmg not dealt {:?}", drain_dmg), _ => panic!("siphon tick damage not dealt {:?}", siphon_damage),
} }
return resolution; return resolution;
@ -960,7 +960,7 @@ fn purge(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Res
if !immune { if !immune {
for (i, ce) in target.effects.clone().iter_mut().enumerate() { for (i, ce) in target.effects.clone().iter_mut().enumerate() {
if ce.effect.category() == Category::SpellBuff { if ce.effect.category() == Category::BlueBuff {
target.effects.remove(i); target.effects.remove(i);
resolution.results.push(ResolutionResult::Removal { effect: ce.effect, immunity: immunity.clone() }); resolution.results.push(ResolutionResult::Removal { effect: ce.effect, immunity: immunity.clone() });
} }
@ -976,7 +976,7 @@ fn purify(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Re
if !immune { if !immune {
for (i, ce) in target.effects.clone().iter_mut().enumerate() { for (i, ce) in target.effects.clone().iter_mut().enumerate() {
if ce.effect.category() == Category::SpellDebuff { if ce.effect.category() == Category::BlueDebuff {
target.effects.remove(i); target.effects.remove(i);
resolution.results.push(ResolutionResult::Removal { effect: ce.effect, immunity: immunity.clone() }); resolution.results.push(ResolutionResult::Removal { effect: ce.effect, immunity: immunity.clone() });
} }
@ -1011,7 +1011,7 @@ mod tests {
.learn(Skill::Heal) .learn(Skill::Heal)
.create(); .create();
x.deal_phys_dmg(Skill::Attack, 5); x.deal_red_damage(Skill::Attack, 5);
heal(&mut y, &mut x, Resolution::new(Skill::Heal)); heal(&mut y, &mut x, Resolution::new(Skill::Heal));
} }
@ -1051,7 +1051,7 @@ mod tests {
.create(); .create();
// ensure it doesn't have 0 pd // ensure it doesn't have 0 pd
x.phys_dmg.force(100); x.red_damage.force(100);
y.hp.force(500); y.hp.force(500);
block(&mut y.clone(), &mut y, Resolution::new(Skill::Block)); block(&mut y.clone(), &mut y, Resolution::new(Skill::Block));
@ -1078,13 +1078,13 @@ mod tests {
.create(); .create();
// ensure it doesn't have 0 sd // ensure it doesn't have 0 sd
x.spell_dmg.force(50); x.blue_damage.force(50);
// remove all mitigation // remove all mitigation
y.armour.force(0); y.red_shield.force(0);
y.spell_shield.force(0); y.blue_shield.force(0);
y.deal_phys_dmg(Skill::Attack, 5); y.deal_red_damage(Skill::Attack, 5);
let prev_hp = y.hp(); let prev_hp = y.hp();
let res = Resolution::new(Skill::Triage); let res = Resolution::new(Skill::Triage);
@ -1118,11 +1118,11 @@ mod tests {
.level(8) .level(8)
.create(); .create();
x.spell_dmg.force(50); x.blue_damage.force(50);
amplify(&mut x.clone(), &mut x, Resolution::new(Skill::Amplify)); amplify(&mut x.clone(), &mut x, Resolution::new(Skill::Amplify));
assert!(x.effects.iter().any(|e| e.effect == Effect::Amplify)); assert!(x.effects.iter().any(|e| e.effect == Effect::Amplify));
assert_eq!(x.spell_dmg(), 100); assert_eq!(x.blue_damage(), 100);
} }
#[test] #[test]

View File

@ -25,30 +25,30 @@ impl Spec {
pub fn apply(&self, modified: u64, base: u64) -> u64 { pub fn apply(&self, modified: u64, base: u64) -> u64 {
match self.spec { match self.spec {
SpecType::PhysDamage5 => modified + (base * 5 / 100), SpecType::RedDamage5 => modified + (base * 5 / 100),
SpecType::SpellDamage5 => modified + (base * 5 / 100), SpecType::BlueDamage5 => modified + (base * 5 / 100),
} }
} }
} }
#[derive(Debug,Copy,Clone,Serialize,Deserialize,PartialEq)] #[derive(Debug,Copy,Clone,Serialize,Deserialize,PartialEq)]
pub enum SpecType { pub enum SpecType {
PhysDamage5, RedDamage5,
SpellDamage5, BlueDamage5,
} }
impl SpecType { impl SpecType {
fn affects(&self) -> Stat { fn affects(&self) -> Stat {
match *self { match *self {
SpecType::PhysDamage5 => Stat::PhysicalDamage, SpecType::RedDamage5 => Stat::RedDamage,
SpecType::SpellDamage5 => Stat::SpellDamage, SpecType::BlueDamage5 => Stat::BlueDamage,
} }
} }
fn level(&self) -> SpecLevel { fn level(&self) -> SpecLevel {
match *self { match *self {
SpecType::PhysDamage5 => SpecLevel::Common, SpecType::RedDamage5 => SpecLevel::Common,
SpecType::SpellDamage5 => SpecLevel::Common, SpecType::BlueDamage5 => SpecLevel::Common,
} }
} }
} }

406
server/src/vbox.rs Normal file
View File

@ -0,0 +1,406 @@
use std::iter;
use uuid::Uuid;
// drops
use rand::prelude::*;
use rand::{thread_rng};
use rand::distributions::{WeightedIndex};
use serde_cbor::{from_slice, to_vec};
use postgres::transaction::Transaction;
use failure::Error;
use failure::err_msg;
use account::Account;
use rpc::{VboxStateParams, VboxAcceptParams, VboxDiscardParams, VboxCombineParams, VboxApplyParams, VboxDropParams};
use skill::{Skill};
use cryp::{cryp_get, cryp_write};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Var {
Blue,
Green,
Red,
Attack,
Block,
Stun,
Buff,
Debuff,
Amplify,
Banish,
Blast,
Curse,
Empower,
Haste,
Heal,
Hex,
Parry,
Purge,
Purify,
Reflect,
Ruin,
Shield,
Silence,
Slay,
Slow,
Snare,
Strangle,
Strike,
Siphon,
Survival,
Taunt,
Throw,
Toxic,
Triage,
}
impl Var {
fn is_base(&self) -> bool {
match self {
Var::Attack |
Var::Block |
Var::Stun |
Var::Debuff |
Var::Buff => true,
_ => false,
}
}
fn skill(&self) -> Result<Skill, Error> {
match self {
Var::Amplify => Ok(Skill::Amplify),
Var::Banish => Ok(Skill::Banish),
Var::Blast => Ok(Skill::Blast),
Var::Curse => Ok(Skill::Curse),
Var::Empower => Ok(Skill::Empower),
Var::Haste => Ok(Skill::Haste),
Var::Heal => Ok(Skill::Heal),
Var::Hex => Ok(Skill::Hex),
Var::Parry => Ok(Skill::Parry),
Var::Purge => Ok(Skill::Purge),
Var::Purify => Ok(Skill::Purify),
// Var::Reflect => Ok(Skill::Reflect),
Var::Ruin => Ok(Skill::Ruin),
Var::Shield => Ok(Skill::Shield),
Var::Silence => Ok(Skill::Silence),
Var::Slay => Ok(Skill::Slay),
Var::Slow => Ok(Skill::Slow),
Var::Snare => Ok(Skill::Snare),
Var::Strangle => Ok(Skill::Strangle),
// Var::Strike => Ok(Skill::Strike),
// Var::Survival => Ok(Skill::Survival),
// Var::Taunt => Ok(Skill::Taunt),
Var::Throw => Ok(Skill::Throw),
// Var::Toxic => Ok(Skill::Toxic),
Var::Triage => Ok(Skill::Triage),
_ => Err(err_msg("not a usable var"))
}
}
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
enum ColourCode {
RR,
GG,
BB,
RG,
BR,
GB,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Vbox {
pub id: Uuid,
pub balance: u16,
pub free: Vec<Var>,
pub bound: Vec<Var>,
pub game: Uuid,
pub account: Uuid,
}
impl Vbox {
pub fn new(account_id: Uuid, game_id: Uuid) -> Vbox {
Vbox {
id: Uuid::new_v4(),
account: account_id,
game: game_id,
free: vec![],
bound: vec![],
balance: 0,
}
}
pub fn fill(mut self: Vbox) -> Vbox {
let vars = vec![
(Var::Red, 1),
(Var::Green, 1),
(Var::Blue, 1),
(Var::Attack, 1),
(Var::Block, 1),
(Var::Buff, 1),
(Var::Debuff, 1),
(Var::Stun, 1),
];
self.free = iter::
repeat_with(|| {
let mut rng = thread_rng();
let dist = WeightedIndex::new(vars.iter().map(|item| item.1)).unwrap();
return vars[dist.sample(&mut rng)].0;
})
.take(8)
.collect::<Vec<Var>>();
self
}
pub fn accept(&mut self, i: usize) -> Result<&mut Vbox, Error> {
if self.bound.len() >= 9 {
return Err(err_msg("too many vars bound"));
}
self.free.get(i).ok_or(format_err!("no var at index {:?}", i))?;
self.bound.push(self.free.remove(i));
Ok(self)
}
pub fn drop(&mut self, i: usize) -> Result<&mut Vbox, Error> {
self.bound.get(i).ok_or(format_err!("no var at index {:?}", i))?;
self.bound.remove(i);
// balance update
Ok(self)
}
pub fn combine(&mut self, mut indices: Vec<usize>) -> Result<&mut Vbox, Error> {
if indices.len() != 3 {
return Err(err_msg("exactly 3 indices required"));
}
if !indices.iter().all(|i| self.bound.get(*i).is_some()) {
return Err(err_msg("var missing index"));
}
// have to sort the indices and keep track of the iteration
// because when removing the elements the array shifts
indices.sort();
let mut vars = indices
.iter()
.enumerate()
.map(|(i, index)| {
self.bound.remove(*index - i)
})
.collect::<Vec<Var>>();
let base_index = vars
.iter()
.position(|v| v.is_base())
.ok_or(err_msg("no base item selected"))?;
let base = vars.remove(base_index);
// fold colours into RGB
let colours = vars
.iter()
.fold([0, 0, 0], |mut acc, c| {
match c {
Var::Red => acc[0] += 1,
Var::Green => acc[1] += 1,
Var::Blue => acc[2] += 1,
_ => (),
};
acc
});
let colour_code = match colours {
[2,0,0] => ColourCode::RR,
[0,2,0] => ColourCode::GG,
[0,0,2] => ColourCode::BB,
[1,1,0] => ColourCode::RG,
[0,1,1] => ColourCode::GB,
[1,0,1] => ColourCode::BR,
_ => return Err(err_msg("not a combo")),
};
let new = match base {
Var::Attack => match colour_code {
ColourCode::RR => Var::Strike,
ColourCode::GG => Var::Heal,
ColourCode::BB => Var::Blast,
ColourCode::RG => Var::Slay, //
ColourCode::GB => return Err(err_msg("unhandled skill combo")),
ColourCode::BR => Var::Banish, //
},
Var::Block => match colour_code {
ColourCode::RR => Var::Parry,
ColourCode::GG => Var::Reflect,
ColourCode::BB => Var::Toxic,
ColourCode::RG => Var::Taunt,
ColourCode::GB => Var::Shield,
ColourCode::BR => return Err(err_msg("unhandled skill combo")),
},
Var::Buff => match colour_code {
ColourCode::RR => Var::Empower,
ColourCode::GG => Var::Triage,
ColourCode::BB => Var::Amplify,
ColourCode::RG => Var::Survival,
ColourCode::GB => return Err(err_msg("unhandled skill combo")),
ColourCode::BR => Var::Haste,
},
Var::Debuff => match colour_code {
ColourCode::RR => Var::Snare,
ColourCode::GG => Var::Purge,
ColourCode::BB => Var::Curse,
ColourCode::RG => return Err(err_msg("unhandled skill combo")),
ColourCode::GB => Var::Siphon,
ColourCode::BR => Var::Slow,
},
Var::Stun => match colour_code {
ColourCode::RR => Var::Strangle,
ColourCode::GG => Var::Throw,
ColourCode::BB => Var::Ruin,
ColourCode::RG => return Err(err_msg("unhandled skill combo")),
ColourCode::GB => Var::Silence,
ColourCode::BR => Var::Hex,
},
_ => panic!("wrong base {:?}", base),
};
self.bound.push(new);
Ok(self)
}
}
pub fn vbox_create(vbox: Vbox, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let vbox_bytes = to_vec(&vbox)?;
let query = "
INSERT INTO vbox (id, account, game, data)
VALUES ($1, $2, $3, $4)
RETURNING id;
";
let result = tx
.query(query, &[&vbox.id, &account.id, &vbox.game, &vbox_bytes])?;
result.iter().next().ok_or(format_err!("no vbox written"))?;
// println!("{:} wrote vbox", vbox.id);
return Ok(vbox);
}
pub fn vbox_write(vbox: Vbox, tx: &mut Transaction) -> Result<Vbox, Error> {
let vbox_bytes = to_vec(&vbox)?;
let query = "
UPDATE vbox
SET data = $1
WHERE id = $2
RETURNING id, account, data;
";
let result = tx
.query(query, &[&vbox_bytes, &vbox.id])?;
result.iter().next().ok_or(err_msg("no vbox row returned"))?;
// println!("{:?} wrote vbox", vbox.id);
return Ok(vbox);
}
pub fn vbox_get(tx: &mut Transaction, game_id: Uuid, account: &Account) -> Result<Vbox, Error> {
let query = "
SELECT *
FROM vbox
WHERE account = $1
AND game = $2;
";
let result = tx
.query(query, &[&account.id, &game_id])?;
let returned = match result.iter().next() {
Some(row) => row,
None => return Err(err_msg("vbox not found")),
};
// tells from_slice to cast into a cryp
let vbox_bytes: Vec<u8> = returned.get("data");
let vbox = from_slice::<Vbox>(&vbox_bytes)?;
return Ok(vbox);
}
pub fn vbox_state(params: VboxStateParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
match vbox_get(tx, params.game_id, account) {
Ok(v) => Ok(v),
Err(e) => {
println!("{:?}", e);
vbox_create(Vbox::new(account.id, params.game_id).fill(), tx, account)
}
}
}
pub fn vbox_discard(params: VboxDiscardParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let vbox = vbox_get(tx, params.game_id, account)?;
return vbox_write(vbox.fill(), tx);
}
pub fn vbox_accept(params: VboxAcceptParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
vbox.accept(params.index)?;
return vbox_write(vbox, tx);
}
pub fn vbox_combine(params: VboxCombineParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
vbox.combine(params.indices)?;
return vbox_write(vbox, tx);
}
pub fn vbox_drop(params: VboxDropParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
vbox.drop(params.index)?;
return vbox_write(vbox, tx);
}
pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
let mut cryp = cryp_get(tx, params.cryp_id, account.id)?;
let var = vbox.bound.remove(params.index);
// done here because i teach them a tonne of skills for tests
let max_skills = 4;
if cryp.skills.len() >= max_skills {
return Err(format_err!("cryp at max skills ({:?})", max_skills));
}
let skill = var.skill()?;
cryp = cryp.learn(skill);
cryp_write(cryp, tx)?;
return vbox_write(vbox, tx);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn combine_test() {
let mut vbox = Vbox::new(Uuid::new_v4(), Uuid::new_v4());
vbox.bound = vec![Var::Attack, Var::Green, Var::Green];
vbox.combine(vec![1,2,0]).unwrap();
assert_eq!(vbox.bound[0], Var::Heal);
}
}