Merge branch 'develop' of ssh://git.mnml.gg:40022/~/mnml into develop
This commit is contained in:
commit
d4ae38e733
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.4.4",
|
"version": "1.4.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -53,7 +53,7 @@ aside {
|
|||||||
border-color: forestgreen;
|
border-color: forestgreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active, &:focus {
|
&:active, &:focus, &.enabled {
|
||||||
background: forestgreen;
|
background: forestgreen;
|
||||||
color: black;
|
color: black;
|
||||||
border-color: forestgreen;
|
border-color: forestgreen;
|
||||||
|
|||||||
@ -286,3 +286,9 @@ li {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#clipboard {
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.4.4",
|
"version": "1.4.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"preact-compat": "^3.19.0",
|
"preact-compat": "^3.19.0",
|
||||||
"preact-context": "^1.1.3",
|
"preact-context": "^1.1.3",
|
||||||
"preact-redux": "^2.1.0",
|
"preact-redux": "^2.1.0",
|
||||||
|
"query-string": "^6.8.3",
|
||||||
"react-string-replace": "^0.4.4",
|
"react-string-replace": "^0.4.4",
|
||||||
"react-stripe-elements": "^3.0.0",
|
"react-stripe-elements": "^3.0.0",
|
||||||
"redux": "^4.0.0"
|
"redux": "^4.0.0"
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export const setConstructRename = value => ({ type: 'SET_CONSTRUCT_RENAME', valu
|
|||||||
export const setGame = value => ({ type: 'SET_GAME', value });
|
export const setGame = value => ({ type: 'SET_GAME', 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 setInstance = value => ({ type: 'SET_INSTANCE', value });
|
export const setInstance = value => ({ type: 'SET_INSTANCE', value });
|
||||||
export const setInstances = value => ({ type: 'SET_INSTANCES', value });
|
export const setInstances = value => ({ type: 'SET_INSTANCES', value });
|
||||||
export const setItemEquip = value => ({ type: 'SET_ITEM_EQUIP', value });
|
export const setItemEquip = value => ({ type: 'SET_ITEM_EQUIP', value });
|
||||||
|
|||||||
@ -76,7 +76,9 @@ function Controls(args) {
|
|||||||
background: displayColour,
|
background: displayColour,
|
||||||
};
|
};
|
||||||
|
|
||||||
const timer = (
|
const timer = instance.phase !== 'InProgress'
|
||||||
|
? null
|
||||||
|
: (
|
||||||
<div class="timer-container">
|
<div class="timer-container">
|
||||||
<div class="timer" style={timerStyles} > </div>
|
<div class="timer" style={timerStyles} > </div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const { errorToast, infoToast } = require('../utils');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
ws,
|
ws,
|
||||||
instances,
|
instances,
|
||||||
|
invite,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
function sendInstanceState(id) {
|
function sendInstanceState(id) {
|
||||||
@ -20,12 +23,18 @@ const addState = connect(
|
|||||||
ws.sendInstanceQueue();
|
ws.sendInstanceQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendInstanceInvite() {
|
||||||
|
ws.sendInstanceInvite();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instances,
|
instances,
|
||||||
|
invite,
|
||||||
|
|
||||||
sendInstanceState,
|
sendInstanceState,
|
||||||
sendInstanceQueue,
|
sendInstanceQueue,
|
||||||
sendInstancePractice,
|
sendInstancePractice,
|
||||||
|
sendInstanceInvite,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -33,10 +42,12 @@ const addState = connect(
|
|||||||
function JoinButtons(args) {
|
function JoinButtons(args) {
|
||||||
const {
|
const {
|
||||||
instances,
|
instances,
|
||||||
|
invite,
|
||||||
|
|
||||||
sendInstanceState,
|
sendInstanceState,
|
||||||
sendInstanceQueue,
|
sendInstanceQueue,
|
||||||
sendInstancePractice,
|
sendInstancePractice,
|
||||||
|
sendInstanceInvite,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (instances.length) {
|
if (instances.length) {
|
||||||
@ -55,6 +66,48 @@ function JoinButtons(args) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const inviteBtn = () => {
|
||||||
|
if (!invite) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
class='pvp ready'
|
||||||
|
onClick={() => sendInstanceInvite()}
|
||||||
|
type="submit">
|
||||||
|
Invite
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyClick(e) {
|
||||||
|
const link = `${document.location.origin}#join=${invite}`;
|
||||||
|
const textArea = document.createElement('textarea', { id: '#clipboard' });
|
||||||
|
textArea.value = link;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
infoToast('Invite link copied.');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('link copy error', err);
|
||||||
|
errorToast('Invite link copy error.');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
class='pvp ready enabled'
|
||||||
|
onClick={copyClick}
|
||||||
|
type="submit">
|
||||||
|
Copy Link
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside class='play-ctrl'>
|
<aside class='play-ctrl'>
|
||||||
<div class="timer-container"></div>
|
<div class="timer-container"></div>
|
||||||
@ -65,6 +118,7 @@ function JoinButtons(args) {
|
|||||||
type="submit">
|
type="submit">
|
||||||
PVP
|
PVP
|
||||||
</button>
|
</button>
|
||||||
|
{inviteBtn()}
|
||||||
<button
|
<button
|
||||||
class='practice ready'
|
class='practice ready'
|
||||||
onClick={() => sendInstancePractice()}
|
onClick={() => sendInstancePractice()}
|
||||||
|
|||||||
@ -92,13 +92,14 @@ function Play(args) {
|
|||||||
<section class="top">
|
<section class="top">
|
||||||
<div class="news">
|
<div class="news">
|
||||||
<h1>v{VERSION}</h1>
|
<h1>v{VERSION}</h1>
|
||||||
<p>use the buttons on the right to join an instance.</p>
|
<p>Use the buttons on the right to join an instance.</p>
|
||||||
<p>
|
<p>
|
||||||
select <b>PVP</b> to play against other players.<br />
|
Select <b>PVP</b> to play against other players.<br />
|
||||||
click <b>LEARN</b> to practice the game without time controls.
|
Select <b>INVITE</b> then click <b>COPY LINK</b> to generate an instance invitation for a friend.<br />
|
||||||
|
Click <b>LEARN</b> to practice the game without time controls.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
if you enjoy the game please support its development by <b>subscribing</b> or purchasing <b>credits</b>.<br />
|
If you enjoy the game please support its development by <b>subscribing</b> or purchasing <b>credits</b>.<br />
|
||||||
glhf
|
glhf
|
||||||
</p>
|
</p>
|
||||||
<p>--ntr & mashy</p>
|
<p>--ntr & mashy</p>
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
const querystring = require('query-string');
|
||||||
|
|
||||||
const eachSeries = require('async/eachSeries');
|
const eachSeries = require('async/eachSeries');
|
||||||
const sample = require('lodash/sample');
|
const sample = require('lodash/sample');
|
||||||
|
|
||||||
@ -168,9 +170,20 @@ function registerEvents(store) {
|
|||||||
return store.dispatch(actions.setInstances(v));
|
return store.dispatch(actions.setInstances(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setInvite(code) {
|
||||||
|
if (!code) return store.dispatch(actions.setInvite(null));
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(code).then(() => {
|
||||||
|
notify(`your invite code ${code} was copied to the clipboard.`);
|
||||||
|
}, () => {});
|
||||||
|
|
||||||
|
return store.dispatch(actions.setInvite(code));
|
||||||
|
}
|
||||||
|
|
||||||
function setInstance(v) {
|
function setInstance(v) {
|
||||||
const { account, instance, ws } = store.getState();
|
const { account, instance, ws } = store.getState();
|
||||||
if (v) {
|
if (v) {
|
||||||
|
setInvite(null);
|
||||||
const player = v.players.find(p => p.id === account.id);
|
const player = v.players.find(p => p.id === account.id);
|
||||||
store.dispatch(actions.setPlayer(player));
|
store.dispatch(actions.setPlayer(player));
|
||||||
|
|
||||||
@ -272,6 +285,16 @@ function registerEvents(store) {
|
|||||||
} */
|
} */
|
||||||
// setup / localstorage
|
// setup / localstorage
|
||||||
|
|
||||||
|
function urlHashChange() {
|
||||||
|
const { ws } = store.getState();
|
||||||
|
const cmds = querystring.parse(location.hash);
|
||||||
|
|
||||||
|
if (cmds.join) ws.sendInstanceJoin(cmds.join);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', urlHashChange, false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clearCombiner,
|
clearCombiner,
|
||||||
clearConstructRename,
|
clearConstructRename,
|
||||||
@ -289,12 +312,15 @@ function registerEvents(store) {
|
|||||||
setEmail,
|
setEmail,
|
||||||
setInstance,
|
setInstance,
|
||||||
setItemInfo,
|
setItemInfo,
|
||||||
|
setInvite,
|
||||||
setPing,
|
setPing,
|
||||||
setShop,
|
setShop,
|
||||||
setTeam,
|
setTeam,
|
||||||
setSubscription,
|
setSubscription,
|
||||||
setWs,
|
setWs,
|
||||||
|
|
||||||
|
urlHashChange,
|
||||||
|
|
||||||
notify,
|
notify,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ module.exports = {
|
|||||||
constructRename: createReducer(null, 'SET_CONSTRUCT_RENAME'),
|
constructRename: createReducer(null, 'SET_CONSTRUCT_RENAME'),
|
||||||
game: createReducer(null, 'SET_GAME'),
|
game: createReducer(null, 'SET_GAME'),
|
||||||
email: createReducer(null, 'SET_EMAIL'),
|
email: createReducer(null, 'SET_EMAIL'),
|
||||||
|
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'),
|
||||||
instances: createReducer([], 'SET_INSTANCES'),
|
instances: createReducer([], 'SET_INSTANCES'),
|
||||||
|
|||||||
@ -126,6 +126,14 @@ function createSocket(events) {
|
|||||||
send(['InstanceQueue', {}]);
|
send(['InstanceQueue', {}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendInstanceInvite() {
|
||||||
|
send(['InstanceInvite', {}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendInstanceJoin(code) {
|
||||||
|
send(['InstanceJoin', { code }]);
|
||||||
|
}
|
||||||
|
|
||||||
function sendInstanceReady(instanceId) {
|
function sendInstanceReady(instanceId) {
|
||||||
send(['InstanceReady', { instance_id: instanceId }]);
|
send(['InstanceReady', { instance_id: instanceId }]);
|
||||||
}
|
}
|
||||||
@ -239,6 +247,9 @@ function createSocket(events) {
|
|||||||
|
|
||||||
QueueRequested: () => events.notify('pvp queue request received'),
|
QueueRequested: () => events.notify('pvp queue request received'),
|
||||||
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'),
|
||||||
|
Invite: code => events.setInvite(code),
|
||||||
|
Joining: () => events.notify('searching for instance...'),
|
||||||
|
|
||||||
Error: errHandler,
|
Error: errHandler,
|
||||||
};
|
};
|
||||||
@ -284,6 +295,8 @@ function createSocket(events) {
|
|||||||
sendPing();
|
sendPing();
|
||||||
sendItemInfo();
|
sendItemInfo();
|
||||||
|
|
||||||
|
events.urlHashChange();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,6 +331,7 @@ function createSocket(events) {
|
|||||||
ws.addEventListener('message', onMessage);
|
ws.addEventListener('message', onMessage);
|
||||||
ws.addEventListener('error', onError);
|
ws.addEventListener('error', onError);
|
||||||
ws.addEventListener('close', onClose);
|
ws.addEventListener('close', onClose);
|
||||||
|
|
||||||
return ws;
|
return ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,6 +352,8 @@ function createSocket(events) {
|
|||||||
sendInstancePractice,
|
sendInstancePractice,
|
||||||
sendInstanceQueue,
|
sendInstanceQueue,
|
||||||
sendInstanceState,
|
sendInstanceState,
|
||||||
|
sendInstanceInvite,
|
||||||
|
sendInstanceJoin,
|
||||||
|
|
||||||
sendVboxAccept,
|
sendVboxAccept,
|
||||||
sendVboxApply,
|
sendVboxApply,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-ops",
|
"name": "mnml-ops",
|
||||||
"version": "1.4.4",
|
"version": "1.4.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mnml"
|
name = "mnml"
|
||||||
version = "1.4.4"
|
version = "1.4.5"
|
||||||
authors = ["ntr <ntr@smokestack.io>"]
|
authors = ["ntr <ntr@smokestack.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -46,7 +46,6 @@ impl Colours {
|
|||||||
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
||||||
pub struct ConstructSkill {
|
pub struct ConstructSkill {
|
||||||
pub skill: Skill,
|
pub skill: Skill,
|
||||||
pub self_targeting: bool,
|
|
||||||
pub cd: Cooldown,
|
pub cd: Cooldown,
|
||||||
// used for Uon client
|
// used for Uon client
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
@ -56,7 +55,6 @@ impl ConstructSkill {
|
|||||||
pub fn new(skill: Skill) -> ConstructSkill {
|
pub fn new(skill: Skill) -> ConstructSkill {
|
||||||
ConstructSkill {
|
ConstructSkill {
|
||||||
skill,
|
skill,
|
||||||
self_targeting: skill.self_targeting(),
|
|
||||||
cd: skill.base_cd(),
|
cd: skill.base_cd(),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ use account;
|
|||||||
use account::Account;
|
use account::Account;
|
||||||
use game;
|
use game;
|
||||||
use instance;
|
use instance;
|
||||||
|
use names;
|
||||||
|
|
||||||
use pg::{Db, PgPool};
|
use pg::{Db, PgPool};
|
||||||
use rpc::RpcMessage;
|
use rpc::RpcMessage;
|
||||||
@ -54,6 +55,9 @@ pub enum Event {
|
|||||||
|
|
||||||
// client events
|
// client events
|
||||||
Queue(Id),
|
Queue(Id),
|
||||||
|
Invite(Id),
|
||||||
|
Join(Id, String),
|
||||||
|
Joined(Id),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WsClient {
|
struct WsClient {
|
||||||
@ -62,6 +66,7 @@ struct WsClient {
|
|||||||
tx: Sender<RpcMessage>,
|
tx: Sender<RpcMessage>,
|
||||||
subs: HashSet<Uuid>,
|
subs: HashSet<Uuid>,
|
||||||
pvp: bool,
|
pvp: bool,
|
||||||
|
invite: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Events {
|
impl Events {
|
||||||
@ -115,7 +120,7 @@ impl Events {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let client = WsClient { id, tx, account: account_id, subs: HashSet::new(), pvp: false };
|
let client = WsClient { id, tx, account: account_id, subs: HashSet::new(), pvp: false, invite: None };
|
||||||
self.clients.insert(id, client);
|
self.clients.insert(id, client);
|
||||||
|
|
||||||
info!("clients={:?}", self.clients.len());
|
info!("clients={:?}", self.clients.len());
|
||||||
@ -223,6 +228,59 @@ impl Events {
|
|||||||
info!("joined game queue id={:?} account={:?}", requester.id, requester.account);
|
info!("joined game queue id={:?} account={:?}", requester.id, requester.account);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Event::Invite(id) => {
|
||||||
|
// check whether request is valid
|
||||||
|
let c = self.clients.get_mut(&id)
|
||||||
|
.ok_or(format_err!("connection not found id={:?}", id))?;
|
||||||
|
|
||||||
|
if let None = c.account {
|
||||||
|
return Err(err_msg("cannot join pvp queue anonymously"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let code = names::name().split_whitespace().collect::<Vec<&str>>().join("-");
|
||||||
|
info!("pvp invite request id={:?} account={:?} code={:?}", c.id, c.account, code);
|
||||||
|
c.invite = Some(code.clone());
|
||||||
|
c.tx.send(RpcMessage::Invite(code))?;
|
||||||
|
return Ok(());
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::Join(id, code) => {
|
||||||
|
// check whether request is valid
|
||||||
|
let c = self.clients.get(&id)
|
||||||
|
.ok_or(format_err!("connection not found id={:?}", id))?;
|
||||||
|
|
||||||
|
if let None = c.account {
|
||||||
|
return Err(err_msg("cannot join pvp queue anonymously"));
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("pvp join request id={:?} account={:?} code={:?}", c.id, c.account, code);
|
||||||
|
|
||||||
|
let inv = self.clients.iter()
|
||||||
|
.filter(|(_id, c)| c.invite.is_some())
|
||||||
|
.find(|(_id, c)| match c.invite {
|
||||||
|
Some(ref c) => *c == code,
|
||||||
|
None => false,
|
||||||
|
})
|
||||||
|
.map(|(_id, c)| PvpRequest { id: c.id, account: c.account.unwrap(), tx: c.tx.clone() })
|
||||||
|
.ok_or(format_err!("invite not found code={:?}", code))?;
|
||||||
|
|
||||||
|
let join = PvpRequest { id: c.id, account: c.account.unwrap(), tx: c.tx.clone() };
|
||||||
|
|
||||||
|
self.warden.send(GameEvent::Match((join, inv)))?;
|
||||||
|
return Ok(());
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::Joined(id) => {
|
||||||
|
// check whether request is valid
|
||||||
|
let c = self.clients.get_mut(&id)
|
||||||
|
.ok_or(format_err!("connection not found id={:?}", id))?;
|
||||||
|
|
||||||
|
c.pvp = false;
|
||||||
|
c.invite = None;
|
||||||
|
return Ok(());
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -236,7 +236,7 @@ impl Game {
|
|||||||
target = find_target();
|
target = find_target();
|
||||||
}
|
}
|
||||||
|
|
||||||
pve_skills.push((mobs.id, mob.id, Some(target.id), s));
|
pve_skills.push((mobs.id, mob.id, target.id, s));
|
||||||
},
|
},
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
@ -258,7 +258,7 @@ impl Game {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_skill(&mut self, player_id: Uuid, source_construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill) -> Result<&mut Game, Error> {
|
fn add_skill(&mut self, player_id: Uuid, source_construct_id: Uuid, target_construct_id: Uuid, skill: Skill) -> Result<&mut Game, Error> {
|
||||||
// check player in game
|
// check player in game
|
||||||
self.player_by_id(player_id)?;
|
self.player_by_id(player_id)?;
|
||||||
|
|
||||||
@ -266,17 +266,9 @@ impl Game {
|
|||||||
return Err(err_msg("game not in skill phase"));
|
return Err(err_msg("game not in skill phase"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_target_id = match skill.self_targeting() {
|
|
||||||
true => source_construct_id,
|
|
||||||
false => match target_construct_id {
|
|
||||||
Some(t) => t,
|
|
||||||
None => return Err(err_msg("skill requires a target")),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// target checks
|
// target checks
|
||||||
{
|
{
|
||||||
let target = match self.construct_by_id(final_target_id) {
|
let target = match self.construct_by_id(target_construct_id) {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
None => return Err(err_msg("target construct not in game")),
|
None => return Err(err_msg("target construct not in game")),
|
||||||
};
|
};
|
||||||
@ -318,7 +310,7 @@ impl Game {
|
|||||||
self.stack.remove(s);
|
self.stack.remove(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
let skill = Cast::new(source_construct_id, player_id, final_target_id, skill);
|
let skill = Cast::new(source_construct_id, player_id, target_construct_id, skill);
|
||||||
self.stack.push(skill);
|
self.stack.push(skill);
|
||||||
|
|
||||||
return Ok(self);
|
return Ok(self);
|
||||||
@ -887,7 +879,7 @@ fn game_json_file_write(g: &Game) -> Result<String, Error> {
|
|||||||
Ok(dest)
|
Ok(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill) -> Result<Game, Error> {
|
pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, construct_id: Uuid, target_construct_id: Uuid, skill: Skill) -> Result<Game, Error> {
|
||||||
let mut game = game_get(tx, game_id)?;
|
let mut game = game_get(tx, game_id)?;
|
||||||
|
|
||||||
game.add_skill(account.id, construct_id, target_construct_id, skill)?;
|
game.add_skill(account.id, construct_id, target_construct_id, skill)?;
|
||||||
@ -1039,8 +1031,8 @@ mod tests {
|
|||||||
let x_construct = x_player.constructs[0].clone();
|
let x_construct = x_player.constructs[0].clone();
|
||||||
let y_construct = y_player.constructs[0].clone();
|
let y_construct = y_player.constructs[0].clone();
|
||||||
|
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Attack).unwrap();
|
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
@ -1068,8 +1060,8 @@ mod tests {
|
|||||||
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
||||||
}
|
}
|
||||||
|
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Stun).unwrap();
|
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Stun).unwrap();
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
@ -1105,8 +1097,8 @@ mod tests {
|
|||||||
// remove all mitigation
|
// remove all mitigation
|
||||||
game.player_by_id(x_player.id).unwrap().construct_by_id(x_construct.id).unwrap().red_life.force(0);
|
game.player_by_id(x_player.id).unwrap().construct_by_id(x_construct.id).unwrap().red_life.force(0);
|
||||||
|
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Stun).unwrap();
|
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Stun).unwrap();
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
@ -1135,8 +1127,8 @@ mod tests {
|
|||||||
assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Stun).is_some());
|
assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Stun).is_some());
|
||||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Block).is_none());
|
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Block).is_none());
|
||||||
|
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Attack).unwrap();
|
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
@ -1149,8 +1141,8 @@ mod tests {
|
|||||||
|
|
||||||
// second round
|
// second round
|
||||||
// now we block and it should go back on cd
|
// now we block and it should go back on cd
|
||||||
// game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Stun).unwrap();
|
// game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Stun).unwrap();
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
@ -1179,8 +1171,8 @@ mod tests {
|
|||||||
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
||||||
}
|
}
|
||||||
|
|
||||||
game.add_skill(x_player.id, x_construct.id, None, Skill::Counter).unwrap();
|
game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Counter).unwrap();
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Stun).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Stun).unwrap();
|
||||||
|
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
@ -1214,14 +1206,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply buff
|
// apply buff
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(x_construct.id), Skill::Electrify).unwrap();
|
game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Electrify).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
assert!(game.construct_by_id(x_construct.id).unwrap().affected(Effect::Electric));
|
assert!(game.construct_by_id(x_construct.id).unwrap().affected(Effect::Electric));
|
||||||
|
|
||||||
// attack and receive debuff
|
// attack and receive debuff
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
@ -1246,7 +1238,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply buff
|
// apply buff
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Link).unwrap();
|
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Link).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
@ -1265,7 +1257,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// attack and receive link hit
|
// attack and receive link hit
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
@ -1296,14 +1288,14 @@ mod tests {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// // apply buff
|
// // apply buff
|
||||||
// game.add_skill(x_player.id, x_construct.id, Some(x_construct.id), Skill::Absorb).unwrap();
|
// game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Absorb).unwrap();
|
||||||
// game.player_ready(x_player.id).unwrap();
|
// game.player_ready(x_player.id).unwrap();
|
||||||
// game.player_ready(y_player.id).unwrap();
|
// game.player_ready(y_player.id).unwrap();
|
||||||
// game = game.resolve_phase_start();
|
// game = game.resolve_phase_start();
|
||||||
// assert!(game.construct_by_id(x_construct.id).unwrap().affected(Effect::Absorb));
|
// assert!(game.construct_by_id(x_construct.id).unwrap().affected(Effect::Absorb));
|
||||||
|
|
||||||
// // attack and receive debuff
|
// // attack and receive debuff
|
||||||
// game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::TestAttack).unwrap();
|
// game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::TestAttack).unwrap();
|
||||||
// game.player_ready(x_player.id).unwrap();
|
// game.player_ready(x_player.id).unwrap();
|
||||||
// game.player_ready(y_player.id).unwrap();
|
// game.player_ready(y_player.id).unwrap();
|
||||||
// game = game.resolve_phase_start();
|
// game = game.resolve_phase_start();
|
||||||
@ -1330,10 +1322,10 @@ mod tests {
|
|||||||
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
||||||
}
|
}
|
||||||
|
|
||||||
game.add_skill(i_player.id, i_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Ruin).unwrap();
|
game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Ruin).unwrap();
|
||||||
game.add_skill(x_player.id, y_construct.id, Some(i_construct.id), Skill::Attack).unwrap();
|
game.add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(i_player.id).unwrap();
|
game.player_ready(i_player.id).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
@ -1380,10 +1372,10 @@ mod tests {
|
|||||||
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
|
||||||
}
|
}
|
||||||
|
|
||||||
game.add_skill(i_player.id, i_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Intercept).unwrap();
|
game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Intercept).unwrap();
|
||||||
game.add_skill(x_player.id, y_construct.id, Some(i_construct.id), Skill::Attack).unwrap();
|
game.add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap();
|
||||||
|
|
||||||
game.player_ready(i_player.id).unwrap();
|
game.player_ready(i_player.id).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
@ -1411,10 +1403,10 @@ mod tests {
|
|||||||
let x_construct = x_player.constructs[0].clone();
|
let x_construct = x_player.constructs[0].clone();
|
||||||
let y_construct = x_player.constructs[1].clone();
|
let y_construct = x_player.constructs[1].clone();
|
||||||
|
|
||||||
game.add_skill(i_player.id, i_construct.id, Some(x_construct.id), Skill::Attack).unwrap()
|
game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap()
|
||||||
.add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap()
|
.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap()
|
||||||
.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Attack).unwrap()
|
.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Attack).unwrap()
|
||||||
.add_skill(x_player.id, y_construct.id, Some(i_construct.id), Skill::Attack).unwrap()
|
.add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap()
|
||||||
.player_ready(i_player.id).unwrap()
|
.player_ready(i_player.id).unwrap()
|
||||||
.player_ready(x_player.id).unwrap();
|
.player_ready(x_player.id).unwrap();
|
||||||
|
|
||||||
@ -1430,10 +1422,10 @@ mod tests {
|
|||||||
assert!(game.player_by_id(x_player.id).unwrap().skills_required() == 2);
|
assert!(game.player_by_id(x_player.id).unwrap().skills_required() == 2);
|
||||||
|
|
||||||
// add some more skills
|
// add some more skills
|
||||||
game.add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap();
|
game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(j_construct.id), Skill::Attack).unwrap();
|
game.add_skill(x_player.id, x_construct.id, j_construct.id, Skill::Attack).unwrap();
|
||||||
game.add_skill(x_player.id, y_construct.id, Some(j_construct.id), Skill::Attack).unwrap();
|
game.add_skill(x_player.id, y_construct.id, j_construct.id, Skill::Attack).unwrap();
|
||||||
assert!(game.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Attack).is_err());
|
assert!(game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Attack).is_err());
|
||||||
|
|
||||||
game.player_ready(i_player.id).unwrap();
|
game.player_ready(i_player.id).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
@ -1475,7 +1467,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply buff
|
// apply buff
|
||||||
game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Decay).unwrap();
|
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Decay).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
@ -1490,7 +1482,7 @@ mod tests {
|
|||||||
game.resolved.clear();
|
game.resolved.clear();
|
||||||
|
|
||||||
// remove
|
// remove
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(y_construct.id), Skill::Purify).unwrap();
|
game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
@ -1503,14 +1495,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
game.add_skill(y_player.id, x_construct.id, Some(y_construct.id), Skill::Siphon).unwrap();
|
game.add_skill(y_player.id, x_construct.id, y_construct.id, Skill::Siphon).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
|
|
||||||
game.resolved.clear();
|
game.resolved.clear();
|
||||||
|
|
||||||
game.add_skill(y_player.id, y_construct.id, Some(y_construct.id), Skill::Purify).unwrap();
|
game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap();
|
||||||
game.player_ready(x_player.id).unwrap();
|
game.player_ready(x_player.id).unwrap();
|
||||||
game.player_ready(y_player.id).unwrap();
|
game.player_ready(y_player.id).unwrap();
|
||||||
game = game.resolve_phase_start();
|
game = game.resolve_phase_start();
|
||||||
|
|||||||
@ -117,7 +117,7 @@ pub fn shapes_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
(ConstructShapes::Circle, 10),
|
(ConstructShapes::Circle, 10),
|
||||||
(ConstructShapes::Line, 10),
|
(ConstructShapes::Line, 10),
|
||||||
(ConstructShapes::V, 10),
|
(ConstructShapes::V, 10),
|
||||||
// (ConstructShapes::Tri, 3),
|
(ConstructShapes::Tri, 10),
|
||||||
// (ConstructShapes::Plus, 5),
|
// (ConstructShapes::Plus, 5),
|
||||||
(ConstructShapes::Blank, 1),
|
(ConstructShapes::Blank, 1),
|
||||||
];
|
];
|
||||||
@ -155,6 +155,9 @@ pub fn shapes_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
let size = rng.gen_range(20.0, 50.0);
|
let size = rng.gen_range(20.0, 50.0);
|
||||||
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
||||||
fill = colour, x = size / 2.0, y = size / 2.0, width = size, height = size, x_t = x_translate, y_t = y_translate, rotation = rotation)?;
|
fill = colour, x = size / 2.0, y = size / 2.0, width = size, height = size, x_t = x_translate, y_t = y_translate, rotation = rotation)?;
|
||||||
|
if scalar == 0.0 && rng.gen_bool(0.5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
||||||
fill = colour, x = size / 2.0, y = size / 2.0, width = size, height = size, x_t = -x_translate, y_t = -y_translate, rotation = rotation)?;
|
fill = colour, x = size / 2.0, y = size / 2.0, width = size, height = size, x_t = -x_translate, y_t = -y_translate, rotation = rotation)?;
|
||||||
},
|
},
|
||||||
@ -163,6 +166,9 @@ pub fn shapes_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
let b = rng.gen_range(20.0, 50.0);
|
let b = rng.gen_range(20.0, 50.0);
|
||||||
write!(&mut svg, "<polygon fill=\"{fill}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
write!(&mut svg, "<polygon fill=\"{fill}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
||||||
fill = colour, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?;
|
fill = colour, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?;
|
||||||
|
if scalar == 0.0 && rng.gen_bool(0.5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
write!(&mut svg, "<polygon fill=\"{fill}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
write!(&mut svg, "<polygon fill=\"{fill}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
||||||
fill = colour, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation + 180, x_translate = -x_translate, y_translate = -y_translate)?;
|
fill = colour, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation + 180, x_translate = -x_translate, y_translate = -y_translate)?;
|
||||||
},
|
},
|
||||||
@ -178,6 +184,9 @@ pub fn shapes_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
let height = rng.gen_range(20.0, 50.0);
|
let height = rng.gen_range(20.0, 50.0);
|
||||||
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
||||||
fill = colour, x = width / 2.0, y = height / 2.0, width = width, height = height, x_t = x_translate, y_t = y_translate, rotation = rotation)?;
|
fill = colour, x = width / 2.0, y = height / 2.0, width = width, height = height, x_t = x_translate, y_t = y_translate, rotation = rotation)?;
|
||||||
|
if scalar == 0.0 && rng.gen_bool(0.5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
write!(&mut svg, "<rect fill=\"{fill}\" x=\"-{x}\" y=\"-{y}\" width=\"{width}\" height=\"{height}\" transform=\"translate({x_t}, {y_t}) rotate({rotation})\" />",
|
||||||
fill = colour, x = width / 2.0, y = height / 2.0, width = width, height = height, x_t = -x_translate, y_t = -y_translate, rotation = rotation)?;
|
fill = colour, x = width / 2.0, y = height / 2.0, width = width, height = height, x_t = -x_translate, y_t = -y_translate, rotation = rotation)?;
|
||||||
},
|
},
|
||||||
@ -188,11 +197,30 @@ pub fn shapes_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
|
|
||||||
write!(&mut svg, "<polyline fill=\"none\" stroke=\"{fill}\" stroke-width=\"{width}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
write!(&mut svg, "<polyline fill=\"none\" stroke=\"{fill}\" stroke-width=\"{width}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
||||||
fill = colour, width = width, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?;
|
fill = colour, width = width, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?;
|
||||||
|
if scalar == 0.0 && rng.gen_bool(0.5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
write!(&mut svg, "<polyline fill=\"none\" stroke=\"{fill}\" stroke-width=\"{width}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
write!(&mut svg, "<polyline fill=\"none\" stroke=\"{fill}\" stroke-width=\"{width}\" x=\"{x}\" y=\"{y}\" points=\"{x0} {y0}, {x1} {y1}, {x2} {y2}\" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
||||||
fill = colour, width = width, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation + 180, x_translate = -x_translate, y_translate = -y_translate)?;
|
fill = colour, width = width, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation + 180, x_translate = -x_translate, y_translate = -y_translate)?;
|
||||||
},
|
},
|
||||||
ConstructShapes::Tri => {
|
ConstructShapes::Tri => {
|
||||||
|
let width = rng.gen_range(2.0, 4.0);
|
||||||
|
let length = rng.gen_range(12.5, 25.0);
|
||||||
|
|
||||||
|
let x0 = (0.0 as f64).cos() * length;
|
||||||
|
let y0 = (0.0 as f64).sin() * length;
|
||||||
|
let x1 = ((f64::consts::PI * 2.0) / 3.0).cos() * length;
|
||||||
|
let y1 = ((f64::consts::PI * 2.0) / 3.0).sin() * length;
|
||||||
|
let x2 = ((f64::consts::PI * 4.0) / 3.0).cos() * length;
|
||||||
|
let y2 = ((f64::consts::PI * 4.0) / 3.0).sin() * length;
|
||||||
|
|
||||||
|
write!(&mut svg, "<path stroke=\"{fill}\" stroke-width=\"{width}\" d=\"M{x0} {y0}L 0 0 M{x1} {y1}L 0 0 M{x2} {y2}L 0 0 \" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
||||||
|
fill = colour, width = width, x0 = x0, y0 = y0, x1 = x1, y1 = y1, x2 = x2, y2 = y2, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?;
|
||||||
|
if scalar == 0.0 && rng.gen_bool(0.5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
write!(&mut svg, "<path stroke=\"{fill}\" stroke-width=\"{width}\" d=\"M{x0} {y0}L 0 0 M{x1} {y1}L 0 0 M{x2} {y2}L 0 0 \" transform=\"translate({x_translate}, {y_translate}) rotate({rotation})\" />",
|
||||||
|
fill = colour, width = width, x0 = x0, y0 = y0, x1 = x1, y1 = y1, x2 = x2, y2 = y2, rotation = rotation, x_translate = -x_translate, y_translate = -y_translate)?;
|
||||||
},
|
},
|
||||||
ConstructShapes::Plus => {
|
ConstructShapes::Plus => {
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,10 @@ pub enum RpcMessage {
|
|||||||
QueueJoined(()),
|
QueueJoined(()),
|
||||||
QueueCancelled(()),
|
QueueCancelled(()),
|
||||||
|
|
||||||
|
InviteRequested(()),
|
||||||
|
Invite(String),
|
||||||
|
Joining(()),
|
||||||
|
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +82,7 @@ pub enum RpcRequest {
|
|||||||
|
|
||||||
GameState { id: Uuid },
|
GameState { id: Uuid },
|
||||||
GameReady { id: Uuid },
|
GameReady { id: Uuid },
|
||||||
GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill },
|
GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Uuid, skill: Skill },
|
||||||
GameSkillClear { game_id: Uuid },
|
GameSkillClear { game_id: Uuid },
|
||||||
|
|
||||||
AccountState {},
|
AccountState {},
|
||||||
@ -91,6 +95,8 @@ pub enum RpcRequest {
|
|||||||
SubscriptionState {},
|
SubscriptionState {},
|
||||||
EmailState {},
|
EmailState {},
|
||||||
|
|
||||||
|
InstanceInvite {},
|
||||||
|
InstanceJoin { code: String },
|
||||||
InstanceQueue {},
|
InstanceQueue {},
|
||||||
InstancePractice {},
|
InstancePractice {},
|
||||||
InstanceAbandon { instance_id: Uuid },
|
InstanceAbandon { instance_id: Uuid },
|
||||||
@ -136,21 +142,27 @@ impl Connection {
|
|||||||
None => return Err(err_msg("auth required")),
|
None => return Err(err_msg("auth required")),
|
||||||
};
|
};
|
||||||
|
|
||||||
// evented but authorization required
|
|
||||||
match v {
|
|
||||||
RpcRequest::InstanceQueue {} => {
|
|
||||||
self.events.send(Event::Queue(self.id))?;
|
|
||||||
return Ok(RpcMessage::QueueRequested(()));
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
// all good, let's make a tx and process
|
|
||||||
let mut tx = db.transaction()?;
|
|
||||||
|
|
||||||
let request = v.clone();
|
let request = v.clone();
|
||||||
|
|
||||||
let response = match v {
|
let response = match v {
|
||||||
|
// evented but authorization required
|
||||||
|
RpcRequest::InstanceQueue {} => {
|
||||||
|
self.events.send(Event::Queue(self.id))?;
|
||||||
|
Ok(RpcMessage::QueueRequested(()))
|
||||||
|
},
|
||||||
|
RpcRequest::InstanceInvite {} => {
|
||||||
|
self.events.send(Event::Invite(self.id))?;
|
||||||
|
Ok(RpcMessage::InviteRequested(()))
|
||||||
|
},
|
||||||
|
RpcRequest::InstanceJoin { code } => {
|
||||||
|
self.events.send(Event::Join(self.id, code))?;
|
||||||
|
Ok(RpcMessage::Joining(()))
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// all good, let's make a tx and process
|
||||||
|
let mut tx = db.transaction()?;
|
||||||
|
|
||||||
|
let res = match v {
|
||||||
RpcRequest::AccountState {} =>
|
RpcRequest::AccountState {} =>
|
||||||
Ok(RpcMessage::AccountState(account.clone())),
|
Ok(RpcMessage::AccountState(account.clone())),
|
||||||
RpcRequest::AccountConstructs {} =>
|
RpcRequest::AccountConstructs {} =>
|
||||||
@ -228,6 +240,9 @@ impl Connection {
|
|||||||
};
|
};
|
||||||
|
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
info!("request={:?} account={:?} duration={:?}", request, account.name, begin.elapsed());
|
info!("request={:?} account={:?} duration={:?}", request, account.name, begin.elapsed());
|
||||||
|
|
||||||
|
|||||||
@ -1213,20 +1213,6 @@ impl Skill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn self_targeting(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Skill::Block |
|
|
||||||
Skill::Sustain|
|
|
||||||
Skill::SustainPlus |
|
|
||||||
Skill::SustainPlusPlus |
|
|
||||||
Skill::Counter|
|
|
||||||
Skill::CounterPlus |
|
|
||||||
Skill::CounterPlusPlus => true,
|
|
||||||
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn defensive(&self) -> bool {
|
pub fn defensive(&self) -> bool {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
|||||||
@ -90,6 +90,10 @@ impl Warden {
|
|||||||
fn on_match(&mut self, pair: Pair) -> Result<(), Error> {
|
fn on_match(&mut self, pair: Pair) -> Result<(), Error> {
|
||||||
info!("received pair={:?}", pair);
|
info!("received pair={:?}", pair);
|
||||||
|
|
||||||
|
// clear pvp status
|
||||||
|
self.events.send(Event::Joined(pair.0.id))?;
|
||||||
|
self.events.send(Event::Joined(pair.1.id))?;
|
||||||
|
|
||||||
let db = self.pool.get()?;
|
let db = self.pool.get()?;
|
||||||
let mut tx = db.transaction()?;
|
let mut tx = db.transaction()?;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user