Merge branch 'release/1.6.0'
This commit is contained in:
commit
0b55484c14
34
CHANGELOG.md
34
CHANGELOG.md
@ -2,6 +2,40 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [1.6.0] - 2019-10-18
|
||||||
|
### Added
|
||||||
|
- Subscriber chat!
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Made available skill / effect information during the combat phase.
|
||||||
|
- Highlighting a skill replace the effect area with the skill description including speed multiplier.
|
||||||
|
- Highlighting an effect will replace the targetting arrow / anim skill text with effect info.
|
||||||
|
- You can now preview combinations before you create them
|
||||||
|
- After selecting the three items for a combo hover over the combine button for info
|
||||||
|
|
||||||
|
- Damage formula for Slay and Siphon reworked
|
||||||
|
- Slay now deals red damage based RedPower and GreenPower. Previously only based on RedPower.
|
||||||
|
- Siphon now deals blue damage based BluePower and GreenPower. Previously only based on BluePower.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Matchmaking bug where server matches you with yourself
|
||||||
|
|
||||||
|
## [1.5.6] - 2019-10-17
|
||||||
|
We've updated the UI during the vbox / buy phase to give a better indication of valid actions.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Borders for skill combo's represent the base colours.
|
||||||
|
- Heal (GG) has a green border, Siphon (BG) has an alternating blue / green border etc.
|
||||||
|
- Borders are shown for items in inventory and as equipped skills during both phases.
|
||||||
|
|
||||||
|
- Improvements to making item combo's
|
||||||
|
- If you select an item in your inventory it will now highlight other items that are valid for combining.
|
||||||
|
- This includes items that can be bought and in your inventory.
|
||||||
|
|
||||||
|
- Improved the indicator for where to click for equipping and buying items where its valid.
|
||||||
|
- Now slowly flashes between black and grey, previously changed the border once.
|
||||||
|
|
||||||
|
|
||||||
## [1.5.5] - 2019-10-15
|
## [1.5.5] - 2019-10-15
|
||||||
### Changed
|
### Changed
|
||||||
* Purge
|
* Purge
|
||||||
|
|||||||
10
WORKLOG.md
10
WORKLOG.md
@ -3,10 +3,7 @@
|
|||||||
|
|
||||||
*PRODUCTION*
|
*PRODUCTION*
|
||||||
|
|
||||||
* border colours for skills e.g. strike red border, slay half red half green
|
|
||||||
* rename vbox to shop
|
* rename vbox to shop
|
||||||
* combat phase info system
|
|
||||||
* drag and drop buy / equip / unequip items
|
|
||||||
|
|
||||||
* mobile styles
|
* mobile styles
|
||||||
* mobile info page
|
* mobile info page
|
||||||
@ -16,6 +13,11 @@
|
|||||||
* can't reset password without knowing password =\
|
* can't reset password without knowing password =\
|
||||||
* Invert recharge
|
* Invert recharge
|
||||||
|
|
||||||
|
* serde serialize privatise
|
||||||
|
* chat
|
||||||
|
|
||||||
|
* Convert spec 'Plus' -> '+' when it appears as combo text in combiner and in info text
|
||||||
|
|
||||||
## SOON
|
## SOON
|
||||||
|
|
||||||
* equip from shop (buy and equip without putting in your inventory) for bases
|
* equip from shop (buy and equip without putting in your inventory) for bases
|
||||||
@ -23,7 +25,6 @@
|
|||||||
* bot game grind
|
* bot game grind
|
||||||
* ACP
|
* ACP
|
||||||
* essential
|
* essential
|
||||||
* serde serialize privatise
|
|
||||||
* msg pane / chatwheel
|
* msg pane / chatwheel
|
||||||
* audio
|
* audio
|
||||||
* treats
|
* treats
|
||||||
@ -71,6 +72,7 @@ $$$
|
|||||||
* Highlight (dota) colour
|
* Highlight (dota) colour
|
||||||
* fx colours + styles
|
* fx colours + styles
|
||||||
|
|
||||||
|
* ??? (PROBS NOT) drag and drop buy / equip / unequip items ???
|
||||||
* modules
|
* modules
|
||||||
* troll life -> dmg
|
* troll life -> dmg
|
||||||
* prince of peace
|
* prince of peace
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.5.6",
|
"version": "1.6.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -132,10 +132,16 @@ aside {
|
|||||||
flex: 0;
|
flex: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ready, .quit {
|
.ready {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 200%;
|
font-size: 200%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quit {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 200%;
|
||||||
|
animation: co 0.75s cubic-bezier(0, 0, 1, 1) 0s infinite alternate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.abandon:not([disabled]) {
|
.abandon:not([disabled]) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ footer {
|
|||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
grid-area: footer;
|
grid-area: footer;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@ -123,7 +123,6 @@
|
|||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
height: 25%;
|
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
button.active {
|
button.active {
|
||||||
@ -204,6 +203,7 @@
|
|||||||
|
|
||||||
.resolving-skill {
|
.resolving-skill {
|
||||||
grid-area: target;
|
grid-area: target;
|
||||||
|
text-align: center;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
height: auto;
|
height: auto;
|
||||||
svg {
|
svg {
|
||||||
@ -213,6 +213,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skill-description {
|
||||||
|
padding-left: 1em;
|
||||||
|
padding-right: 1em;
|
||||||
|
text-align: center;
|
||||||
|
svg {
|
||||||
|
display: inline;
|
||||||
|
height: 1em;
|
||||||
|
margin-right: 0.1em
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* some stupid bug in chrome makes it fill the entire screen */
|
/* some stupid bug in chrome makes it fill the entire screen */
|
||||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
#targeting {
|
#targeting {
|
||||||
@ -396,6 +407,10 @@
|
|||||||
.skills button {
|
.skills button {
|
||||||
font-size: 50%;
|
font-size: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skill-description {
|
||||||
|
font-size: 65%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.player {
|
.player {
|
||||||
|
|||||||
@ -45,5 +45,9 @@
|
|||||||
grid-area: msg;
|
grid-area: msg;
|
||||||
color: @white;
|
color: @white;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ html body {
|
|||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
// overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mnml {
|
#mnml {
|
||||||
@ -26,7 +26,7 @@ html body {
|
|||||||
|
|
||||||
/* stops inspector going skitz*/
|
/* stops inspector going skitz*/
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
// overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @media (min-width: 1921px) {
|
// @media (min-width: 1921px) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.5.6",
|
"version": "1.6.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -11,14 +11,22 @@ export const setAnimText = value => ({ type: 'SET_ANIM_TEXT', value });
|
|||||||
|
|
||||||
export const setDemo = value => ({ type: 'SET_DEMO', value });
|
export const setDemo = value => ({ type: 'SET_DEMO', value });
|
||||||
|
|
||||||
|
export const setChatShow = value => ({ type: 'SET_CHAT_SHOW', value });
|
||||||
|
export const setChatWheel = value => ({ type: 'SET_CHAT_WHEEL', value });
|
||||||
|
export const setInstanceChat = value => ({ type: 'SET_INSTANCE_CHAT', value });
|
||||||
|
|
||||||
export const setActiveItem = value => ({ type: 'SET_ACTIVE_VAR', value });
|
export const setActiveItem = value => ({ type: 'SET_ACTIVE_VAR', value });
|
||||||
export const setActiveSkill = (constructId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: constructId ? { constructId, skill } : null });
|
export const setActiveSkill = (constructId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: constructId ? { constructId, skill } : null });
|
||||||
export const setCombiner = value => ({ type: 'SET_COMBINER', value: Array.from(value) });
|
export const setCombiner = value => ({ type: 'SET_COMBINER', value: Array.from(value) });
|
||||||
export const setConstructEditId = value => ({ type: 'SET_CONSTRUCT_EDIT_ID', value });
|
export const setConstructEditId = value => ({ type: 'SET_CONSTRUCT_EDIT_ID', value });
|
||||||
export const setConstructs = value => ({ type: 'SET_CONSTRUCTS', value });
|
export const setConstructs = value => ({ type: 'SET_CONSTRUCTS', value });
|
||||||
export const setConstructRename = value => ({ type: 'SET_CONSTRUCT_RENAME', value });
|
export const setConstructRename = value => ({ type: 'SET_CONSTRUCT_RENAME', value });
|
||||||
|
|
||||||
export const setGame = value => ({ type: 'SET_GAME', value });
|
export const setGame = value => ({ type: 'SET_GAME', value });
|
||||||
|
export const setGameSkillInfo = value => ({ type: 'SET_GAME_SKILL_INFO', value });
|
||||||
|
export const setGameEffectInfo = value => ({ type: 'SET_GAME_EFFECT_INFO', value });
|
||||||
export const setInfo = value => ({ type: 'SET_INFO', value });
|
export const setInfo = value => ({ type: 'SET_INFO', value });
|
||||||
|
|
||||||
export const setEmail = value => ({ type: 'SET_EMAIL', value });
|
export const setEmail = value => ({ type: 'SET_EMAIL', value });
|
||||||
export const setInvite = value => ({ type: 'SET_INVITE', value });
|
export const setInvite = value => ({ type: 'SET_INVITE', value });
|
||||||
export const setInstance = value => ({ type: 'SET_INSTANCE', value });
|
export const setInstance = value => ({ type: 'SET_INSTANCE', value });
|
||||||
|
|||||||
65
client/src/components/chat.jsx
Normal file
65
client/src/components/chat.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('../actions');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const {
|
||||||
|
ws,
|
||||||
|
chatShow,
|
||||||
|
chatWheel,
|
||||||
|
instance,
|
||||||
|
game,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
function sendInstanceChat(instance, i) {
|
||||||
|
return ws.sendInstanceChat(instance, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
instance,
|
||||||
|
game,
|
||||||
|
chatShow,
|
||||||
|
chatWheel,
|
||||||
|
|
||||||
|
sendInstanceChat,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setChatShow(v) {
|
||||||
|
dispatch(actions.setChatShow(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setChatShow,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function Chat(args) {
|
||||||
|
const {
|
||||||
|
instance,
|
||||||
|
game,
|
||||||
|
chatShow,
|
||||||
|
chatWheel,
|
||||||
|
|
||||||
|
sendInstanceChat,
|
||||||
|
setChatShow,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
function onClick(i) {
|
||||||
|
sendInstanceChat(instance ? instance.id : game && game.id, i);
|
||||||
|
setChatShow(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={`instance-ctrl-btns chat`}>
|
||||||
|
{chatWheel.map((c, i) => <button key={i} onClick={() => onClick(i)} >{c}</button>)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Chat);
|
||||||
@ -2,10 +2,13 @@ const { connect } = require('preact-redux');
|
|||||||
const { Component } = require('preact');
|
const { Component } = require('preact');
|
||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
const range = require('lodash/range');
|
const range = require('lodash/range');
|
||||||
|
const reactStringReplace = require('react-string-replace');
|
||||||
|
|
||||||
const { STATS } = require('../utils');
|
const { STATS } = require('../utils');
|
||||||
const { ConstructAvatar, ConstructText } = require('./construct');
|
const { ConstructAvatar, ConstructText } = require('./construct');
|
||||||
const shapes = require('./shapes');
|
const shapes = require('./shapes');
|
||||||
|
const { INFO } = require('./../constants');
|
||||||
|
const actions = require('../actions');
|
||||||
|
|
||||||
const SkillBtn = require('./skill.btn');
|
const SkillBtn = require('./skill.btn');
|
||||||
|
|
||||||
@ -19,6 +22,8 @@ const addState = connect(
|
|||||||
animFocus,
|
animFocus,
|
||||||
animating,
|
animating,
|
||||||
animText,
|
animText,
|
||||||
|
gameSkillInfo,
|
||||||
|
itemInfo,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
function selectSkillTarget(targetConstructId) {
|
function selectSkillTarget(targetConstructId) {
|
||||||
@ -40,8 +45,19 @@ const addState = connect(
|
|||||||
animText,
|
animText,
|
||||||
activeSkill,
|
activeSkill,
|
||||||
selectSkillTarget,
|
selectSkillTarget,
|
||||||
|
gameSkillInfo,
|
||||||
|
itemInfo,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setGameEffectInfo(info) {
|
||||||
|
dispatch(actions.setGameEffectInfo(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setGameEffectInfo };
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventClasses = (animating, animFocus, construct, postSkill) => {
|
const eventClasses = (animating, animFocus, construct, postSkill) => {
|
||||||
@ -77,6 +93,10 @@ class GameConstruct extends Component {
|
|||||||
selectSkillTarget,
|
selectSkillTarget,
|
||||||
animFocus,
|
animFocus,
|
||||||
animText,
|
animText,
|
||||||
|
|
||||||
|
setGameEffectInfo,
|
||||||
|
gameSkillInfo,
|
||||||
|
itemInfo,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const ko = construct.green_life.value === 0 ? 'ko' : '';
|
const ko = construct.green_life.value === 0 ? 'ko' : '';
|
||||||
@ -96,9 +116,33 @@ class GameConstruct extends Component {
|
|||||||
let crypSkills = <div></div>;
|
let crypSkills = <div></div>;
|
||||||
if (player) crypSkills = (<div class="skills"> {skills} </div>);
|
if (player) crypSkills = (<div class="skills"> {skills} </div>);
|
||||||
|
|
||||||
const effects = construct.effects.length
|
function hoverInfo(e, info) {
|
||||||
? construct.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
|
e.stopPropagation();
|
||||||
: null;
|
return setGameEffectInfo(info);
|
||||||
|
}
|
||||||
|
const effectBox = () => {
|
||||||
|
if (gameSkillInfo && gameSkillInfo.constructId === construct.id) {
|
||||||
|
const fullInfo = itemInfo.items.find(k => k.item === gameSkillInfo.skill) || INFO[gameSkillInfo.skill];
|
||||||
|
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
|
||||||
|
const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]());
|
||||||
|
const speed = <div> Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}% </div>;
|
||||||
|
return (
|
||||||
|
<div class="skill-description">
|
||||||
|
<h2> {gameSkillInfo.skill} </h2>
|
||||||
|
<div> {infoDescription} </div>
|
||||||
|
{speed}
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
const effects = construct.effects.length
|
||||||
|
? construct.effects.map(c =>
|
||||||
|
<div
|
||||||
|
key={c.effect}
|
||||||
|
onMouseOver={e => hoverInfo(e, c)}
|
||||||
|
onMouseOut={e => hoverInfo(e, null)}
|
||||||
|
> {c.effect} - {c.duration}T</div>)
|
||||||
|
: null;
|
||||||
|
return (<div class="effects"> {effects} </div>);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -107,7 +151,7 @@ class GameConstruct extends Component {
|
|||||||
class={`game-construct ${ko} ${classes}`} >
|
class={`game-construct ${ko} ${classes}`} >
|
||||||
<div class="left">
|
<div class="left">
|
||||||
{crypSkills}
|
{crypSkills}
|
||||||
<div class="effects"> {effects} </div>
|
{effectBox()}
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="stats"> {stats} </div>
|
<div class="stats"> {stats} </div>
|
||||||
|
|||||||
@ -8,6 +8,8 @@ const addState = connect(
|
|||||||
const {
|
const {
|
||||||
ws,
|
ws,
|
||||||
game,
|
game,
|
||||||
|
account,
|
||||||
|
chatShow,
|
||||||
animating,
|
animating,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
@ -30,6 +32,8 @@ const addState = connect(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
game,
|
game,
|
||||||
|
account,
|
||||||
|
chatShow,
|
||||||
sendAbandon,
|
sendAbandon,
|
||||||
sendGameSkillClear,
|
sendGameSkillClear,
|
||||||
sendReady,
|
sendReady,
|
||||||
@ -45,7 +49,14 @@ const addState = connect(
|
|||||||
dispatch(actions.setInstance(null));
|
dispatch(actions.setInstance(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { quit };
|
function setChatShow(v) {
|
||||||
|
dispatch(actions.setChatShow(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setChatShow,
|
||||||
|
quit,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -53,10 +64,13 @@ function GameCtrlBtns(args) {
|
|||||||
const {
|
const {
|
||||||
game,
|
game,
|
||||||
animating,
|
animating,
|
||||||
|
account,
|
||||||
|
chatShow,
|
||||||
|
|
||||||
getInstanceState,
|
getInstanceState,
|
||||||
sendGameSkillClear,
|
sendGameSkillClear,
|
||||||
sendReady,
|
sendReady,
|
||||||
|
setChatShow,
|
||||||
quit,
|
quit,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
@ -73,7 +87,7 @@ function GameCtrlBtns(args) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="game-ctrl-btns">
|
<div class="game-ctrl-btns">
|
||||||
<button disabled={true} >Chat</button>
|
<button disabled={!account.subscribed} onClick={() => setChatShow(!chatShow)}>Chat</button>
|
||||||
<button disabled={animating} onClick={sendGameSkillClear}>Clear</button>
|
<button disabled={animating} onClick={sendGameSkillClear}>Clear</button>
|
||||||
{finished ? quitBtn : readyBtn}
|
{finished ? quitBtn : readyBtn}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ const { connect } = require('preact-redux');
|
|||||||
const actions = require('../actions');
|
const actions = require('../actions');
|
||||||
|
|
||||||
const PlayerBox = require('./player.box');
|
const PlayerBox = require('./player.box');
|
||||||
|
const Chat = require('./chat');
|
||||||
const GameCtrlButtons = require('./game.ctrl.btns');
|
const GameCtrlButtons = require('./game.ctrl.btns');
|
||||||
const GameCtrlTopButtons = require('./game.ctrl.btns.top');
|
const GameCtrlTopButtons = require('./game.ctrl.btns.top');
|
||||||
|
|
||||||
@ -13,12 +14,16 @@ const addState = connect(
|
|||||||
animating,
|
animating,
|
||||||
game,
|
game,
|
||||||
account,
|
account,
|
||||||
|
chatShow,
|
||||||
|
instanceChat,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
animating,
|
animating,
|
||||||
game,
|
game,
|
||||||
account,
|
account,
|
||||||
|
chatShow,
|
||||||
|
instanceChat,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -28,6 +33,8 @@ function Controls(args) {
|
|||||||
animating,
|
animating,
|
||||||
account,
|
account,
|
||||||
game,
|
game,
|
||||||
|
chatShow,
|
||||||
|
instanceChat,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!game) return false;
|
if (!game) return false;
|
||||||
@ -37,7 +44,7 @@ function Controls(args) {
|
|||||||
const zero = Date.parse(game.phase_start);
|
const zero = Date.parse(game.phase_start);
|
||||||
const now = animating ? zero : Date.now();
|
const now = animating ? zero : Date.now();
|
||||||
const end = Date.parse(game.phase_end);
|
const end = Date.parse(game.phase_end);
|
||||||
|
|
||||||
const timerPct = game.phase_end
|
const timerPct = game.phase_end
|
||||||
? ((now - zero) / (end - zero) * 100)
|
? ((now - zero) / (end - zero) * 100)
|
||||||
: 100;
|
: 100;
|
||||||
@ -61,13 +68,17 @@ function Controls(args) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const bottom = chatShow
|
||||||
|
? <Chat />
|
||||||
|
: <PlayerBox player={player} isPlayer={true} chat={instanceChat && instanceChat[player.id]} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside>
|
<aside>
|
||||||
{timer}
|
{timer}
|
||||||
<div class="controls instance-ctrl">
|
<div class="controls instance-ctrl">
|
||||||
<GameCtrlTopButtons />
|
<GameCtrlTopButtons />
|
||||||
<PlayerBox player={opponent}/>
|
<PlayerBox player={opponent} chat={instanceChat && instanceChat[opponent.id]}/>
|
||||||
<PlayerBox player={player} isPlayer={true} />
|
{bottom}
|
||||||
<GameCtrlButtons />
|
<GameCtrlButtons />
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@ -7,7 +7,9 @@ const addState = connect(
|
|||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
ws,
|
ws,
|
||||||
|
chatShow,
|
||||||
instance,
|
instance,
|
||||||
|
account,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
function sendReady() {
|
function sendReady() {
|
||||||
@ -21,19 +23,34 @@ const addState = connect(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
instance,
|
instance,
|
||||||
|
chatShow,
|
||||||
|
account,
|
||||||
|
|
||||||
sendAbandon,
|
sendAbandon,
|
||||||
sendReady,
|
sendReady,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setChatShow(v) {
|
||||||
|
dispatch(actions.setChatShow(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setChatShow,
|
||||||
|
};
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function InstanceCtrlBtns(args) {
|
function InstanceCtrlBtns(args) {
|
||||||
const {
|
const {
|
||||||
instance,
|
instance,
|
||||||
|
chatShow,
|
||||||
|
account,
|
||||||
|
|
||||||
sendAbandon,
|
sendAbandon,
|
||||||
sendReady,
|
sendReady,
|
||||||
|
setChatShow,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
const finished = instance && instance.phase === 'Finished';
|
const finished = instance && instance.phase === 'Finished';
|
||||||
@ -49,7 +66,7 @@ function InstanceCtrlBtns(args) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="instance-ctrl-btns">
|
<div class="instance-ctrl-btns">
|
||||||
<button disabled={true} >Chat</button>
|
<button disabled={!account.subscribed} onClick={() => setChatShow(!chatShow)}>Chat</button>
|
||||||
<button disabled={finished} class="ready" onClick={() => sendReady()}>Ready</button>
|
<button disabled={finished} class="ready" onClick={() => sendReady()}>Ready</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,21 +1,27 @@
|
|||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
const actions = require('../actions');
|
|
||||||
const PlayerBox = require('./player.box');
|
const PlayerBox = require('./player.box');
|
||||||
|
const Chat = require('./chat');
|
||||||
const InstanceCtrlBtns = require('./instance.ctrl.btns');
|
const InstanceCtrlBtns = require('./instance.ctrl.btns');
|
||||||
const InstanceCtrlTopBtns = require('./instance.ctrl.top.btns');
|
const InstanceCtrlTopBtns = require('./instance.ctrl.top.btns');
|
||||||
|
|
||||||
|
const actions = require('../actions');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
ws,
|
ws,
|
||||||
instance,
|
instance,
|
||||||
|
instanceChat,
|
||||||
account,
|
account,
|
||||||
|
chatShow,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
chatShow,
|
||||||
instance,
|
instance,
|
||||||
|
instanceChat,
|
||||||
account,
|
account,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -25,6 +31,8 @@ function Controls(args) {
|
|||||||
const {
|
const {
|
||||||
account,
|
account,
|
||||||
instance,
|
instance,
|
||||||
|
instanceChat,
|
||||||
|
chatShow,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!instance) return false;
|
if (!instance) return false;
|
||||||
@ -58,13 +66,17 @@ function Controls(args) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const bottom = chatShow
|
||||||
|
? <Chat />
|
||||||
|
: <PlayerBox player={player} isPlayer={true} chat={instanceChat && instanceChat[player.id]} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside>
|
<aside>
|
||||||
{timer}
|
{timer}
|
||||||
<div class="controls instance-ctrl">
|
<div class="controls instance-ctrl">
|
||||||
<InstanceCtrlTopBtns />
|
<InstanceCtrlTopBtns />
|
||||||
<PlayerBox player={opponent} />
|
<PlayerBox player={opponent} chat={instanceChat && instanceChat[opponent.id]}/>
|
||||||
<PlayerBox player={player} isPlayer={true} />
|
{bottom}
|
||||||
<InstanceCtrlBtns />
|
<InstanceCtrlBtns />
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const preact = require('preact');
|
|||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
const Main = require('./main');
|
const Main = require('./main');
|
||||||
const Nav = require('./nav');
|
// const Nav = require('./nav');
|
||||||
const Controls = require('./controls');
|
const Controls = require('./controls');
|
||||||
const Footer = require('./footer');
|
const Footer = require('./footer');
|
||||||
|
|
||||||
@ -12,7 +12,6 @@ const addState = connect(
|
|||||||
|
|
||||||
const Mnml = ({ showNav }) =>
|
const Mnml = ({ showNav }) =>
|
||||||
<div id="mnml" class={showNav ? 'nav-visible' : ''}>
|
<div id="mnml" class={showNav ? 'nav-visible' : ''}>
|
||||||
<Nav />
|
|
||||||
<Main />
|
<Main />
|
||||||
<Controls />
|
<Controls />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@ -56,6 +56,7 @@ function Scoreboard(args) {
|
|||||||
const {
|
const {
|
||||||
isPlayer,
|
isPlayer,
|
||||||
player,
|
player,
|
||||||
|
chat,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
const scoreText = () => {
|
const scoreText = () => {
|
||||||
@ -73,14 +74,14 @@ function Scoreboard(args) {
|
|||||||
<div class="score">{scoreText()}</div>
|
<div class="score">{scoreText()}</div>
|
||||||
<div class="name">{player.name}</div>
|
<div class="name">{player.name}</div>
|
||||||
<Img img={player.img} id={player.id} />
|
<Img img={player.img} id={player.id} />
|
||||||
<div class="msg"> </div>
|
<div class="msg">{chat || '\u00A0'}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={`player-box bottom ${player.ready ? 'ready' : ''}`}>
|
<div class={`player-box bottom ${player.ready ? 'ready' : ''}`}>
|
||||||
<div class="msg"> </div>
|
<div class="msg">{chat || '\u00A0'}</div>
|
||||||
<div class="score">{scoreText()}</div>
|
<div class="score">{scoreText()}</div>
|
||||||
<div class="name">{player.name}</div>
|
<div class="name">{player.name}</div>
|
||||||
<Img img={player.img} id={player.id} />
|
<Img img={player.img} id={player.id} />
|
||||||
|
|||||||
@ -23,18 +23,24 @@ const addState = connect(
|
|||||||
dispatch(actions.setActiveSkill(constructId, skill));
|
dispatch(actions.setActiveSkill(constructId, skill));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { setActiveSkill };
|
function setGameSkillInfo(info) {
|
||||||
|
dispatch(actions.setGameSkillInfo(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setActiveSkill, setGameSkillInfo };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
function Skill(props) {
|
function Skill(props) {
|
||||||
const {
|
const {
|
||||||
|
animating,
|
||||||
construct,
|
construct,
|
||||||
game,
|
game,
|
||||||
i,
|
i,
|
||||||
activeSkill,
|
activeSkill,
|
||||||
setActiveSkill,
|
setActiveSkill,
|
||||||
|
setGameSkillInfo,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
if (!game) return false;
|
if (!game) return false;
|
||||||
@ -42,6 +48,11 @@ function Skill(props) {
|
|||||||
const s = construct.skills[i];
|
const s = construct.skills[i];
|
||||||
const ko = construct.green_life.value === 0 ? 'ko' : '';
|
const ko = construct.green_life.value === 0 ? 'ko' : '';
|
||||||
|
|
||||||
|
function hoverInfo(e, info) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (animating) return false;
|
||||||
|
return setGameSkillInfo(info);
|
||||||
|
}
|
||||||
if (!s || !game) {
|
if (!s || !game) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@ -76,6 +87,8 @@ function Skill(props) {
|
|||||||
<button
|
<button
|
||||||
disabled={cdText || s.disabled || ko}
|
disabled={cdText || s.disabled || ko}
|
||||||
class={`${(targeting || highlight) ? 'active' : ''} ${border}`}
|
class={`${(targeting || highlight) ? 'active' : ''} ${border}`}
|
||||||
|
onMouseOver={e => hoverInfo(e, { skill: s.skill, constructId: construct.id })}
|
||||||
|
onMouseOut={e => hoverInfo(e, null)}
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={onClick}>
|
onClick={onClick}>
|
||||||
{s.skill} {cdText}
|
{s.skill} {cdText}
|
||||||
|
|||||||
@ -6,11 +6,11 @@ const reactStringReplace = require('react-string-replace');
|
|||||||
const throttle = require('lodash/throttle');
|
const throttle = require('lodash/throttle');
|
||||||
|
|
||||||
const shapes = require('./shapes');
|
const shapes = require('./shapes');
|
||||||
const { removeTier } = require('../utils');
|
const { effectInfo, removeTier } = require('../utils');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
({ game, account, animSkill, animating, itemInfo }) =>
|
({ game, account, animSkill, animating, itemInfo, gameEffectInfo }) =>
|
||||||
({ game, account, animSkill, animating, itemInfo })
|
({ game, account, animSkill, animating, itemInfo, gameEffectInfo })
|
||||||
);
|
);
|
||||||
|
|
||||||
class TargetSvg extends Component {
|
class TargetSvg extends Component {
|
||||||
@ -28,10 +28,24 @@ class TargetSvg extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(props, state) {
|
render(props, state) {
|
||||||
const { game, account, animating, animSkill, itemInfo } = props;
|
const { game, account, animating, animSkill, itemInfo, gameEffectInfo } = props;
|
||||||
const { width, height } = state;
|
const { width, height } = state;
|
||||||
if (!game) return false; // game will be null when battle ends
|
if (!game) return false; // game will be null when battle ends
|
||||||
|
|
||||||
|
// Whenever someones looking at effects throw it up here
|
||||||
|
if (gameEffectInfo) {
|
||||||
|
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
|
||||||
|
const infoString = effectInfo(gameEffectInfo);
|
||||||
|
const infoDescription = reactStringReplace(infoString, regEx, match => shapes[match]());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="resolving-skill">
|
||||||
|
<h1>{gameEffectInfo.effect}</h1>
|
||||||
|
<div> {infoDescription} </div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// resolutions happening
|
// resolutions happening
|
||||||
// just put skill name up
|
// just put skill name up
|
||||||
if (animating) {
|
if (animating) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@ const addState = connect(
|
|||||||
itemInfo,
|
itemInfo,
|
||||||
itemUnequip,
|
itemUnequip,
|
||||||
navInstance,
|
navInstance,
|
||||||
|
info,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
function sendVboxDiscard() {
|
function sendVboxDiscard() {
|
||||||
@ -56,6 +57,7 @@ const addState = connect(
|
|||||||
itemUnequip,
|
itemUnequip,
|
||||||
sendItemUnequip,
|
sendItemUnequip,
|
||||||
navInstance,
|
navInstance,
|
||||||
|
info,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -115,6 +117,7 @@ function Vbox(args) {
|
|||||||
sendItemUnequip,
|
sendItemUnequip,
|
||||||
|
|
||||||
setReclaiming,
|
setReclaiming,
|
||||||
|
info,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!player) return false;
|
if (!player) return false;
|
||||||
@ -138,7 +141,7 @@ function Vbox(args) {
|
|||||||
//
|
//
|
||||||
function vboxHover(e, v) {
|
function vboxHover(e, v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
setInfo(v);
|
if (info !== v) setInfo(v);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -329,7 +332,7 @@ function Vbox(args) {
|
|||||||
|
|
||||||
function combinerBtn() {
|
function combinerBtn() {
|
||||||
let text = '';
|
let text = '';
|
||||||
|
let comboItem = '';
|
||||||
if (combiner.length < 3) {
|
if (combiner.length < 3) {
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
if (combiner.length > i) {
|
if (combiner.length > i) {
|
||||||
@ -339,14 +342,18 @@ function Vbox(args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
text = 'combine';
|
// Since theres 3 items in combiner and you can't have invalid combos we can preview it
|
||||||
|
const combinerItems = combiner.map(j => vbox.bound[j]);
|
||||||
|
const comboItemObj = itemInfo.combos.find(combo => combinerItems.every(c => combo.components.includes(c)));
|
||||||
|
comboItem = comboItemObj ? comboItemObj.item : 'refine';
|
||||||
|
text = `Combine - ${comboItem}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
class='vbox-btn'
|
class='vbox-btn'
|
||||||
disabled={combiner.length !== 3}
|
disabled={combiner.length !== 3}
|
||||||
onMouseOver={e => hoverInfo(e, 'refine')}
|
onMouseOver={e => hoverInfo(e, comboItem)}
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
onMouseDown={() => sendVboxCombine()}>
|
onMouseDown={() => sendVboxCombine()}>
|
||||||
{text}
|
{text}
|
||||||
@ -390,9 +397,10 @@ function Vbox(args) {
|
|||||||
//
|
//
|
||||||
// EVERYTHING
|
// EVERYTHING
|
||||||
//
|
//
|
||||||
function hoverInfo(e, info) {
|
function hoverInfo(e, newInfo) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
return setInfo(info);
|
if (info === newInfo) return true;
|
||||||
|
return setInfo(newInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
const classes = `vbox ${navInstance === 0 ? 'visible' : ''}`;
|
const classes = `vbox ${navInstance === 0 ? 'visible' : ''}`;
|
||||||
|
|||||||
@ -109,7 +109,7 @@ function registerEvents(store) {
|
|||||||
store.dispatch(actions.setAnimTarget(null));
|
store.dispatch(actions.setAnimTarget(null));
|
||||||
store.dispatch(actions.setAnimText(null));
|
store.dispatch(actions.setAnimText(null));
|
||||||
store.dispatch(actions.setAnimating(false));
|
store.dispatch(actions.setAnimating(false));
|
||||||
|
store.dispatch(actions.setGameEffectInfo(null));
|
||||||
store.dispatch(actions.setSkip(false));
|
store.dispatch(actions.setSkip(false));
|
||||||
|
|
||||||
// set the game state so resolutions don't fire twice
|
// set the game state so resolutions don't fire twice
|
||||||
@ -212,6 +212,14 @@ function registerEvents(store) {
|
|||||||
return store.dispatch(actions.setInstance(v));
|
return store.dispatch(actions.setInstance(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setInstanceChat(v) {
|
||||||
|
return store.dispatch(actions.setInstanceChat(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChatWheel(v) {
|
||||||
|
return store.dispatch(actions.setChatWheel(v));
|
||||||
|
}
|
||||||
|
|
||||||
function setItemInfo(v) {
|
function setItemInfo(v) {
|
||||||
return store.dispatch(actions.setItemInfo(v));
|
return store.dispatch(actions.setItemInfo(v));
|
||||||
}
|
}
|
||||||
@ -318,12 +326,14 @@ function registerEvents(store) {
|
|||||||
setAccountInstances,
|
setAccountInstances,
|
||||||
setActiveItem,
|
setActiveItem,
|
||||||
setActiveSkill,
|
setActiveSkill,
|
||||||
|
setChatWheel,
|
||||||
setDemo,
|
setDemo,
|
||||||
setConstructList,
|
setConstructList,
|
||||||
setNewConstruct,
|
setNewConstruct,
|
||||||
setGame,
|
setGame,
|
||||||
setEmail,
|
setEmail,
|
||||||
setInstance,
|
setInstance,
|
||||||
|
setInstanceChat,
|
||||||
setItemInfo,
|
setItemInfo,
|
||||||
setInvite,
|
setInvite,
|
||||||
setPing,
|
setPing,
|
||||||
|
|||||||
@ -24,15 +24,21 @@ module.exports = {
|
|||||||
|
|
||||||
demo: createReducer(null, 'SET_DEMO'),
|
demo: createReducer(null, 'SET_DEMO'),
|
||||||
|
|
||||||
|
chatShow: createReducer(null, 'SET_CHAT_SHOW'),
|
||||||
|
chatWheel: createReducer([], 'SET_CHAT_WHEEL'),
|
||||||
|
|
||||||
combiner: createReducer([], 'SET_COMBINER'),
|
combiner: createReducer([], 'SET_COMBINER'),
|
||||||
constructs: createReducer([], 'SET_CONSTRUCTS'),
|
constructs: createReducer([], 'SET_CONSTRUCTS'),
|
||||||
constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'),
|
constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'),
|
||||||
constructRename: createReducer(null, 'SET_CONSTRUCT_RENAME'),
|
constructRename: createReducer(null, 'SET_CONSTRUCT_RENAME'),
|
||||||
game: createReducer(null, 'SET_GAME'),
|
game: createReducer(null, 'SET_GAME'),
|
||||||
|
gameSkillInfo: createReducer(null, 'SET_GAME_SKILL_INFO'),
|
||||||
|
gameEffectInfo: createReducer(null, 'SET_GAME_EFFECT_INFO'),
|
||||||
email: createReducer(null, 'SET_EMAIL'),
|
email: createReducer(null, 'SET_EMAIL'),
|
||||||
invite: createReducer(null, 'SET_INVITE'),
|
invite: createReducer(null, 'SET_INVITE'),
|
||||||
info: createReducer(null, 'SET_INFO'),
|
info: createReducer(null, 'SET_INFO'),
|
||||||
instance: createReducer(null, 'SET_INSTANCE'),
|
instance: createReducer(null, 'SET_INSTANCE'),
|
||||||
|
instanceChat: createReducer(null, 'SET_INSTANCE_CHAT'),
|
||||||
instances: createReducer([], 'SET_INSTANCES'),
|
instances: createReducer([], 'SET_INSTANCES'),
|
||||||
itemEquip: createReducer(null, 'SET_ITEM_EQUIP'),
|
itemEquip: createReducer(null, 'SET_ITEM_EQUIP'),
|
||||||
itemInfo: createReducer({ combos: [], items: [] }, 'SET_ITEM_INFO'),
|
itemInfo: createReducer({ combos: [], items: [] }, 'SET_ITEM_INFO'),
|
||||||
|
|||||||
@ -67,6 +67,10 @@ function createSocket(events) {
|
|||||||
send(['InstanceState', { instance_id: instanceId }]);
|
send(['InstanceState', { instance_id: instanceId }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendInstanceChat(instanceId, index) {
|
||||||
|
send(['InstanceChat', { instance_id: instanceId, index }]);
|
||||||
|
}
|
||||||
|
|
||||||
function sendVboxAccept(instanceId, group, index) {
|
function sendVboxAccept(instanceId, group, index) {
|
||||||
send(['VboxAccept', { instance_id: instanceId, group, index }]);
|
send(['VboxAccept', { instance_id: instanceId, group, index }]);
|
||||||
events.clearInstance();
|
events.clearInstance();
|
||||||
@ -253,8 +257,11 @@ function createSocket(events) {
|
|||||||
QueueJoined: () => events.notify('you have joined the pvp queue'),
|
QueueJoined: () => events.notify('you have joined the pvp queue'),
|
||||||
InviteRequested: () => events.notify('pvp queue request received'),
|
InviteRequested: () => events.notify('pvp queue request received'),
|
||||||
Invite: code => events.setInvite(code),
|
Invite: code => events.setInvite(code),
|
||||||
|
InstanceChat: chat => events.setInstanceChat(chat),
|
||||||
|
ChatWheel: wheel => events.setChatWheel(wheel),
|
||||||
Joining: () => events.notify('searching for instance...'),
|
Joining: () => events.notify('searching for instance...'),
|
||||||
|
|
||||||
|
Processing: () => true,
|
||||||
Error: errHandler,
|
Error: errHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -358,6 +365,7 @@ function createSocket(events) {
|
|||||||
sendInstanceState,
|
sendInstanceState,
|
||||||
sendInstanceInvite,
|
sendInstanceInvite,
|
||||||
sendInstanceJoin,
|
sendInstanceJoin,
|
||||||
|
sendInstanceChat,
|
||||||
|
|
||||||
sendVboxAccept,
|
sendVboxAccept,
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
|
|||||||
@ -237,6 +237,64 @@ function convertItem(v) {
|
|||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function effectInfo(i) {
|
||||||
|
console.log(i);
|
||||||
|
|
||||||
|
function multiplier(s) { // Update later to use server info in future
|
||||||
|
if (s === 'CounterAttack') return 70;
|
||||||
|
if (s === 'CounterAttack+') return 95;
|
||||||
|
if (s === 'CounterAttack++') return 120;
|
||||||
|
|
||||||
|
if (s === 'DecayTick') return 33;
|
||||||
|
if (s === 'DecayTick+') return 45;
|
||||||
|
if (s === 'DecayTick++') return 70;
|
||||||
|
|
||||||
|
if (s === 'SiphonTick') return 20;
|
||||||
|
if (s === 'SiphonTick+') return 25;
|
||||||
|
if (s === 'SiphonTick++') return 30;
|
||||||
|
|
||||||
|
if (s === 'TriageTick') return 75;
|
||||||
|
if (s === 'TriageTick+') return 110;
|
||||||
|
if (s === 'TriageTick++') return 140;
|
||||||
|
|
||||||
|
if (s === 'Electrocute' || s === 'ElectrocuteTick') return 80;
|
||||||
|
if (s === 'Electrocute+' || s === 'ElectrocuteTick+') return 100;
|
||||||
|
if (s === 'Electrocute++' || s === 'ElectrocuteTick++') return 130;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (i.effect) {
|
||||||
|
case 'Amplify': return `Increases construct RedPower and BluePower by ${i.meta[1] - 100}%`;
|
||||||
|
case 'Banish': return 'Banished construct cannot cast or take damage';
|
||||||
|
case 'Block': return `Reduces construct red damage taken by ${100 - i.meta[1]}%`;
|
||||||
|
case 'Buff': return `Increases construct RedPower and SpeedStat by ${i.meta[1] - 100}%`;
|
||||||
|
case 'Sustain': return 'Construct cannot be KO while active. Additionally provides immunity to disables';
|
||||||
|
case 'Curse': return `Construct will take ${i.meta[1] - 100}% increased red and blue damage`;
|
||||||
|
case 'Haste': return `Construct has ${i.meta[1] - 100}% increased SpeedStat. Red attack skills will trigger a HasteStrike dealing 30% SpeedStat as red damage.`;
|
||||||
|
case 'Hybrid': return `Construct has ${i.meta[1] - 100}% increased GreenPower. Blue attack skills will trigger a HybridBlast dealing 25% GreenPower as red damage.`;
|
||||||
|
case 'Invert': return 'Reverses damage and healing. Healing will damage this construct and damage will heal.';
|
||||||
|
case 'Counter': return `Red damage taken by this construct will trigger a CounterAttack. CounterAttack deals ${multiplier(i.meta[1])}% RedPower as red damage.`;
|
||||||
|
case 'Purge': return 'Disable construct from casting any green skills';
|
||||||
|
case 'Reflect': return 'Reflect blue skills back to caster';
|
||||||
|
case 'Slow': return `Reduces construct SpeedStat by ${100 - i.meta[1]}%`;
|
||||||
|
case 'Restrict': return 'Disable construct from casting any red skills';
|
||||||
|
case 'Stun': return 'Stunned construct cannot use skills';
|
||||||
|
case 'Intercept': return 'Redirect any skills on team to this target construct';
|
||||||
|
case 'Vulnerable': return `Construct will take ${i.meta[1] - 100}% increased red damage`;
|
||||||
|
case 'Silence': return 'Disable construct from casting any blue skills';
|
||||||
|
case 'Wither': return `Construct will take ${100 - i.meta[1]}% reduced healing`; //
|
||||||
|
case 'Decay': return `Construct will take ${multiplier(i.tick.skill)}% of caster's BluePower as blue damage each turn.`; //
|
||||||
|
case 'Electric': return `Attacks against this construct will apply Electrocute dealing ${multiplier(i.meta[1])}% of construct BluePower as blue damage each turn.`;
|
||||||
|
case 'Electrocute': return `Construct will take ${multiplier(i.tick.skill)}% of caster's BluePower as blue damage each turn.`;
|
||||||
|
case 'Absorb': return 'If construct takes damage, Absorption will be applied increasing RedPower and BluePower based on damage taken.';
|
||||||
|
case 'Absorption': return `Increasing construct RedPower and BluePower by ${i.meta[1]}`;
|
||||||
|
case 'Triage': return `Construct will be healed for ${multiplier(i.tick.skill)}% of caster's GreenPower each turn.`;
|
||||||
|
case 'Siphon': return `Construct will take ${multiplier(i.tick.skill)}% of caster's BluePower + GreenPower as blue damage each turn, healing the caster.`;
|
||||||
|
|
||||||
|
default: return 'Missing Effect Text';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
stringSort,
|
stringSort,
|
||||||
numSort,
|
numSort,
|
||||||
@ -251,4 +309,5 @@ module.exports = {
|
|||||||
randomPoints,
|
randomPoints,
|
||||||
removeTier,
|
removeTier,
|
||||||
match,
|
match,
|
||||||
|
effectInfo,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-ops",
|
"name": "mnml-ops",
|
||||||
"version": "1.5.6",
|
"version": "1.6.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mnml"
|
name = "mnml"
|
||||||
version = "1.5.6"
|
version = "1.6.0"
|
||||||
authors = ["ntr <ntr@smokestack.io>"]
|
authors = ["ntr <ntr@smokestack.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -65,6 +65,19 @@ pub fn select(db: &Db, id: Uuid) -> Result<Account, Error> {
|
|||||||
Account::try_from(row)
|
Account::try_from(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn chat_wheel(_db: &Db, _id: Uuid) -> Result<Vec<String>, Error> {
|
||||||
|
return Ok(vec![
|
||||||
|
"gl".to_string(),
|
||||||
|
"hf".to_string(),
|
||||||
|
"gg".to_string(),
|
||||||
|
"thx".to_string(),
|
||||||
|
"nice".to_string(),
|
||||||
|
"hmm".to_string(),
|
||||||
|
"ok".to_string(),
|
||||||
|
"...".to_string(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn select_name(db: &Db, name: &String) -> Result<Account, Error> {
|
pub fn select_name(db: &Db, name: &String) -> Result<Account, Error> {
|
||||||
let query = "
|
let query = "
|
||||||
SELECT id, name, balance, subscribed, img
|
SELECT id, name, balance, subscribed, img
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::thread::{spawn, sleep};
|
||||||
|
use std::time;
|
||||||
|
|
||||||
// Db Commons
|
// Db Commons
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -58,6 +60,9 @@ pub enum Event {
|
|||||||
Invite(Id),
|
Invite(Id),
|
||||||
Join(Id, String),
|
Join(Id, String),
|
||||||
Joined(Id),
|
Joined(Id),
|
||||||
|
|
||||||
|
Chat(Id, Uuid, String),
|
||||||
|
ChatClear(Id, Uuid),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WsClient {
|
struct WsClient {
|
||||||
@ -65,6 +70,7 @@ struct WsClient {
|
|||||||
account: Option<Uuid>,
|
account: Option<Uuid>,
|
||||||
tx: Sender<RpcMessage>,
|
tx: Sender<RpcMessage>,
|
||||||
subs: HashSet<Uuid>,
|
subs: HashSet<Uuid>,
|
||||||
|
chat: Option<(Uuid, String)>,
|
||||||
pvp: bool,
|
pvp: bool,
|
||||||
invite: Option<String>,
|
invite: Option<String>,
|
||||||
}
|
}
|
||||||
@ -120,7 +126,15 @@ impl Events {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let client = WsClient { id, tx, account: account_id, subs: HashSet::new(), pvp: false, invite: None };
|
let client = WsClient { id,
|
||||||
|
tx,
|
||||||
|
account: account_id,
|
||||||
|
subs: HashSet::new(),
|
||||||
|
pvp: false,
|
||||||
|
invite: None,
|
||||||
|
chat: None,
|
||||||
|
};
|
||||||
|
|
||||||
self.clients.insert(id, client);
|
self.clients.insert(id, client);
|
||||||
|
|
||||||
info!("clients={:?}", self.clients.len());
|
info!("clients={:?}", self.clients.len());
|
||||||
@ -171,7 +185,17 @@ impl Events {
|
|||||||
for (client_id, client) in self.clients.iter() {
|
for (client_id, client) in self.clients.iter() {
|
||||||
if client.subs.contains(&id) {
|
if client.subs.contains(&id) {
|
||||||
subs += 1;
|
subs += 1;
|
||||||
match client.tx.send(msg.clone()) {
|
|
||||||
|
let redacted = match client.account {
|
||||||
|
Some(a) => match msg {
|
||||||
|
RpcMessage::InstanceState(ref i) => RpcMessage::InstanceState(i.clone().redact(a)),
|
||||||
|
RpcMessage::GameState(ref i) => RpcMessage::GameState(i.clone().redact(a)),
|
||||||
|
_ => msg.clone(),
|
||||||
|
}
|
||||||
|
None => msg.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match client.tx.send(redacted) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("unable to send msg to client err={:?}", e);
|
warn!("unable to send msg to client err={:?}", e);
|
||||||
@ -205,7 +229,7 @@ impl Events {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the req for the already queued opponent
|
// create the req for the already queued opponent
|
||||||
if let Some(opp_req) = match self.clients.iter_mut().find(|(_c_id, c)| c.pvp) {
|
if let Some(opp_req) = match self.clients.iter_mut().find(|(c_id, c)| c.pvp && **c_id != id) {
|
||||||
Some((q_id, q)) => {
|
Some((q_id, q)) => {
|
||||||
q.pvp = false;
|
q.pvp = false;
|
||||||
Some(PvpRequest { id: *q_id, account: q.account.unwrap(), tx: q.tx.clone() })
|
Some(PvpRequest { id: *q_id, account: q.account.unwrap(), tx: q.tx.clone() })
|
||||||
@ -281,6 +305,58 @@ impl Events {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Event::Chat(id, instance, msg) => {
|
||||||
|
// set the chat state of this connection
|
||||||
|
{
|
||||||
|
let c = self.clients.get_mut(&id)
|
||||||
|
.ok_or(format_err!("connection not found id={:?}", id))?;
|
||||||
|
|
||||||
|
if c.chat.is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
c.chat = Some((instance, msg));
|
||||||
|
|
||||||
|
let events_tx = self.tx.clone();
|
||||||
|
spawn(move || {
|
||||||
|
sleep(time::Duration::from_secs(3));
|
||||||
|
events_tx.send(Event::ChatClear(id, instance)).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// now collect all listeners of this instance
|
||||||
|
|
||||||
|
let chat_state: HashMap<Uuid, String> = self.clients.iter()
|
||||||
|
.filter(|(_id, c)| c.account.is_some())
|
||||||
|
.filter(|(_id, c)| match c.chat {
|
||||||
|
Some(ref chat) => chat.0 == instance,
|
||||||
|
None => false,
|
||||||
|
})
|
||||||
|
.map(|(_id, c)| (c.account.unwrap(), c.chat.clone().unwrap().1))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state)));
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::ChatClear(id, instance) => {
|
||||||
|
{
|
||||||
|
match self.clients.get_mut(&id) {
|
||||||
|
Some(c) => c.chat = None,
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let chat_state: HashMap<Uuid, String> = self.clients.iter()
|
||||||
|
.filter(|(_id, c)| c.account.is_some())
|
||||||
|
.filter(|(_id, c)| match c.chat {
|
||||||
|
Some(ref chat) => chat.0 == instance,
|
||||||
|
None => false,
|
||||||
|
})
|
||||||
|
.map(|(_id, c)| (c.account.unwrap(), c.chat.clone().unwrap().1))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,17 @@ impl Game {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn redact(mut self, account: Uuid) -> Game {
|
||||||
|
self.players = self.players.into_iter()
|
||||||
|
.map(|p| p.redact(account))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.stack
|
||||||
|
.retain(|s| s.source_player_id == account);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_time_control(&mut self, tc: TimeControl) -> &mut Game {
|
pub fn set_time_control(&mut self, tc: TimeControl) -> &mut Game {
|
||||||
self.time_control = tc;
|
self.time_control = tc;
|
||||||
self.phase_end = Some(tc.lobby_timeout());
|
self.phase_end = Some(tc.lobby_timeout());
|
||||||
@ -631,8 +642,8 @@ pub fn game_write(tx: &mut Transaction, game: &Game) -> Result<(), Error> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn game_state(tx: &mut Transaction, _account: &Account, id: Uuid) -> Result<Game, Error> {
|
pub fn game_state(tx: &mut Transaction, account: &Account, id: Uuid) -> Result<Game, Error> {
|
||||||
return game_get(tx, id)
|
Ok(game_get(tx, id)?.redact(account.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn game_get(tx: &mut Transaction, id: Uuid) -> Result<Game, Error> {
|
pub fn game_get(tx: &mut Transaction, id: Uuid) -> Result<Game, Error> {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::collections::{HashMap};
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -31,6 +32,8 @@ enum InstancePhase {
|
|||||||
Finished,
|
Finished,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ChatState = HashMap<Uuid, String>;
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
struct Round {
|
struct Round {
|
||||||
game_id: Option<Uuid>,
|
game_id: Option<Uuid>,
|
||||||
@ -126,6 +129,14 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn redact(mut self, account: Uuid) -> Instance {
|
||||||
|
self.players = self.players.into_iter()
|
||||||
|
.map(|p| p.redact(account))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn phase_timed_out(&self) -> bool {
|
fn phase_timed_out(&self) -> bool {
|
||||||
match self.phase_end {
|
match self.phase_end {
|
||||||
Some(t) => Utc::now().signed_duration_since(t).num_milliseconds() > 0,
|
Some(t) => Utc::now().signed_duration_since(t).num_milliseconds() > 0,
|
||||||
|
|||||||
@ -850,7 +850,8 @@ impl Item {
|
|||||||
Item::Slay|
|
Item::Slay|
|
||||||
Item::SlayPlus |
|
Item::SlayPlus |
|
||||||
Item::SlayPlusPlus => format!(
|
Item::SlayPlusPlus => format!(
|
||||||
"Deals {:?}% RedPower as red damage and provides self healing based on damage dealt.",
|
"Deals {:?}% RedPower + {:?}% GreenPower as red damage and provides self healing based on damage dealt.",
|
||||||
|
self.into_skill().unwrap().multiplier(),
|
||||||
self.into_skill().unwrap().multiplier()),
|
self.into_skill().unwrap().multiplier()),
|
||||||
|
|
||||||
Item::Sleep|
|
Item::Sleep|
|
||||||
@ -884,7 +885,8 @@ impl Item {
|
|||||||
Item::Siphon|
|
Item::Siphon|
|
||||||
Item::SiphonPlus |
|
Item::SiphonPlus |
|
||||||
Item::SiphonPlusPlus => format!(
|
Item::SiphonPlusPlus => format!(
|
||||||
"Deals {:?}% BluePower as blue damage each turn and heals caster based on damage dealt. Lasts {:?}T.",
|
"Deals {:?}% BluePower + {:?}% GreenPower as blue damage each turn and heals caster based on damage dealt. Lasts {:?}T.",
|
||||||
|
self.into_skill().unwrap().effect()[0].get_skill().unwrap().multiplier(),
|
||||||
self.into_skill().unwrap().effect()[0].get_skill().unwrap().multiplier(),
|
self.into_skill().unwrap().effect()[0].get_skill().unwrap().multiplier(),
|
||||||
self.into_skill().unwrap().effect()[0].get_duration()),
|
self.into_skill().unwrap().effect()[0].get_duration()),
|
||||||
|
|
||||||
|
|||||||
@ -103,6 +103,24 @@ impl Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn redact(mut self, account: Uuid) -> Player {
|
||||||
|
// all g
|
||||||
|
if account == self.id {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove vbox
|
||||||
|
self.vbox = Vbox::new();
|
||||||
|
|
||||||
|
// hide skills
|
||||||
|
for construct in self.constructs.iter_mut() {
|
||||||
|
construct.skills = vec![];
|
||||||
|
construct.specs = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_bot(mut self, bot: bool) -> Player {
|
pub fn set_bot(mut self, bot: bool) -> Player {
|
||||||
self.bot = bot;
|
self.bot = bot;
|
||||||
self
|
self
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
use std::time::{Instant};
|
use std::time::{Instant};
|
||||||
use std::thread::spawn;
|
use std::thread::{spawn, sleep};
|
||||||
|
use std::time;
|
||||||
|
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -21,7 +23,7 @@ use account;
|
|||||||
use construct::{Construct};
|
use construct::{Construct};
|
||||||
use events::{Event};
|
use events::{Event};
|
||||||
use game::{Game, game_state, game_skill, game_skill_clear, game_ready};
|
use game::{Game, game_state, game_skill, game_skill_clear, game_ready};
|
||||||
use instance::{Instance, instance_state, instance_practice, instance_ready, instance_abandon, demo};
|
use instance::{Instance, ChatState, instance_state, instance_practice, instance_ready, instance_abandon, demo};
|
||||||
use item::{Item, ItemInfoCtr, item_info};
|
use item::{Item, ItemInfoCtr, item_info};
|
||||||
use mtx;
|
use mtx;
|
||||||
use mail;
|
use mail;
|
||||||
@ -50,6 +52,8 @@ pub enum RpcMessage {
|
|||||||
ItemInfo(ItemInfoCtr),
|
ItemInfo(ItemInfoCtr),
|
||||||
|
|
||||||
InstanceState(Instance),
|
InstanceState(Instance),
|
||||||
|
InstanceChat(ChatState),
|
||||||
|
ChatWheel(Vec<String>),
|
||||||
|
|
||||||
EmailState(Option<Email>),
|
EmailState(Option<Email>),
|
||||||
SubscriptionState(Option<Subscription>),
|
SubscriptionState(Option<Subscription>),
|
||||||
@ -66,6 +70,8 @@ pub enum RpcMessage {
|
|||||||
Invite(String),
|
Invite(String),
|
||||||
Joining(()),
|
Joining(()),
|
||||||
|
|
||||||
|
Processing(()),
|
||||||
|
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +108,7 @@ pub enum RpcRequest {
|
|||||||
InstanceAbandon { instance_id: Uuid },
|
InstanceAbandon { instance_id: Uuid },
|
||||||
InstanceReady { instance_id: Uuid },
|
InstanceReady { instance_id: Uuid },
|
||||||
InstanceState { instance_id: Uuid },
|
InstanceState { instance_id: Uuid },
|
||||||
|
InstanceChat { instance_id: Uuid, index: usize },
|
||||||
|
|
||||||
VboxAccept { instance_id: Uuid, group: usize, index: usize },
|
VboxAccept { instance_id: Uuid, group: usize, index: usize },
|
||||||
VboxDiscard { instance_id: Uuid },
|
VboxDiscard { instance_id: Uuid },
|
||||||
@ -158,6 +165,22 @@ impl Connection {
|
|||||||
self.events.send(Event::Join(self.id, code))?;
|
self.events.send(Event::Join(self.id, code))?;
|
||||||
Ok(RpcMessage::Joining(()))
|
Ok(RpcMessage::Joining(()))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
RpcRequest::InstanceChat { instance_id, index } => {
|
||||||
|
if !account.subscribed {
|
||||||
|
return Err(err_msg("subscribe to unlock chat"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let wheel = account::chat_wheel(&db, account.id)?;
|
||||||
|
|
||||||
|
if let Some(c) = wheel.get(index) {
|
||||||
|
self.events.send(Event::Chat(self.id, instance_id, c.to_string()))?;
|
||||||
|
} else {
|
||||||
|
return Err(err_msg("invalid chat index"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(RpcMessage::Processing(()))
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// all good, let's make a tx and process
|
// all good, let's make a tx and process
|
||||||
let mut tx = db.transaction()?;
|
let mut tx = db.transaction()?;
|
||||||
@ -257,6 +280,25 @@ impl Connection {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is where last minute processing happens
|
||||||
|
// use it to modify outgoing messages, update subs, serialize in some way...
|
||||||
|
fn send(&self, msg: RpcMessage) -> Result<(), Error> {
|
||||||
|
let msg = match self.account {
|
||||||
|
Some(ref a) => match msg {
|
||||||
|
RpcMessage::InstanceState(v) => RpcMessage::InstanceState(v.redact(a.id)),
|
||||||
|
RpcMessage::AccountInstances(v) =>
|
||||||
|
RpcMessage::AccountInstances(v.into_iter().map(|i| i.redact(a.id)).collect()),
|
||||||
|
RpcMessage::GameState(v) => RpcMessage::GameState(v.redact(a.id)),
|
||||||
|
_ => msg,
|
||||||
|
},
|
||||||
|
None => msg,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ws.send(msg).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we unwrap everything in here cause really
|
// we unwrap everything in here cause really
|
||||||
@ -272,7 +314,7 @@ impl Handler for Connection {
|
|||||||
|
|
||||||
// if user logged in do some prep work
|
// if user logged in do some prep work
|
||||||
if let Some(ref a) = self.account {
|
if let Some(ref a) = self.account {
|
||||||
self.ws.send(RpcMessage::AccountState(a.clone())).unwrap();
|
self.send(RpcMessage::AccountState(a.clone())).unwrap();
|
||||||
self.events.send(Event::Subscribe(self.id, a.id)).unwrap();
|
self.events.send(Event::Subscribe(self.id, a.id)).unwrap();
|
||||||
|
|
||||||
// check if they have an image that needs to be generated
|
// check if they have an image that needs to be generated
|
||||||
@ -283,23 +325,26 @@ impl Handler for Connection {
|
|||||||
|
|
||||||
// send account constructs
|
// send account constructs
|
||||||
let account_constructs = account::constructs(&mut tx, a).unwrap();
|
let account_constructs = account::constructs(&mut tx, a).unwrap();
|
||||||
self.ws.send(RpcMessage::AccountConstructs(account_constructs)).unwrap();
|
self.send(RpcMessage::AccountConstructs(account_constructs)).unwrap();
|
||||||
|
|
||||||
// get account instances
|
// get account instances
|
||||||
// and send them to the client
|
// and send them to the client
|
||||||
let account_instances = account::account_instances(&mut tx, a).unwrap();
|
let account_instances = account::account_instances(&mut tx, a).unwrap();
|
||||||
self.ws.send(RpcMessage::AccountInstances(account_instances)).unwrap();
|
self.send(RpcMessage::AccountInstances(account_instances)).unwrap();
|
||||||
|
|
||||||
let shop = mtx::account_shop(&mut tx, &a).unwrap();
|
let shop = mtx::account_shop(&mut tx, &a).unwrap();
|
||||||
self.ws.send(RpcMessage::AccountShop(shop)).unwrap();
|
self.send(RpcMessage::AccountShop(shop)).unwrap();
|
||||||
|
|
||||||
let team = account::team(&mut tx, &a).unwrap();
|
let team = account::team(&mut tx, &a).unwrap();
|
||||||
self.ws.send(RpcMessage::AccountTeam(team)).unwrap();
|
self.send(RpcMessage::AccountTeam(team)).unwrap();
|
||||||
|
|
||||||
|
let wheel = account::chat_wheel(&db, a.id).unwrap();
|
||||||
|
self.send(RpcMessage::ChatWheel(wheel)).unwrap();
|
||||||
|
|
||||||
// tx should do nothing
|
// tx should do nothing
|
||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
} else {
|
} else {
|
||||||
self.ws.send(RpcMessage::Demo(demo().unwrap())).unwrap();
|
self.send(RpcMessage::Demo(demo().unwrap())).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -327,11 +372,11 @@ impl Handler for Connection {
|
|||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.ws.send(reply).unwrap();
|
self.send(reply).unwrap();
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("{:?}", e);
|
warn!("{:?}", e);
|
||||||
self.ws.send(RpcMessage::Error(e.to_string())).unwrap();
|
self.send(RpcMessage::Error(e.to_string())).unwrap();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -757,13 +757,13 @@ impl Skill {
|
|||||||
Skill::HealPlus => 185, //GG
|
Skill::HealPlus => 185, //GG
|
||||||
Skill::HealPlusPlus => 270, //GG
|
Skill::HealPlusPlus => 270, //GG
|
||||||
|
|
||||||
Skill::SiphonTick=> 40, // GB
|
Skill::SiphonTick=> 20, // GB
|
||||||
Skill::SiphonTickPlus => 50,
|
Skill::SiphonTickPlus => 25,
|
||||||
Skill::SiphonTickPlusPlus => 60,
|
Skill::SiphonTickPlusPlus => 30,
|
||||||
|
|
||||||
Skill::Slay=> 70, // RG
|
Skill::Slay=> 40, // RG
|
||||||
Skill::SlayPlus => 115,
|
Skill::SlayPlus => 60,
|
||||||
Skill::SlayPlusPlus => 180,
|
Skill::SlayPlusPlus => 90,
|
||||||
|
|
||||||
Skill::Strike=> 90, //RR
|
Skill::Strike=> 90, //RR
|
||||||
Skill::StrikePlus => 140,
|
Skill::StrikePlus => 140,
|
||||||
@ -1420,9 +1420,7 @@ fn break_(source: &mut Construct, target: &mut Construct, mut results: Resolutio
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn block(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn block(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
results.push(Resolution::new(source, target)
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||||
.event(target.add_effect(skill, skill.effect()[0]))
|
|
||||||
.stages(EventStages::StartEnd));
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1473,7 +1471,7 @@ fn restrict(source: &mut Construct, target: &mut Construct, mut results: Resolut
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn slay(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn slay(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
let amount = source.red_power().pct(skill.multiplier());
|
let amount = source.red_power().pct(skill.multiplier()) + source.green_power().pct(skill.multiplier());
|
||||||
let slay_events = target.deal_red_damage(skill, amount);
|
let slay_events = target.deal_red_damage(skill, amount);
|
||||||
|
|
||||||
for e in slay_events {
|
for e in slay_events {
|
||||||
@ -1734,7 +1732,7 @@ fn siphon(source: &mut Construct, target: &mut Construct, mut results: Resolutio
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn siphon_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn siphon_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
let amount = source.blue_power().pct(skill.multiplier());
|
let amount = source.blue_power().pct(skill.multiplier()) + source.green_power().pct(skill.multiplier());
|
||||||
let siphon_events = target.deal_blue_damage(skill, amount);
|
let siphon_events = target.deal_blue_damage(skill, amount);
|
||||||
|
|
||||||
for e in siphon_events {
|
for e in siphon_events {
|
||||||
@ -2039,13 +2037,14 @@ mod tests {
|
|||||||
.named(&"camel".to_string());
|
.named(&"camel".to_string());
|
||||||
|
|
||||||
x.blue_power.force(256);
|
x.blue_power.force(256);
|
||||||
|
x.green_power.force(220);
|
||||||
x.green_life.force(1024);
|
x.green_life.force(1024);
|
||||||
x.green_life.reduce(512);
|
x.green_life.reduce(512);
|
||||||
|
|
||||||
let mut results = resolve(Skill::Siphon, &mut x, &mut y, vec![]);
|
let mut results = resolve(Skill::Siphon, &mut x, &mut y, vec![]);
|
||||||
|
|
||||||
assert!(y.affected(Effect::Siphon));
|
assert!(y.affected(Effect::Siphon));
|
||||||
assert!(x.green_life() == (512 + 256.pct(Skill::SiphonTick.multiplier())));
|
assert!(x.green_life() == (512 + 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier())));
|
||||||
|
|
||||||
let Resolution { source: _, target: _, event, stages: _ } = results.remove(0);
|
let Resolution { source: _, target: _, event, stages: _ } = results.remove(0);
|
||||||
match event {
|
match event {
|
||||||
@ -2055,14 +2054,15 @@ mod tests {
|
|||||||
|
|
||||||
let Resolution { source: _, target: _, event, stages: _ } = results.remove(0);
|
let Resolution { source: _, target: _, event, stages: _ } = results.remove(0);
|
||||||
match event {
|
match event {
|
||||||
Event::Damage { amount, skill: _, mitigation: _, colour: _} => assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier())),
|
Event::Damage { amount, skill: _, mitigation: _, colour: _} => assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier())
|
||||||
|
+ 220.pct(Skill::SiphonTick.multiplier())),
|
||||||
_ => panic!("not damage siphon"),
|
_ => panic!("not damage siphon"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let Resolution { source: _, target, event, stages: _ } = results.remove(0);
|
let Resolution { source: _, target, event, stages: _ } = results.remove(0);
|
||||||
match event {
|
match event {
|
||||||
Event::Healing { amount, skill: _, overhealing: _ } => {
|
Event::Healing { amount, skill: _, overhealing: _ } => {
|
||||||
assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()));
|
assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier()));
|
||||||
assert_eq!(target.id, x.id);
|
assert_eq!(target.id, x.id);
|
||||||
},
|
},
|
||||||
_ => panic!("not healing"),
|
_ => panic!("not healing"),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user