Merge branch 'develop' of ssh://git.mnml.gg:40022/~/mnml into develop
This commit is contained in:
commit
500584ab10
@ -116,7 +116,7 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
.reclaiming {
|
.Refunding {
|
||||||
button:not([disabled]) {
|
button:not([disabled]) {
|
||||||
&, &:hover, &:active {
|
&, &:hover, &:active {
|
||||||
background: @red;
|
background: @red;
|
||||||
|
|||||||
@ -49,7 +49,7 @@ export const setTeamSelect = value => ({ type: 'SET_TEAM_SELECT', value: Array.f
|
|||||||
export const setTutorial = value => ({ type: 'SET_TUTORIAL', value });
|
export const setTutorial = value => ({ type: 'SET_TUTORIAL', value });
|
||||||
export const setTutorialGame = value => ({ type: 'SET_TUTORIAL_GAME', value });
|
export const setTutorialGame = value => ({ type: 'SET_TUTORIAL_GAME', value });
|
||||||
|
|
||||||
export const setVboxSelected = value => ({ type: 'SET_VBOX_SELECTED', value });
|
export const setVboxSelected = value => ({ type: 'SET_VBOX_SELECTED', value: Object.create(value) });
|
||||||
export const setVboxCombiner = value => ({ type: 'SET_VBOX_COMBINER', value });
|
export const setVboxCombiner = value => ({ type: 'SET_VBOX_COMBINER', value });
|
||||||
export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value });
|
export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value });
|
||||||
export const setVboxInfo = value => ({ type: 'SET_VBOX_INFO', value });
|
export const setVboxInfo = value => ({ type: 'SET_VBOX_INFO', value });
|
||||||
|
|||||||
@ -24,8 +24,8 @@ const addState = connect(
|
|||||||
tutorial,
|
tutorial,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
function sendVboxAcceptEquip(constructId) {
|
function sendVboxBuyEquip(constructId) {
|
||||||
return ws.sendVboxAcceptEquip(instance.id, vboxSelected.storeSelect[0][0], vboxSelected.storeSelect[0][1], constructId);
|
return ws.sendVboxBuyEquip(instance.id, vboxSelected.storeSelect[0][0], vboxSelected.storeSelect[0][1], constructId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxApply(constructId, i) {
|
function sendVboxApply(constructId, i) {
|
||||||
@ -40,7 +40,7 @@ const addState = connect(
|
|||||||
instance,
|
instance,
|
||||||
player,
|
player,
|
||||||
account,
|
account,
|
||||||
sendVboxAcceptEquip,
|
sendVboxBuyEquip,
|
||||||
sendVboxUnequipApply,
|
sendVboxUnequipApply,
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
itemInfo,
|
itemInfo,
|
||||||
@ -83,7 +83,7 @@ function Construct(props) {
|
|||||||
itemInfo,
|
itemInfo,
|
||||||
// Function Calls
|
// Function Calls
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
sendVboxAcceptEquip,
|
sendVboxBuyEquip,
|
||||||
sendVboxUnequipApply,
|
sendVboxUnequipApply,
|
||||||
setItemUnequip,
|
setItemUnequip,
|
||||||
setInfo,
|
setInfo,
|
||||||
@ -98,7 +98,7 @@ function Construct(props) {
|
|||||||
const duplicateSkill = construct.skills.length !== 0 && construct.skills.every(sk => {
|
const duplicateSkill = construct.skills.length !== 0 && construct.skills.every(sk => {
|
||||||
if (!itemEquip && itemEquip !== 0) return false;
|
if (!itemEquip && itemEquip !== 0) return false;
|
||||||
if (!sk) return false;
|
if (!sk) return false;
|
||||||
return sk.skill === vbox.bound[itemEquip];
|
return sk.skill === vbox.stash[itemEquip];
|
||||||
});
|
});
|
||||||
const tutorialDisableEquip = tutorialShouldDisableEquip(tutorial, iter, instance, construct);
|
const tutorialDisableEquip = tutorialShouldDisableEquip(tutorial, iter, instance, construct);
|
||||||
function onClick(e) {
|
function onClick(e) {
|
||||||
@ -106,7 +106,7 @@ function Construct(props) {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (duplicateSkill || tutorialDisableEquip) return true;
|
if (duplicateSkill || tutorialDisableEquip) return true;
|
||||||
if (itemEquip !== -1) return sendVboxApply(construct.id, itemEquip);
|
if (itemEquip !== -1) return sendVboxApply(construct.id, itemEquip);
|
||||||
if (vboxSelected.storeSelect.length === 1) return sendVboxAcceptEquip(construct.id);
|
if (vboxSelected.storeSelect.length === 1) return sendVboxBuyEquip(construct.id);
|
||||||
if (itemUnequip.length && itemUnequip[0] !== construct.id) return sendVboxUnequipApply(construct.id);
|
if (itemUnequip.length && itemUnequip[0] !== construct.id) return sendVboxUnequipApply(construct.id);
|
||||||
setItemUnequip([]);
|
setItemUnequip([]);
|
||||||
return true;
|
return true;
|
||||||
@ -136,7 +136,7 @@ function Construct(props) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const equipping = skillList.includes(vbox.bound[itemEquip]) && !skill
|
const equipping = skillList.includes(vbox.stash[itemEquip]) && !skill
|
||||||
&& !tutorialDisableEquip && !duplicateSkill && i === construct.skills.length;
|
&& !tutorialDisableEquip && !duplicateSkill && i === construct.skills.length;
|
||||||
const border = () => {
|
const border = () => {
|
||||||
if (!skill) return '';
|
if (!skill) return '';
|
||||||
@ -169,7 +169,7 @@ function Construct(props) {
|
|||||||
const s = construct.specs[i];
|
const s = construct.specs[i];
|
||||||
|
|
||||||
if (!s) {
|
if (!s) {
|
||||||
const equipping = specList.includes(vbox.bound[itemEquip]) && i === construct.specs.length;
|
const equipping = specList.includes(vbox.stash[itemEquip]) && i === construct.specs.length;
|
||||||
const classes = `${equipping ? 'equipping' : 'gray'} empty`;
|
const classes = `${equipping ? 'equipping' : 'gray'} empty`;
|
||||||
return (
|
return (
|
||||||
<button key={i} class={classes} disabled={!equipping} >
|
<button key={i} class={classes} disabled={!equipping} >
|
||||||
@ -261,7 +261,7 @@ class InstanceConstructs extends preact.Component {
|
|||||||
// Function calls
|
// Function calls
|
||||||
setInfo,
|
setInfo,
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
sendVboxAcceptEquip,
|
sendVboxBuyEquip,
|
||||||
sendVboxUnequipApply,
|
sendVboxUnequipApply,
|
||||||
setItemUnequip,
|
setItemUnequip,
|
||||||
} = props;
|
} = props;
|
||||||
@ -281,7 +281,7 @@ class InstanceConstructs extends preact.Component {
|
|||||||
setItemUnequip,
|
setItemUnequip,
|
||||||
player,
|
player,
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
sendVboxAcceptEquip,
|
sendVboxBuyEquip,
|
||||||
sendVboxUnequipApply,
|
sendVboxUnequipApply,
|
||||||
setInfo,
|
setInfo,
|
||||||
itemInfo,
|
itemInfo,
|
||||||
|
|||||||
@ -26,10 +26,17 @@ class Combiner extends preact.Component {
|
|||||||
|
|
||||||
const { stashSelect, storeSelect } = vboxSelected;
|
const { stashSelect, storeSelect } = vboxSelected;
|
||||||
|
|
||||||
|
function cost([group, i]) {
|
||||||
|
if (group === 'Colours') return 1;
|
||||||
|
if (group === 'Skills') return 2;
|
||||||
|
if (group === 'Specs') return 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
if (vboxCombiner) {
|
if (vboxCombiner) {
|
||||||
const combinerComboText = vboxCombiner.replace('Plus', '+');
|
const combinerComboText = vboxCombiner.replace('Plus', '+');
|
||||||
let bits = 0;
|
let bits = 0;
|
||||||
storeSelect.forEach(item => bits += item[0] + 1);
|
storeSelect.forEach(item => bits += cost(item));
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
class='combiner vbox-btn'
|
class='combiner vbox-btn'
|
||||||
@ -48,7 +55,7 @@ class Combiner extends preact.Component {
|
|||||||
class='combiner vbox-btn'
|
class='combiner vbox-btn'
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
onMouseDown={vboxBuySelected}>
|
onMouseDown={vboxBuySelected}>
|
||||||
{`Buy ${vbox.free[item[0]][item[1]]} ${item[0] + 1}b`}
|
{`Buy ${vbox.store[item[0]][item[1]]} ${cost(item)}b`}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,22 +27,22 @@ const addState = connect(
|
|||||||
return ws.clearTutorial(instance.id);
|
return ws.clearTutorial(instance.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxDiscard() {
|
function sendVboxRefill() {
|
||||||
return ws.sendVboxDiscard(instance.id);
|
return ws.sendVboxRefill(instance.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxAccept(group, index) {
|
function sendVboxBuy(group, index) {
|
||||||
if (!(vboxSelected.storeSelect.length === 1 && vboxSelected.stashSelect.length === 0)) return false;
|
if (!(vboxSelected.storeSelect.length === 1 && vboxSelected.stashSelect.length === 0)) return false;
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
return ws.sendVboxAccept(instance.id, group, index);
|
return ws.sendVboxBuy(instance.id, group, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxCombine() {
|
function sendVboxCombine() {
|
||||||
return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.storeSelect);
|
return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.storeSelect);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxReclaim(i) {
|
function sendVboxRefund(i) {
|
||||||
return ws.sendVboxReclaim(instance.id, i);
|
return ws.sendVboxRefund(instance.id, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendItemUnequip([constructId, item]) {
|
function sendItemUnequip([constructId, item]) {
|
||||||
@ -60,10 +60,10 @@ const addState = connect(
|
|||||||
|
|
||||||
clearTutorial,
|
clearTutorial,
|
||||||
sendItemUnequip,
|
sendItemUnequip,
|
||||||
sendVboxAccept,
|
sendVboxBuy,
|
||||||
sendVboxCombine,
|
sendVboxCombine,
|
||||||
sendVboxDiscard,
|
sendVboxRefill,
|
||||||
sendVboxReclaim,
|
sendVboxRefund,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -109,10 +109,10 @@ class Vbox extends preact.Component {
|
|||||||
clearTutorial,
|
clearTutorial,
|
||||||
dispatchVboxSelect,
|
dispatchVboxSelect,
|
||||||
sendItemUnequip,
|
sendItemUnequip,
|
||||||
sendVboxAccept,
|
sendVboxBuy,
|
||||||
sendVboxCombine,
|
sendVboxCombine,
|
||||||
sendVboxDiscard,
|
sendVboxRefill,
|
||||||
sendVboxReclaim,
|
sendVboxRefund,
|
||||||
setInfo,
|
setInfo,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ class Vbox extends preact.Component {
|
|||||||
|
|
||||||
const setVboxSelected = v => dispatchVboxSelect(v, { itemInfo, itemUnequip, vbox });
|
const setVboxSelected = v => dispatchVboxSelect(v, { itemInfo, itemUnequip, vbox });
|
||||||
const clearVboxSelected = () => setVboxSelected({ storeSelect: [], stashSelect: [] });
|
const clearVboxSelected = () => setVboxSelected({ storeSelect: [], stashSelect: [] });
|
||||||
const vboxBuySelected = () => sendVboxAccept(storeSelect[0][0], storeSelect[0][1]);
|
const vboxBuySelected = () => sendVboxBuy(storeSelect[0][0], storeSelect[0][1]);
|
||||||
|
|
||||||
function vboxHover(e, v) {
|
function vboxHover(e, v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
@ -151,7 +151,7 @@ class Vbox extends preact.Component {
|
|||||||
&& instance.time_control === 'Practice' && instance.rounds.length === 1)
|
&& instance.time_control === 'Practice' && instance.rounds.length === 1)
|
||||||
}
|
}
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
onMouseDown={() => sendVboxDiscard()}>
|
onMouseDown={() => sendVboxRefill()}>
|
||||||
refill <br />
|
refill <br />
|
||||||
2b
|
2b
|
||||||
</button>
|
</button>
|
||||||
@ -161,7 +161,7 @@ class Vbox extends preact.Component {
|
|||||||
|
|
||||||
function stashHdr() {
|
function stashHdr() {
|
||||||
const refund = storeSelect.length === 0 && stashSelect.length === 1
|
const refund = storeSelect.length === 0 && stashSelect.length === 1
|
||||||
? itemInfo.items.find(i => i.item === vbox.bound[stashSelect[0]]).cost
|
? itemInfo.items.find(i => i.item === vbox.stash[stashSelect[0]]).cost
|
||||||
: 0;
|
: 0;
|
||||||
const tutorialDisabled = tutorial && tutorial < 8
|
const tutorialDisabled = tutorial && tutorial < 8
|
||||||
&& instance.time_control === 'Practice' && instance.rounds.length === 1;
|
&& instance.time_control === 'Practice' && instance.rounds.length === 1;
|
||||||
@ -172,7 +172,7 @@ class Vbox extends preact.Component {
|
|||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
onMouseDown={e => {
|
onMouseDown={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
sendVboxReclaim(vboxSelected.stashSelect[0]);
|
sendVboxRefund(vboxSelected.stashSelect[0]);
|
||||||
}}>
|
}}>
|
||||||
refund <br />
|
refund <br />
|
||||||
{refund}b
|
{refund}b
|
||||||
|
|||||||
@ -81,7 +81,7 @@ class stashElement extends preact.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (notValidCombo) {
|
if (notValidCombo) {
|
||||||
setInfo(vbox.bound[i]);
|
setInfo(vbox.stash[i]);
|
||||||
return setVboxSelected({ storeSelect: [], stashSelect: [i] });
|
return setVboxSelected({ storeSelect: [], stashSelect: [i] });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class stashElement extends preact.Component {
|
|||||||
onDragOver={ev => ev.preventDefault()}
|
onDragOver={ev => ev.preventDefault()}
|
||||||
onDrop={stashClick}
|
onDrop={stashClick}
|
||||||
>
|
>
|
||||||
{range(0, 6).map(i => stashBtn(vbox.bound[i], i))}
|
{range(0, 6).map(i => stashBtn(vbox.stash[i], i.toString()))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class storeElement extends preact.Component {
|
|||||||
const { storeSelect, stashSelect } = vboxSelected;
|
const { storeSelect, stashSelect } = vboxSelected;
|
||||||
|
|
||||||
function availableBtn(v, group, index) {
|
function availableBtn(v, group, index) {
|
||||||
if (!v) return <button disabled class='empty' key={(group * 10) + index} > </button>;
|
if (!v) return <button disabled class='empty' key={group + index} > </button>;
|
||||||
const selected = storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index);
|
const selected = storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index);
|
||||||
|
|
||||||
const notValidCombo = vboxHighlight && !vboxHighlight.includes(v);
|
const notValidCombo = vboxHighlight && !vboxHighlight.includes(v);
|
||||||
@ -63,7 +63,7 @@ class storeElement extends preact.Component {
|
|||||||
const disabled = vbox.bits <= group;
|
const disabled = vbox.bits <= group;
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
key={group * 10 + index}
|
key={group + index}
|
||||||
onDragEnd={clearVboxSelected}>
|
onDragEnd={clearVboxSelected}>
|
||||||
<button
|
<button
|
||||||
class={classes}
|
class={classes}
|
||||||
@ -81,11 +81,11 @@ class storeElement extends preact.Component {
|
|||||||
<div class='store'
|
<div class='store'
|
||||||
onClick={e => e.stopPropagation()}>
|
onClick={e => e.stopPropagation()}>
|
||||||
<div class="vbox-colours">
|
<div class="vbox-colours">
|
||||||
{range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))}
|
{range(0, 6).map(i => availableBtn(vbox.store['Colours'][i], 'Colours', i.toString()))}
|
||||||
</div>
|
</div>
|
||||||
<div class="vbox-items">
|
<div class="vbox-items">
|
||||||
{range(0, 3).map(i => availableBtn(vbox.free[1][i], 1, i))}
|
{range(0, 3).map(i => availableBtn(vbox.store['Skills'][i], 'Skills', i.toString()))}
|
||||||
{range(0, 3).map(i => availableBtn(vbox.free[2][i], 2, i))}
|
{range(0, 3).map(i => availableBtn(vbox.store['Specs'][i], 'Specs', i.toString()))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -21,10 +21,10 @@ function setVboxState(dispatch, vboxSelected, state) {
|
|||||||
let vboxCombiner = false;
|
let vboxCombiner = false;
|
||||||
let vboxHighlight = false;
|
let vboxHighlight = false;
|
||||||
|
|
||||||
if (!(storeSelect.length === 0 && stashSelect.length === 0)) {
|
if (storeSelect.length || stashSelect.length) {
|
||||||
vboxHighlight = [];
|
vboxHighlight = [];
|
||||||
const stashItems = stashSelect.map(j => vbox.bound[j]);
|
const stashItems = stashSelect.map(j => vbox.stash[j]);
|
||||||
const shopItems = storeSelect.map(j => vbox.free[j[0]][j[1]]);
|
const shopItems = storeSelect.map(j => vbox.store[j[0]][j[1]]);
|
||||||
|
|
||||||
const selectedItems = stashItems.concat(shopItems);
|
const selectedItems = stashItems.concat(shopItems);
|
||||||
const itemCount = countBy(selectedItems, co => co);
|
const itemCount = countBy(selectedItems, co => co);
|
||||||
@ -55,18 +55,18 @@ function setVboxState(dispatch, vboxSelected, state) {
|
|||||||
const vboxInfo = () => {
|
const vboxInfo = () => {
|
||||||
if (vboxCombiner) return vboxCombiner;
|
if (vboxCombiner) return vboxCombiner;
|
||||||
if (itemUnequip.length) return itemUnequip[1];
|
if (itemUnequip.length) return itemUnequip[1];
|
||||||
const stashBase = stashSelect.find(i => !(['Red', 'Blue', 'Green'].includes(vbox.bound[i])));
|
const stashBase = stashSelect.find(i => !(['Red', 'Blue', 'Green'].includes(vbox.stash[i])));
|
||||||
if (stashBase > -1) return vbox.bound[stashBase];
|
if (stashBase > -1) return vbox.stash[stashBase];
|
||||||
const storeBase = storeSelect.find(j => !(['Red', 'Blue', 'Green'].includes(vbox.free[j[0]][j[1]])));
|
const storeBase = storeSelect.find(j => !(['Red', 'Blue', 'Green'].includes(vbox.store[j[0]][j[1]])));
|
||||||
if (storeBase) return vbox.free[storeBase[0]][storeBase[1]];
|
if (storeBase) return vbox.store[storeBase[0]][storeBase[1]];
|
||||||
if (stashSelect.length > 0) return vbox.bound[stashSelect[0]];
|
if (stashSelect.length > 0) return vbox.stash[stashSelect[0]];
|
||||||
if (storeSelect.length > 0) return vbox.free[storeSelect[0][0]][storeSelect[0][1]];
|
if (storeSelect.length > 0) return vbox.store[storeSelect[0][0]][storeSelect[0][1]];
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch(actions.setVboxInfo(vboxInfo()));
|
dispatch(actions.setVboxInfo(vboxInfo()));
|
||||||
dispatch(actions.setVboxCombiner(vboxCombiner));
|
dispatch(actions.setVboxCombiner(vboxCombiner));
|
||||||
dispatch(actions.setVboxHighlight(vboxHighlight));
|
dispatch(actions.setVboxHighlight(vboxHighlight.length ? vboxHighlight : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
function genItemInfo(item, itemInfo, player) {
|
function genItemInfo(item, itemInfo, player) {
|
||||||
@ -124,5 +124,10 @@ function genItemInfo(item, itemInfo, player) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cost(group) {
|
||||||
|
if (group === 'Colours') return 1;
|
||||||
|
if (group === 'Skills') return 2;
|
||||||
|
if (group === 'Specs') return 3;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = { setVboxState, genItemInfo };
|
module.exports = { setVboxState, genItemInfo, cost };
|
||||||
|
|||||||
@ -45,10 +45,10 @@ module.exports = {
|
|||||||
item: 'READY',
|
item: 'READY',
|
||||||
description: 'Ready for the game to begin. When all players are ready the first VBOX PHASE begins.',
|
description: 'Ready for the game to begin. When all players are ready the first VBOX PHASE begins.',
|
||||||
},
|
},
|
||||||
reclaim: {
|
Refund: {
|
||||||
item: 'RECLAIM',
|
item: 'Refund',
|
||||||
description: <p>Reclaim items refunding the listed cost of the item.<br />
|
description: <p>Refund items refunding the listed cost of the item.<br />
|
||||||
Click to enable and then click the item to reclaim.</p>,
|
Click to enable and then click the item to Refund.</p>,
|
||||||
},
|
},
|
||||||
refill: {
|
refill: {
|
||||||
item: 'REFILL',
|
item: 'REFILL',
|
||||||
|
|||||||
@ -10,6 +10,7 @@ function setupKeys(store) {
|
|||||||
key('esc', () => store.dispatch(actions.setInfo(null)));
|
key('esc', () => store.dispatch(actions.setInfo(null)));
|
||||||
key('esc', () => store.dispatch(actions.setItemUnequip([])));
|
key('esc', () => store.dispatch(actions.setItemUnequip([])));
|
||||||
key('esc', () => store.dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] })));
|
key('esc', () => store.dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] })));
|
||||||
|
key('esc', () => store.dispatch(actions.setVboxHighlight(null)));
|
||||||
key('esc', () => store.dispatch(actions.setMtxActive(null)));
|
key('esc', () => store.dispatch(actions.setMtxActive(null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ const toast = require('izitoast');
|
|||||||
const cbor = require('borc');
|
const cbor = require('borc');
|
||||||
|
|
||||||
const throttle = require('lodash/throttle');
|
const throttle = require('lodash/throttle');
|
||||||
|
const groupBy = require('lodash/groupBy');
|
||||||
|
|
||||||
const SOCKET_URL =
|
const SOCKET_URL =
|
||||||
`${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`;
|
`${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`;
|
||||||
@ -77,13 +78,13 @@ function createSocket(events) {
|
|||||||
send(['InstanceChat', { instance_id: instanceId, index }]);
|
send(['InstanceChat', { instance_id: instanceId, index }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxAccept(instanceId, group, index) {
|
function sendVboxBuy(instanceId, group, index) {
|
||||||
send(['VboxAccept', { instance_id: instanceId, group, index }]);
|
send(['VboxBuy', { instance_id: instanceId, group, index }]);
|
||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxAcceptEquip(instanceId, group, index, constructId) {
|
function sendVboxBuyEquip(instanceId, group, index, constructId) {
|
||||||
send(['VboxAcceptEquip', { instance_id: instanceId, group, index, construct_id: constructId }]);
|
send(['VboxBuy', { instance_id: instanceId, group, index, construct_id: constructId }]);
|
||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,18 +103,20 @@ function createSocket(events) {
|
|||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxDiscard(instanceId) {
|
function sendVboxRefill(instanceId) {
|
||||||
send(['VboxDiscard', { instance_id: instanceId }]);
|
send(['VboxRefill', { instance_id: instanceId }]);
|
||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxCombine(instanceId, invIndicies, vboxIndicies) {
|
function sendVboxCombine(instanceId, invIndicies, vboxIndicies) {
|
||||||
send(['VboxCombine', { instance_id: instanceId, inv_indices: invIndicies, vbox_indices: vboxIndicies }]);
|
const formatted = {};
|
||||||
|
vboxIndicies.forEach(p => formatted[p[0]] ? formatted[p[0]].push(p[1]) : formatted[p[0]] = [p[1]]);
|
||||||
|
send(['VboxCombine', { instance_id: instanceId, inv_indices: invIndicies, vbox_indices: formatted }]);
|
||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxReclaim(instanceId, index) {
|
function sendVboxRefund(instanceId, index) {
|
||||||
send(['VboxReclaim', { instance_id: instanceId, index }]);
|
send(['VboxRefund', { instance_id: instanceId, index }]);
|
||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,12 +207,6 @@ function createSocket(events) {
|
|||||||
send(['SubscriptionState', {}]);
|
send(['SubscriptionState', {}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearTutorial(instanceId) {
|
|
||||||
events.clearTutorial();
|
|
||||||
events.clearInstance();
|
|
||||||
sendInstanceState(instanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------
|
// -------------
|
||||||
// Incoming
|
// Incoming
|
||||||
// -------------
|
// -------------
|
||||||
@ -416,12 +413,12 @@ function createSocket(events) {
|
|||||||
sendInstanceChat,
|
sendInstanceChat,
|
||||||
sendInstanceLeave,
|
sendInstanceLeave,
|
||||||
|
|
||||||
sendVboxAccept,
|
sendVboxBuy,
|
||||||
sendVboxAcceptEquip,
|
sendVboxBuyEquip,
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
sendVboxReclaim,
|
sendVboxRefund,
|
||||||
sendVboxCombine,
|
sendVboxCombine,
|
||||||
sendVboxDiscard,
|
sendVboxRefill,
|
||||||
sendVboxUnequip,
|
sendVboxUnequip,
|
||||||
sendVboxUnequipApply,
|
sendVboxUnequipApply,
|
||||||
|
|
||||||
@ -436,8 +433,6 @@ function createSocket(events) {
|
|||||||
sendMtxBuy,
|
sendMtxBuy,
|
||||||
sendMtxConstructSpawn,
|
sendMtxConstructSpawn,
|
||||||
|
|
||||||
clearTutorial,
|
|
||||||
|
|
||||||
connect,
|
connect,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,21 +24,21 @@ function tutorialVbox(player, store, tutorial) {
|
|||||||
if (vbox.bits < 29) {
|
if (vbox.bits < 29) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = vbox.free[0].slice(0, 2);
|
vbox.store[0] = vbox.store[0].slice(0, 2);
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = [];
|
vbox.store[2] = [];
|
||||||
vbox.bound.fill(null, 0, 3);
|
vbox.stash.fill(null, 0, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage === 2) {
|
if (stage === 2) {
|
||||||
if (!(vbox.bound.slice(0, 3).every(i => i === 'Attack') && vbox.bound.length >= 3)) {
|
if (!(vbox.stash.slice(0, 3).every(i => i === 'Attack') && vbox.stash.length >= 3)) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = vbox.free[0].slice(0, 2);
|
vbox.store[0] = vbox.store[0].slice(0, 2);
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = [];
|
vbox.store[2] = [];
|
||||||
vbox.bound.fill(null, 1, 3);
|
vbox.stash.fill(null, 1, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,21 +46,21 @@ function tutorialVbox(player, store, tutorial) {
|
|||||||
if (player.constructs[0].skills.length !== 0) {
|
if (player.constructs[0].skills.length !== 0) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = vbox.free[0].slice(0, 2);
|
vbox.store[0] = vbox.store[0].slice(0, 2);
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = [];
|
vbox.store[2] = [];
|
||||||
vbox.bound.fill(null, 0, 2);
|
vbox.stash.fill(null, 0, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage === 4) {
|
if (stage === 4) {
|
||||||
if (!vbox.free[2][0] || vbox.bits < 24) {
|
if (!vbox.store[2][0] || vbox.bits < 24) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = [];
|
vbox.store[0] = [];
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = vbox.free[2].slice(0, 1);
|
vbox.store[2] = vbox.store[2].slice(0, 1);
|
||||||
vbox.bound.fill(null, 0, 2);
|
vbox.stash.fill(null, 0, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,10 +68,10 @@ function tutorialVbox(player, store, tutorial) {
|
|||||||
if (player.constructs[0].specs.length !== 0) {
|
if (player.constructs[0].specs.length !== 0) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = [];
|
vbox.store[0] = [];
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = vbox.free[2].slice(0, 1);
|
vbox.store[2] = vbox.store[2].slice(0, 1);
|
||||||
vbox.bound.fill(null, 0, 2);
|
vbox.stash.fill(null, 0, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +79,9 @@ function tutorialVbox(player, store, tutorial) {
|
|||||||
if (player.constructs.every(c => c.skills.length !== 0)) {
|
if (player.constructs.every(c => c.skills.length !== 0)) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = [];
|
vbox.store[0] = [];
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = [];
|
vbox.store[2] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,9 +89,9 @@ function tutorialVbox(player, store, tutorial) {
|
|||||||
if (vbox.bits < 25) {
|
if (vbox.bits < 25) {
|
||||||
stage += 1;
|
stage += 1;
|
||||||
} else {
|
} else {
|
||||||
vbox.free[0] = [];
|
vbox.store[0] = [];
|
||||||
vbox.free[1] = [];
|
vbox.store[1] = [];
|
||||||
vbox.free[2] = [];
|
vbox.store[2] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store.dispatch(actions.setTutorial(stage));
|
store.dispatch(actions.setTutorial(stage));
|
||||||
@ -204,7 +204,7 @@ function tutorialStage(tutorial, clearTutorial, instance) {
|
|||||||
<p>Press <b>READY</b> to progress to the <b>GAME PHASE</b> <br />
|
<p>Press <b>READY</b> to progress to the <b>GAME PHASE</b> <br />
|
||||||
or continue creating new items to strengthen your constructs further</p>
|
or continue creating new items to strengthen your constructs further</p>
|
||||||
<p>You can unequip skills and specs back into the inventory by double clicking. <br />
|
<p>You can unequip skills and specs back into the inventory by double clicking. <br />
|
||||||
Reclaim can be used to refund the cost of items in your inventory. </p>
|
Refund can be used to refund the cost of items in your inventory. </p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -197,7 +197,7 @@ function postData(url = '/', data = {}) {
|
|||||||
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
|
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
|
||||||
credentials: 'include', // include, same-origin, *omit
|
credentials: 'include', // include, same-origin, *omit
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Buy: 'application/json',
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
},
|
},
|
||||||
redirect: 'error', // manual, *follow, error
|
redirect: 'error', // manual, *follow, error
|
||||||
|
|||||||
@ -15,7 +15,7 @@ use chrono::prelude::*;
|
|||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
|
|
||||||
use account::Account;
|
use account::Account;
|
||||||
use account;
|
use vbox;
|
||||||
|
|
||||||
use player::{Player, Score, player_create};
|
use player::{Player, Score, player_create};
|
||||||
|
|
||||||
@ -466,38 +466,38 @@ impl Instance {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_discard(mut self, account: Uuid) -> Result<Instance, Error> {
|
pub fn vbox_refill(mut self, account: Uuid) -> Result<Instance, Error> {
|
||||||
self.vbox_action_allowed(account)?;
|
self.vbox_action_allowed(account)?;
|
||||||
self.account_player(account)?
|
self.account_player(account)?
|
||||||
.vbox_discard()?;
|
.vbox_refill()?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_accept(mut self, account: Uuid, group: usize, index: usize, construct_id: Option<Uuid>) -> Result<Instance, Error> {
|
pub fn vbox_buy(mut self, account: Uuid, group: vbox::ItemType, index: String, construct_id: Option<Uuid>) -> Result<Instance, Error> {
|
||||||
self.vbox_action_allowed(account)?;
|
self.vbox_action_allowed(account)?;
|
||||||
self.account_player(account)?
|
self.account_player(account)?
|
||||||
.vbox_accept(group, index, construct_id)?;
|
.vbox_buy(group, index, construct_id)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_combine(mut self, account: Uuid, inv_indices: Vec<usize>, vbox_indices: Vec<Vec<usize>>) -> Result<Instance, Error> {
|
pub fn vbox_combine(mut self, account: Uuid, inv_indices: Vec<String>, vbox_indices: vbox::VboxIndices) -> Result<Instance, Error> {
|
||||||
self.vbox_action_allowed(account)?;
|
self.vbox_action_allowed(account)?;
|
||||||
self.account_player(account)?
|
self.account_player(account)?
|
||||||
.vbox_combine(inv_indices, vbox_indices)?;
|
.vbox_combine(inv_indices, vbox_indices)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_reclaim(mut self, account: Uuid, index: usize) -> Result<Instance, Error> {
|
pub fn vbox_refund(mut self, account: Uuid, index: String) -> Result<Instance, Error> {
|
||||||
self.vbox_action_allowed(account)?;
|
self.vbox_action_allowed(account)?;
|
||||||
self.account_player(account)?
|
self.account_player(account)?
|
||||||
.vbox_reclaim(index)?;
|
.vbox_refund(index)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_apply(mut self, account: Uuid, index: usize, construct_id: Uuid) -> Result<Instance, Error> {
|
pub fn vbox_apply(mut self, account: Uuid, index: String, construct_id: Uuid) -> Result<Instance, Error> {
|
||||||
self.vbox_action_allowed(account)?;
|
self.vbox_action_allowed(account)?;
|
||||||
self.account_player(account)?
|
self.account_player(account)?
|
||||||
.vbox_apply(index, construct_id)?;
|
.vbox_equip(index, construct_id)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,19 +834,17 @@ mod tests {
|
|||||||
fn instance_pve_test() {
|
fn instance_pve_test() {
|
||||||
let mut instance = Instance::new();
|
let mut instance = Instance::new();
|
||||||
|
|
||||||
let bot_player = bot_player();
|
let bot = bot_player();
|
||||||
let bot = bot_player.id;
|
let bot_one = bot.id;
|
||||||
instance.add_player(bot_player).unwrap();
|
instance.add_player(bot).unwrap();
|
||||||
|
|
||||||
let player_account = Uuid::new_v4();
|
let bot = bot_player();
|
||||||
let constructs = instance_mobs(player_account);
|
let bot_two = bot.id;
|
||||||
let player = Player::new(player_account, &"test".to_string(), constructs).set_bot(true);
|
instance.add_player(bot).unwrap();
|
||||||
|
|
||||||
instance.add_player(player).expect("could not add player");
|
|
||||||
|
|
||||||
assert_eq!(instance.phase, InstancePhase::Lobby);
|
assert_eq!(instance.phase, InstancePhase::Lobby);
|
||||||
instance.player_ready(player_account).unwrap();
|
instance.player_ready(bot_one).unwrap();
|
||||||
instance.player_ready(bot).unwrap();
|
instance.player_ready(bot_two).unwrap();
|
||||||
|
|
||||||
assert_eq!(instance.phase, InstancePhase::Finished);
|
assert_eq!(instance.phase, InstancePhase::Finished);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::{HashMap};
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|
||||||
@ -9,7 +11,7 @@ use failure::err_msg;
|
|||||||
use account;
|
use account;
|
||||||
use account::Account;
|
use account::Account;
|
||||||
use construct::{Construct, Colours};
|
use construct::{Construct, Colours};
|
||||||
use vbox::{Vbox};
|
use vbox::{Vbox, ItemType, VboxIndices};
|
||||||
use item::{Item, ItemEffect};
|
use item::{Item, ItemEffect};
|
||||||
use effect::{Effect};
|
use effect::{Effect};
|
||||||
|
|
||||||
@ -155,125 +157,162 @@ impl Player {
|
|||||||
pub fn autobuy(&mut self) -> &mut Player {
|
pub fn autobuy(&mut self) -> &mut Player {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
// first check if any constructs have no skills
|
// skill buying phase
|
||||||
// if there is one find an item in vbox that gives a skill
|
while self.constructs.iter().any(|c| c.skills.len() < 3) {
|
||||||
while let Some(c) = self.constructs.iter().position(|c| c.skills.len() == 0) {
|
// find the construct with the smallest number of skills
|
||||||
if let Some(s) = self.vbox.bound.iter().position(|v| v.into_skill().is_some()) {
|
let construct_id = match self.constructs.iter().min_by_key(|c| c.skills.len()) {
|
||||||
let construct_id = self.constructs[c].id;
|
None => panic!("no constructs in autobuy"),
|
||||||
self.vbox_apply(s, construct_id).expect("could not apply");
|
Some(c) => c.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let i = self.vbox.stash.iter()
|
||||||
|
.find(|(_i, v)| v.into_skill().is_some())
|
||||||
|
.map(|(i, _v)| i.clone());
|
||||||
|
|
||||||
|
// got a skill in stash
|
||||||
|
if let Some(i) = i {
|
||||||
|
// AAAAAAAAAAAAAAAAAAAA
|
||||||
|
// there's a bad bug here where if this apply fails
|
||||||
|
// the item in question will be silently dropped
|
||||||
|
let item = self.vbox.stash.remove(&i).unwrap();
|
||||||
|
self.vbox_apply(item, construct_id).ok();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
info!("no skills available...");
|
// need to buy one
|
||||||
}
|
else {
|
||||||
|
|
||||||
// now keep buying and applying items cause whynot
|
// do we have any colours in store?
|
||||||
// inb4 montecarlo gan
|
let colours = self.vbox.store[&ItemType::Colours].keys()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
loop {
|
// how about a base skill?
|
||||||
let (target_construct_i, target_construct_id) = match self.constructs.iter().any(|c| c.skills.len() < 3) {
|
let base = match self.vbox.store[&ItemType::Skills].iter().next() {
|
||||||
true => {
|
Some(b) => Some(b.0.clone()),
|
||||||
let mut target_construct_i = 0;
|
None => None,
|
||||||
for (j, c) in self.constructs.iter().enumerate() {
|
};
|
||||||
if c.skills.len() < self.constructs[target_construct_i].skills.len() {
|
|
||||||
target_construct_i = j;
|
// if no: try to refill and start again
|
||||||
}
|
match colours.len() < 2 || base.is_none() {
|
||||||
}
|
true => match self.vbox_refill() {
|
||||||
(target_construct_i, self.constructs[target_construct_i].id)
|
Ok(_) => continue,
|
||||||
|
Err(_) => break, // give up
|
||||||
},
|
},
|
||||||
false => {
|
false => {
|
||||||
let i = rng.gen_range(0, 3);
|
let mut vbox_items = HashMap::new();
|
||||||
(i, self.constructs[i].id)
|
vbox_items.insert(ItemType::Colours, colours);
|
||||||
|
vbox_items.insert(ItemType::Skills, vec![base.unwrap()]);
|
||||||
|
|
||||||
|
match self.vbox_combine(vec![], Some(vbox_items)) {
|
||||||
|
Ok(_) => continue,
|
||||||
|
Err(_) => break, // give up
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// spec buying phase
|
||||||
|
while self.constructs.iter().any(|c| c.specs.len() < 3) {
|
||||||
|
// find the construct with the smallest number of skills
|
||||||
|
let construct_id = match self.constructs.iter().min_by_key(|c| c.specs.len()) {
|
||||||
|
None => panic!("no constructs in autobuy"),
|
||||||
|
Some(c) => c.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let i = self.vbox.stash.iter()
|
||||||
|
.find(|(_i, v)| v.into_spec().is_some())
|
||||||
|
.map(|(i, _v)| i.clone());
|
||||||
|
|
||||||
|
// got a skill in stash
|
||||||
|
if let Some(i) = i {
|
||||||
|
// AAAAAAAAAAAAAAAAAAAA
|
||||||
|
// there's a bad bug here where if this apply fails
|
||||||
|
// the item in question will be silently dropped
|
||||||
|
let item = self.vbox.stash.remove(&i).unwrap();
|
||||||
|
self.vbox_apply(item, construct_id).ok();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// need to buy one
|
||||||
|
else {
|
||||||
|
// do we have any colours in store?
|
||||||
|
let colours = self.vbox.store[&ItemType::Colours].keys()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
// how about a base spec?
|
||||||
|
let base = match self.vbox.store[&ItemType::Specs].iter().next() {
|
||||||
|
Some(b) => Some(b.0.clone()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// if no: try to refill and start again
|
||||||
|
match colours.len() < 2 || base.is_none() {
|
||||||
|
true => match self.vbox_refill() {
|
||||||
|
Ok(_) => continue,
|
||||||
|
Err(_) => break, // give up
|
||||||
},
|
},
|
||||||
};
|
false => {
|
||||||
|
let mut vbox_items = HashMap::new();
|
||||||
|
vbox_items.insert(ItemType::Colours, colours);
|
||||||
|
vbox_items.insert(ItemType::Specs, vec![base.unwrap()]);
|
||||||
|
|
||||||
let needs_skills = self.constructs[target_construct_i].skills.len() < 3;
|
match self.vbox_combine(vec![], Some(vbox_items)) {
|
||||||
let group_i = match needs_skills {
|
Ok(_) => continue,
|
||||||
true => 1,
|
Err(_) => break, // give up
|
||||||
false => 2,
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let num_colours = self.vbox.bound
|
|
||||||
.iter()
|
|
||||||
.filter(|v| [Item::Red, Item::Green, Item::Blue].contains(v))
|
|
||||||
.count();
|
|
||||||
|
|
||||||
if self.vbox.bound.len() < 3 || num_colours < 2 {
|
|
||||||
if (needs_skills && self.vbox.bits < 4) || self.vbox.bits < 5 {
|
|
||||||
// info!("insufficient balance");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get 2 colours and something else
|
// upgrading phase
|
||||||
let free_colours = self.vbox.free[0].iter().fold(0, |count, item| {
|
// NYI
|
||||||
match item.is_some() {
|
|
||||||
true => count + 1,
|
|
||||||
false => count
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if free_colours < 2 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
self.bot_vbox_accept(0).expect("could't accept colour item");
|
|
||||||
self.bot_vbox_accept(0).expect("could't accept colour item");
|
|
||||||
self.bot_vbox_accept(group_i).expect("could't accept group item");
|
|
||||||
}
|
|
||||||
|
|
||||||
// info!("{:?}", self.vbox.bound);
|
|
||||||
|
|
||||||
let skills = [Item::Attack, Item::Block, Item::Buff, Item::Debuff, Item::Stun];
|
|
||||||
let combo_i = match group_i {
|
|
||||||
1 => self.vbox.bound.iter().position(|v| skills.contains(v)).expect("no skill found"),
|
|
||||||
2 => self.vbox.bound.iter().position(|v| v.into_spec().is_some()).expect("no spec found"),
|
|
||||||
_ => panic!("unknown group_i"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// first 2 colours can be whatever
|
|
||||||
self.vbox_combine(vec![0, 1, combo_i], vec![]).ok();
|
|
||||||
let item_i = self.vbox.bound.len() - 1;
|
|
||||||
self.vbox_apply(item_i, target_construct_id).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_discard(&mut self) -> Result<&mut Player, Error> {
|
pub fn vbox_refill(&mut self) -> Result<&mut Player, Error> {
|
||||||
self.vbox.balance_sub(DISCARD_COST)?;
|
self.vbox.balance_sub(DISCARD_COST)?;
|
||||||
self.vbox.fill();
|
self.vbox.fill();
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bot_vbox_accept(&mut self, group: usize) -> Result<&mut Player, Error> {
|
pub fn bot_vbox_accept(&mut self, group: ItemType) -> Result<&mut Player, Error> {
|
||||||
self.vbox.bot_accept(group)?;
|
let item = self.vbox.bot_buy(group)?;
|
||||||
|
self.vbox.stash_add(item, None)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_accept(&mut self, group: usize, index: usize, construct_id: Option<Uuid>) -> Result<&mut Player, Error> {
|
pub fn vbox_buy(&mut self, group: ItemType, index: String, construct_id: Option<Uuid>) -> Result<&mut Player, Error> {
|
||||||
self.vbox.accept(group, index, construct_id)?;
|
let item = self.vbox.buy(group, &index)?;
|
||||||
if construct_id.is_some() {
|
|
||||||
let equip_index = self.vbox.bound.len() - 1;
|
match construct_id {
|
||||||
self.vbox_apply(equip_index, construct_id.expect("no construct"))?;
|
Some(id) => { self.vbox_apply(item, id)?; },
|
||||||
}
|
None => { self.vbox.stash_add(item, None)?; },
|
||||||
|
};
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_combine(&mut self, inv_indices: Vec<usize>, vbox_indices: Vec<Vec<usize>>) -> Result<&mut Player, Error> {
|
pub fn vbox_combine(&mut self, inv_indices: Vec<String>, vbox_indices: VboxIndices) -> Result<&mut Player, Error> {
|
||||||
self.vbox.combine(inv_indices, vbox_indices)?;
|
self.vbox.combine(inv_indices, vbox_indices)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_reclaim(&mut self, index: usize) -> Result<&mut Player, Error> {
|
pub fn vbox_refund(&mut self, index: String) -> Result<&mut Player, Error> {
|
||||||
self.vbox.reclaim(index)?;
|
self.vbox.refund(index)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_apply(&mut self, index: usize, construct_id: Uuid) -> Result<&mut Player, Error> {
|
pub fn vbox_equip(&mut self, index: String, construct_id: Uuid) -> Result<&mut Player, Error> {
|
||||||
if self.vbox.bound.get(index).is_none() {
|
let item = self.vbox.stash.remove(&index)
|
||||||
return Err(format_err!("no item at index {:?}", index));
|
.ok_or(format_err!("no item at index {:?} {:}", self, &index))?;
|
||||||
|
|
||||||
|
self.vbox_apply(item, construct_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
let item = self.vbox.bound.remove(index);
|
pub fn vbox_apply(&mut self, item: Item, construct_id: Uuid) -> Result<&mut Player, Error> {
|
||||||
|
|
||||||
match item.effect() {
|
match item.effect() {
|
||||||
Some(ItemEffect::Skill) => {
|
Some(ItemEffect::Skill) => {
|
||||||
let skill = item.into_skill().ok_or(format_err!("item {:?} has no associated skill", item))?;
|
let skill = item.into_skill().ok_or(format_err!("item {:?} has no associated skill", item))?;
|
||||||
@ -317,8 +356,8 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_unequip(&mut self, target: Item, construct_id: Uuid, target_construct_id: Option<Uuid>) -> Result<&mut Player, Error> {
|
pub fn vbox_unequip(&mut self, target: Item, construct_id: Uuid, target_construct_id: Option<Uuid>) -> Result<&mut Player, Error> {
|
||||||
if self.vbox.bound.len() >= 9 && !target_construct_id.is_some() {
|
if self.vbox.stash.len() >= 9 && !target_construct_id.is_some() {
|
||||||
return Err(err_msg("too many items bound"));
|
return Err(err_msg("too many items stash"));
|
||||||
}
|
}
|
||||||
|
|
||||||
match target.effect() {
|
match target.effect() {
|
||||||
@ -349,13 +388,10 @@ impl Player {
|
|||||||
construct.apply_modifiers(&player_colours);
|
construct.apply_modifiers(&player_colours);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.vbox.bound.push(target);
|
match target_construct_id {
|
||||||
|
Some(cid) => { self.vbox_apply(target, cid)?; },
|
||||||
if target_construct_id.is_some() {
|
None => { self.vbox.stash_add(target, None)?; },
|
||||||
let equip_index = self.vbox.bound.len() - 1;
|
};
|
||||||
self.vbox_apply(equip_index, target_construct_id.expect("no construct"))?;
|
|
||||||
}
|
|
||||||
// self.vbox.bound.sort_unstable();
|
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
@ -408,8 +444,8 @@ mod tests {
|
|||||||
let player_account = Uuid::new_v4();
|
let player_account = Uuid::new_v4();
|
||||||
let constructs = instance_mobs(player_account);
|
let constructs = instance_mobs(player_account);
|
||||||
let mut player = Player::new(player_account, &"test".to_string(), constructs).set_bot(true);
|
let mut player = Player::new(player_account, &"test".to_string(), constructs).set_bot(true);
|
||||||
player.vbox.fill();
|
|
||||||
|
|
||||||
|
player.vbox.fill();
|
||||||
player.autobuy();
|
player.autobuy();
|
||||||
|
|
||||||
assert!(player.constructs.iter().all(|c| c.skills.len() >= 1));
|
assert!(player.constructs.iter().all(|c| c.skills.len() >= 1));
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::time::{Instant};
|
use std::time::{Instant};
|
||||||
use std::thread::{spawn};
|
use std::thread::{spawn};
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ use mail::Email;
|
|||||||
use pg::{Db};
|
use pg::{Db};
|
||||||
use pg::{PgPool};
|
use pg::{PgPool};
|
||||||
use skill::{Skill, dev_resolve, Resolutions};
|
use skill::{Skill, dev_resolve, Resolutions};
|
||||||
use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip};
|
use vbox::{ItemType, vbox_buy, vbox_apply, vbox_refill, vbox_combine, vbox_refund, vbox_unequip};
|
||||||
use http::{AUTH_CLEAR, TOKEN_HEADER};
|
use http::{AUTH_CLEAR, TOKEN_HEADER};
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize)]
|
#[derive(Debug,Clone,Serialize)]
|
||||||
@ -114,14 +115,13 @@ pub enum RpcRequest {
|
|||||||
InstanceState { instance_id: Uuid },
|
InstanceState { instance_id: Uuid },
|
||||||
InstanceChat { instance_id: Uuid, index: usize },
|
InstanceChat { instance_id: Uuid, index: usize },
|
||||||
|
|
||||||
VboxAccept { instance_id: Uuid, group: usize, index: usize },
|
VboxBuy { instance_id: Uuid, group: ItemType, index: String, construct_id: Option<Uuid> },
|
||||||
VboxAcceptEquip { instance_id: Uuid, group: usize, index: usize, construct_id: Uuid },
|
VboxRefill { instance_id: Uuid },
|
||||||
VboxDiscard { instance_id: Uuid },
|
VboxCombine { instance_id: Uuid, inv_indices: Vec<String>, vbox_indices: Option<HashMap<ItemType, Vec<String>>> },
|
||||||
VboxCombine { instance_id: Uuid, inv_indices: Vec<usize>, vbox_indices: Vec<Vec<usize>> },
|
VboxApply { instance_id: Uuid, construct_id: Uuid, index: String },
|
||||||
VboxApply { instance_id: Uuid, construct_id: Uuid, index: usize },
|
|
||||||
VboxUnequip { instance_id: Uuid, construct_id: Uuid, target: Item },
|
VboxUnequip { instance_id: Uuid, construct_id: Uuid, target: Item },
|
||||||
VboxUnequipApply { instance_id: Uuid, construct_id: Uuid, target: Item, target_construct_id: Uuid },
|
VboxUnequipApply { instance_id: Uuid, construct_id: Uuid, target: Item, target_construct_id: Uuid },
|
||||||
VboxReclaim { instance_id: Uuid, index: usize },
|
VboxRefund { instance_id: Uuid, index: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Connection {
|
struct Connection {
|
||||||
@ -245,11 +245,8 @@ impl Connection {
|
|||||||
RpcRequest::InstanceAbandon { instance_id } =>
|
RpcRequest::InstanceAbandon { instance_id } =>
|
||||||
Ok(instance_abandon(&mut tx, account, instance_id)?),
|
Ok(instance_abandon(&mut tx, account, instance_id)?),
|
||||||
|
|
||||||
RpcRequest::VboxAccept { instance_id, group, index } =>
|
RpcRequest::VboxBuy { instance_id, group, index, construct_id } =>
|
||||||
Ok(RpcMessage::InstanceState(vbox_accept(&mut tx, account, instance_id, group, index, None)?)),
|
Ok(RpcMessage::InstanceState(vbox_buy(&mut tx, account, instance_id, group, index, construct_id)?)),
|
||||||
|
|
||||||
RpcRequest::VboxAcceptEquip { instance_id, group, index, construct_id } =>
|
|
||||||
Ok(RpcMessage::InstanceState(vbox_accept(&mut tx, account, instance_id, group, index, Some(construct_id))?)),
|
|
||||||
|
|
||||||
RpcRequest::VboxApply { instance_id, construct_id, index } =>
|
RpcRequest::VboxApply { instance_id, construct_id, index } =>
|
||||||
Ok(RpcMessage::InstanceState(vbox_apply(&mut tx, account, instance_id, construct_id, index)?)),
|
Ok(RpcMessage::InstanceState(vbox_apply(&mut tx, account, instance_id, construct_id, index)?)),
|
||||||
@ -257,11 +254,11 @@ impl Connection {
|
|||||||
RpcRequest::VboxCombine { instance_id, inv_indices, vbox_indices } =>
|
RpcRequest::VboxCombine { instance_id, inv_indices, vbox_indices } =>
|
||||||
Ok(RpcMessage::InstanceState(vbox_combine(&mut tx, account, instance_id, inv_indices, vbox_indices)?)),
|
Ok(RpcMessage::InstanceState(vbox_combine(&mut tx, account, instance_id, inv_indices, vbox_indices)?)),
|
||||||
|
|
||||||
RpcRequest::VboxDiscard { instance_id } =>
|
RpcRequest::VboxRefill { instance_id } =>
|
||||||
Ok(RpcMessage::InstanceState(vbox_discard(&mut tx, account, instance_id)?)),
|
Ok(RpcMessage::InstanceState(vbox_refill(&mut tx, account, instance_id)?)),
|
||||||
|
|
||||||
RpcRequest::VboxReclaim { instance_id, index } =>
|
RpcRequest::VboxRefund { instance_id, index } =>
|
||||||
Ok(RpcMessage::InstanceState(vbox_reclaim(&mut tx, account, instance_id, index)?)),
|
Ok(RpcMessage::InstanceState(vbox_refund(&mut tx, account, instance_id, index)?)),
|
||||||
|
|
||||||
RpcRequest::VboxUnequip { instance_id, construct_id, target } =>
|
RpcRequest::VboxUnequip { instance_id, construct_id, target } =>
|
||||||
Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, account, instance_id, construct_id, target, None)?)),
|
Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, account, instance_id, construct_id, target, None)?)),
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
// reclaims
|
// refunds
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand::{thread_rng};
|
use rand::{thread_rng};
|
||||||
use rand::distributions::{WeightedIndex};
|
use rand::distributions::{WeightedIndex};
|
||||||
@ -19,30 +20,48 @@ use construct::{Colours};
|
|||||||
|
|
||||||
use item::*;
|
use item::*;
|
||||||
|
|
||||||
|
pub type VboxIndices = Option<HashMap<ItemType, Vec<String>>>;
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct Vbox {
|
pub struct Vbox {
|
||||||
pub bits: usize,
|
pub bits: usize,
|
||||||
pub free: Vec<Vec<Option<Item>>>,
|
pub store: HashMap<ItemType, HashMap<String, Item>>,
|
||||||
pub bound: Vec<Item>,
|
pub stash: HashMap<String, Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,Copy,Clone,Serialize,Deserialize,Hash,PartialEq,Eq)]
|
||||||
pub enum ItemType {
|
pub enum ItemType {
|
||||||
Colours,
|
Colours,
|
||||||
Skills,
|
Skills,
|
||||||
Specs,
|
Specs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const STORE_COLOURS_CAPACITY: usize = 6;
|
||||||
|
const STORE_SKILLS_CAPACITY: usize = 3;
|
||||||
|
const STORE_SPECS_CAPACITY: usize = 3;
|
||||||
|
const STASH_CAPACITY: usize = 6;
|
||||||
|
const STARTING_ATTACK_COUNT: usize = 3;
|
||||||
|
|
||||||
impl Vbox {
|
impl Vbox {
|
||||||
pub fn new() -> Vbox {
|
pub fn new() -> Vbox {
|
||||||
let starting_items = vec![
|
let mut colours: HashMap<String, Item> = HashMap::new();
|
||||||
Item::Attack,
|
let mut skills: HashMap<String, Item> = HashMap::new();
|
||||||
Item::Attack,
|
let mut specs: HashMap<String, Item> = HashMap::new();
|
||||||
Item::Attack,
|
|
||||||
];
|
let store = [
|
||||||
|
(ItemType::Colours, colours),
|
||||||
|
(ItemType::Skills, skills),
|
||||||
|
(ItemType::Colours, specs),
|
||||||
|
].iter().cloned().collect();
|
||||||
|
|
||||||
|
let mut stash = HashMap::new();
|
||||||
|
for i in 0..STARTING_ATTACK_COUNT {
|
||||||
|
stash.insert(i.to_string(), Item::Attack);
|
||||||
|
}
|
||||||
|
|
||||||
Vbox {
|
Vbox {
|
||||||
free: vec![vec![], vec![], vec![]],
|
store,
|
||||||
bound: starting_items,
|
stash,
|
||||||
bits: 30,
|
bits: 30,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,103 +84,130 @@ impl Vbox {
|
|||||||
pub fn fill(&mut self) -> &mut Vbox {
|
pub fn fill(&mut self) -> &mut Vbox {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
self.free = [ItemType::Colours, ItemType::Skills, ItemType::Specs].iter()
|
let colours = vec![
|
||||||
.map(|item_type| {
|
(Item::Red, 1),
|
||||||
let items = match item_type {
|
(Item::Green, 1),
|
||||||
ItemType::Colours => vec![
|
(Item::Blue, 1),
|
||||||
(Some(Item::Red), 1),
|
];
|
||||||
(Some(Item::Green), 1),
|
let colour_dist = WeightedIndex::new(colours.iter().map(|item| item.1)).unwrap();
|
||||||
(Some(Item::Blue), 1),
|
|
||||||
],
|
let skills = vec![
|
||||||
ItemType::Skills => vec![
|
(Item::Attack, 1),
|
||||||
(Some(Item::Attack), 1),
|
(Item::Block, 1),
|
||||||
(Some(Item::Block), 1),
|
(Item::Buff, 1),
|
||||||
(Some(Item::Buff), 1),
|
(Item::Debuff, 1),
|
||||||
(Some(Item::Debuff), 1),
|
(Item::Stun, 1),
|
||||||
(Some(Item::Stun), 1),
|
];
|
||||||
],
|
let skill_dist = WeightedIndex::new(skills.iter().map(|item| item.1)).unwrap();
|
||||||
ItemType::Specs => vec![
|
|
||||||
(Some(Item::Power), 1),
|
let specs = vec![
|
||||||
(Some(Item::Life), 1),
|
(Item::Power, 1),
|
||||||
(Some(Item::Speed), 1),
|
(Item::Life, 1),
|
||||||
],
|
(Item::Speed, 1),
|
||||||
|
];
|
||||||
|
let spec_dist = WeightedIndex::new(specs.iter().map(|item| item.1)).unwrap();
|
||||||
|
|
||||||
|
for item_type in [ItemType::Colours, ItemType::Skills, ItemType::Specs].iter() {
|
||||||
|
let (items, num, dist) = match item_type {
|
||||||
|
ItemType::Colours => (&colours, STORE_COLOURS_CAPACITY, &colour_dist),
|
||||||
|
ItemType::Skills => (&skills, STORE_SKILLS_CAPACITY, &skill_dist),
|
||||||
|
ItemType::Specs => (&specs, STORE_SPECS_CAPACITY, &spec_dist),
|
||||||
};
|
};
|
||||||
|
|
||||||
let dist = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
|
let drops = iter::repeat_with(|| items[dist.sample(&mut rng)].0)
|
||||||
iter::repeat_with(|| {
|
.take(num)
|
||||||
items[dist.sample(&mut rng)].0}).take(match item_type {
|
.enumerate()
|
||||||
ItemType::Colours => 6,
|
.map(|(i, item)| (i.to_string(), item))
|
||||||
_ => 3,
|
.collect::<HashMap<String, Item>>();
|
||||||
}).collect::<Vec<Option<Item>>>()
|
|
||||||
})
|
self.store.insert(*item_type, drops);
|
||||||
.collect::<Vec<Vec<Option<Item>>>>();
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(&mut self, i: usize, j: usize, construct_id: Option<Uuid>) -> Result<&mut Vbox, Error> {
|
pub fn buy(&mut self, item: ItemType, i: &String) -> Result<Item, Error> {
|
||||||
if self.bound.len() >= 6 && !construct_id.is_some() {
|
|
||||||
return Err(err_msg("too many items bound"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check item exists
|
// check item exists
|
||||||
self.free
|
let selection = self.store
|
||||||
.get(i).ok_or(format_err!("no item group at index {:?}", i))?
|
.get_mut(&item).ok_or(format_err!("no item group {:?}", item))?
|
||||||
.get(j).ok_or(format_err!("no item at index {:?}", j))?;
|
.remove(i).ok_or(format_err!("no item at index {:?} {:}", self, i))?;
|
||||||
|
|
||||||
// check can purchase
|
self.balance_sub(selection.cost())?;
|
||||||
let cost = match self.free[i][j] {
|
|
||||||
None => 0,
|
|
||||||
_ => self.free[i][j].unwrap().cost()
|
|
||||||
};
|
|
||||||
self.balance_sub(cost)?;
|
|
||||||
|
|
||||||
// actually move
|
Ok(selection)
|
||||||
match self.free[i][j] {
|
|
||||||
None => (),
|
|
||||||
_ => self.bound.push(self.free[i][j].unwrap())
|
|
||||||
}
|
|
||||||
// self.bound.push(self.free[i][j].unwrap());
|
|
||||||
self.free[i][j] = None;
|
|
||||||
// self.bound.sort_unstable();
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bot_accept(&mut self, i: usize) -> Result<&mut Vbox, Error> {
|
pub fn stash_add(&mut self, item: Item, index: Option<&String>) -> Result<String, Error> {
|
||||||
let buy_index = self.free[i].iter().position(|item| item.is_some());
|
if self.stash.len() >= STASH_CAPACITY {
|
||||||
self.accept(i, buy_index.expect("no valid buys"), None)
|
return Err(err_msg("stash full"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reclaim(&mut self, i: usize) -> Result<&mut Vbox, Error> {
|
if let Some(index) = index {
|
||||||
self.bound.get(i).ok_or(format_err!("no item at index {:?}", i))?;
|
if self.stash.contains_key(index) {
|
||||||
let reclaimed = self.bound.remove(i);
|
return Err(format_err!("slot occupied {:?}", index));
|
||||||
let refund = reclaimed.cost();
|
}
|
||||||
// info!("reclaiming {:?} for {:?}", refund, reclaimed);
|
self.stash.insert(index.clone(), item);
|
||||||
|
return Ok(index.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in (0..STASH_CAPACITY).map(|i| i.to_string()) {
|
||||||
|
if !self.stash.contains_key(&i) {
|
||||||
|
self.stash.insert(i.clone(), item);
|
||||||
|
return Ok(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(err_msg("stash full"));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bot_buy(&mut self, item: ItemType) -> Result<Item, Error> {
|
||||||
|
let buy_index = self.store[&item]
|
||||||
|
.keys()
|
||||||
|
.next()
|
||||||
|
.ok_or(format_err!("no item in group {:?}", item))?
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
self.buy(item, &buy_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn refund(&mut self, i: String) -> Result<&mut Vbox, Error> {
|
||||||
|
let refunded = self.stash.remove(&i)
|
||||||
|
.ok_or(format_err!("no item at index {:?} {:?}", self.stash, i))?;
|
||||||
|
|
||||||
|
let refund = refunded.cost();
|
||||||
|
// info!("refunding {:?} for {:?}", refund, refunded);
|
||||||
self.balance_add(refund);
|
self.balance_add(refund);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn combine(&mut self, mut inv_indices: Vec<usize>, vbox_indicies: Vec<Vec<usize>>) -> Result<&mut Vbox, Error> {
|
pub fn combine(&mut self, stash_indices: Vec<String>, store_indices: Option<HashMap<ItemType, Vec<String>>>) -> Result<&mut Vbox, Error> {
|
||||||
if !inv_indices.iter().all(|i| self.bound.get(*i).is_some()) {
|
// find base item for index to insert into
|
||||||
return Err(err_msg("item missing index"));
|
let base_index = stash_indices.iter()
|
||||||
}
|
.find(|i| match self.stash.get(i.clone()) {
|
||||||
// try to buy up the vbox indicies and add them to the inventory indicies for combining
|
Some(item) => item.into_skill().is_some(),
|
||||||
for vi in vbox_indicies.iter() {
|
None => false,
|
||||||
inv_indices.push(self.bound.len());
|
});
|
||||||
self.accept(vi[0], vi[1], Some(Uuid::nil()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// have to sort the indices and keep track of the iteration
|
let mut input = stash_indices
|
||||||
// because when removing the elements the array shifts
|
|
||||||
inv_indices.sort_unstable();
|
|
||||||
let mut input = inv_indices
|
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.map(|i| self.stash.remove(i)
|
||||||
.map(|(i, index)| {
|
.ok_or(format_err!("no item at index {:?} {:?}", self.stash, i)))
|
||||||
self.bound.remove(index.saturating_sub(i))
|
.collect::<Result<Vec<Item>, Error>>()?;
|
||||||
})
|
|
||||||
.collect::<Vec<Item>>();
|
if let Some(store_indices) = store_indices {
|
||||||
|
let mut purchased = store_indices.iter()
|
||||||
|
.map(|(g, list)|
|
||||||
|
list.iter()
|
||||||
|
.map(|i| self.buy(*g, i))
|
||||||
|
.collect::<Result<Vec<Item>, Error>>()
|
||||||
|
)
|
||||||
|
.collect::<Result<Vec<Vec<Item>>, Error>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
input.append(&mut purchased);
|
||||||
|
}
|
||||||
|
|
||||||
// sort the input to align with the combinations
|
// sort the input to align with the combinations
|
||||||
// combos are sorted when created
|
// combos are sorted when created
|
||||||
@ -169,40 +215,37 @@ impl Vbox {
|
|||||||
let combos = get_combos();
|
let combos = get_combos();
|
||||||
let combo = combos.iter().find(|c| c.components == input).ok_or(err_msg("not a combo"))?;
|
let combo = combos.iter().find(|c| c.components == input).ok_or(err_msg("not a combo"))?;
|
||||||
|
|
||||||
self.bound.push(combo.item);
|
self.stash_add(combo.item, base_index)?;
|
||||||
// self.bound.sort_unstable();
|
|
||||||
if self.bound.len() > 6 {
|
|
||||||
return Err(err_msg("too many items bound"));
|
|
||||||
}
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_discard(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result<Instance, Error> {
|
pub fn vbox_refill(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result<Instance, Error> {
|
||||||
let instance = instance_get(tx, instance_id)?
|
let instance = instance_get(tx, instance_id)?
|
||||||
.vbox_discard(account.id)?;
|
.vbox_refill(account.id)?;
|
||||||
return instance_update(tx, instance);
|
return instance_update(tx, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_accept(tx: &mut Transaction, account: &Account, instance_id: Uuid, group: usize, index: usize, construct_id: Option<Uuid>) -> Result<Instance, Error> {
|
pub fn vbox_buy(tx: &mut Transaction, account: &Account, instance_id: Uuid, group: ItemType, index: String, construct_id: Option<Uuid>) -> Result<Instance, Error> {
|
||||||
let instance = instance_get(tx, instance_id)?
|
let instance = instance_get(tx, instance_id)?
|
||||||
.vbox_accept(account.id, group, index, construct_id)?;
|
.vbox_buy(account.id, group, index, construct_id)?;
|
||||||
return instance_update(tx, instance);
|
return instance_update(tx, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_combine(tx: &mut Transaction, account: &Account, instance_id: Uuid, inv_indices: Vec<usize>, vbox_indices: Vec<Vec<usize>>) -> Result<Instance, Error> {
|
pub fn vbox_combine(tx: &mut Transaction, account: &Account, instance_id: Uuid, stash_indices: Vec<String>, vbox_indices: VboxIndices) -> Result<Instance, Error> {
|
||||||
let instance = instance_get(tx, instance_id)?
|
let instance = instance_get(tx, instance_id)?
|
||||||
.vbox_combine(account.id, inv_indices, vbox_indices)?;
|
.vbox_combine(account.id, stash_indices, vbox_indices)?;
|
||||||
return instance_update(tx, instance);
|
return instance_update(tx, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_reclaim(tx: &mut Transaction, account: &Account, instance_id: Uuid, index: usize) -> Result<Instance, Error> {
|
pub fn vbox_refund(tx: &mut Transaction, account: &Account, instance_id: Uuid, index: String) -> Result<Instance, Error> {
|
||||||
let instance = instance_get(tx, instance_id)?
|
let instance = instance_get(tx, instance_id)?
|
||||||
.vbox_reclaim(account.id, index)?;
|
.vbox_refund(account.id, index)?;
|
||||||
return instance_update(tx, instance);
|
return instance_update(tx, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vbox_apply(tx: &mut Transaction, account: &Account, instance_id: Uuid, construct_id: Uuid, index: usize) -> Result<Instance, Error> {
|
pub fn vbox_apply(tx: &mut Transaction, account: &Account, instance_id: Uuid, construct_id: Uuid, index: String) -> Result<Instance, Error> {
|
||||||
let instance = instance_get(tx, instance_id)?
|
let instance = instance_get(tx, instance_id)?
|
||||||
.vbox_apply(account.id, index, construct_id)?;
|
.vbox_apply(account.id, index, construct_id)?;
|
||||||
return instance_update(tx, instance);
|
return instance_update(tx, instance);
|
||||||
@ -221,9 +264,49 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn combine_test() {
|
fn combine_test() {
|
||||||
let mut vbox = Vbox::new();
|
let mut vbox = Vbox::new();
|
||||||
vbox.bound = vec![Item::Attack, Item::Green, Item::Green];
|
vbox.stash.insert(0.to_string(), Item::Attack);
|
||||||
vbox.combine(vec![1,2,0], vec![]).unwrap();
|
vbox.stash.insert(1.to_string(), Item::Green);
|
||||||
assert_eq!(vbox.bound[0], Item::Heal);
|
vbox.stash.insert(2.to_string(), Item::Green);
|
||||||
|
vbox.combine(vec![0.to_string(), 1.to_string(), 2.to_string()], None).unwrap();
|
||||||
|
assert_eq!(vbox.stash["0"], Item::Heal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn buy_test() {
|
||||||
|
let mut vbox = Vbox::new();
|
||||||
|
vbox.fill();
|
||||||
|
|
||||||
|
// cannot rebuy same
|
||||||
|
vbox.buy(ItemType::Skills, &0.to_string()).unwrap();
|
||||||
|
assert!(vbox.store[&ItemType::Skills].get(&0.to_string()).is_none());
|
||||||
|
assert!(vbox.buy(ItemType::Skills, &0.to_string()).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capacity_test() {
|
||||||
|
let mut vbox = Vbox::new();
|
||||||
|
vbox.fill();
|
||||||
|
vbox.stash_add(Item::Red, None).unwrap();
|
||||||
|
vbox.stash_add(Item::Red, None).unwrap();
|
||||||
|
vbox.stash_add(Item::Red, None).unwrap();
|
||||||
|
assert!(vbox.stash_add(Item::Red, None).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn store_and_stash_combine_test() {
|
||||||
|
let mut vbox = Vbox::new();
|
||||||
|
vbox.fill();
|
||||||
|
|
||||||
|
let mut skill_combine_args = HashMap::new();
|
||||||
|
skill_combine_args.insert(ItemType::Colours, vec![0.to_string(), 1.to_string()]);
|
||||||
|
skill_combine_args.insert(ItemType::Skills, vec![0.to_string()]);
|
||||||
|
|
||||||
|
let mut spec_combine_args = HashMap::new();
|
||||||
|
spec_combine_args.insert(ItemType::Colours, vec![2.to_string(), 3.to_string()]);
|
||||||
|
spec_combine_args.insert(ItemType::Specs, vec![0.to_string()]);
|
||||||
|
|
||||||
|
vbox.combine(vec![], Some(skill_combine_args)).unwrap();
|
||||||
|
vbox.combine(vec![], Some(spec_combine_args)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -239,10 +322,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reclaim_test() {
|
fn refund_test() {
|
||||||
let mut vbox = Vbox::new();
|
let mut vbox = Vbox::new();
|
||||||
vbox.bound = vec![Item::Strike];
|
vbox.stash.insert(0.to_string(), Item::Strike);
|
||||||
vbox.reclaim(0).unwrap();
|
vbox.refund(0.to_string()).unwrap();
|
||||||
assert_eq!(vbox.bits, 32);
|
assert_eq!(vbox.bits, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user