diff --git a/client/src/components/game.ctrl.jsx b/client/src/components/game.ctrl.jsx
index f251770a..a1a1675c 100644
--- a/client/src/components/game.ctrl.jsx
+++ b/client/src/components/game.ctrl.jsx
@@ -27,8 +27,13 @@ const addState = connect(
return ws.sendGameSkillClear(game.id);
}
+ function sendAbandon() {
+ return ws.sendInstanceAbandon(game.instance);
+ }
+
return {
game,
+ sendAbandon,
sendGameSkillClear,
sendReady,
account,
@@ -51,6 +56,7 @@ const addState = connect(
function Controls(args) {
const {
account,
+ sendAbandon,
game,
animating,
sendGameSkillClear,
@@ -104,7 +110,7 @@ function Controls(args) {
{game.phase === 'Finish' ? quitBtn : readyBtn}
-
+
);
diff --git a/client/src/components/instance.ctrl.jsx b/client/src/components/instance.ctrl.jsx
index 47324fa9..ba179c1a 100644
--- a/client/src/components/instance.ctrl.jsx
+++ b/client/src/components/instance.ctrl.jsx
@@ -20,7 +20,12 @@ const addState = connect(
return false;
}
+ function sendAbandon() {
+ return ws.sendInstanceAbandon(instance.id);
+ }
+
return {
+ sendAbandon,
instance,
sendReady,
account,
@@ -41,6 +46,7 @@ const addState = connect(
function Controls(args) {
const {
account,
+ sendAbandon,
instance,
sendReady,
leave,
@@ -77,13 +83,18 @@ function Controls(args) {
);
+ const ready = instance.phase !== 'Finished'
+ ?
+ :
+
+
return (
);
diff --git a/client/src/components/player.box.jsx b/client/src/components/player.box.jsx
index 62184f3f..df2e8b21 100644
--- a/client/src/components/player.box.jsx
+++ b/client/src/components/player.box.jsx
@@ -2,11 +2,11 @@ const preact = require('preact');
function Scoreboard(args) {
const {
+ abandon,
isPlayer,
player,
isGame,
clear,
- leave,
} = args;
let scoreText = () => {
@@ -41,7 +41,7 @@ function Scoreboard(args) {
{(isPlayer && isGame) ? : null}
- {leave ? : null}
+ {abandon ? : null}
);
diff --git a/client/src/socket.jsx b/client/src/socket.jsx
index a2ab9217..4ac30163 100644
--- a/client/src/socket.jsx
+++ b/client/src/socket.jsx
@@ -130,6 +130,10 @@ function createSocket(events) {
send(['InstanceReady', { instance_id: instanceId }]);
}
+ function sendInstanceAbandon(instanceId) {
+ send(['InstanceAbandon', { instance_id: instanceId }]);
+ }
+
function sendMtxApply(constructId, mtx, name) {
send(['MtxConstructApply', { construct_id: constructId, mtx, name }]);
if (mtx === 'Rename') {
@@ -205,7 +209,7 @@ function createSocket(events) {
let pongTimeout;
function onPong() {
events.setPing(Date.now() - ping);
- // pongTimeout = setTimeout(sendPing, 1000);
+ pongTimeout = setTimeout(sendPing, 10000);
}
// -------------
@@ -324,6 +328,7 @@ function createSocket(events) {
sendGameSkillClear,
sendGameTarget,
+ sendInstanceAbandon,
sendInstanceReady,
sendInstancePractice,
sendInstanceQueue,
diff --git a/server/src/instance.rs b/server/src/instance.rs
index 92812673..9abf3aca 100644
--- a/server/src/instance.rs
+++ b/server/src/instance.rs
@@ -316,10 +316,6 @@ impl Instance {
}
fn finish_condition(&mut self) -> bool {
- if self.rounds.len() < 4 {
- return false;
- }
-
// tennis
for player in self.players.iter() {
if player.score == Score::Win {
@@ -327,6 +323,10 @@ impl Instance {
return true;
}
}
+ // Game defaults to lose otherwise
+ if self.rounds.len() < 4 {
+ return false;
+ }
// both players afk
if self.players.iter().all(|p| p.score == Score::Zero) {
@@ -458,6 +458,13 @@ impl Instance {
.ok_or(err_msg("account not in instance"))
}
+ fn account_opponent(&mut self, account: Uuid) -> Result<&mut Player, Error> {
+ self.players
+ .iter_mut()
+ .find(|p| p.id != account)
+ .ok_or(err_msg("opponent not in instance"))
+ }
+
pub fn vbox_action_allowed(&self, account: Uuid) -> Result<(), Error> {
if self.players.iter().find(|p| p.id == account).is_none() {
return Err(err_msg("player not in this instance"));
@@ -739,6 +746,14 @@ pub fn pvp(tx: &mut Transaction, a: &Account, b: &Account) -> Result Result {
+ let mut instance = instance_get(tx, instance_id)?;
+ instance.account_player(account.id)?.set_lose();
+ instance.account_opponent(account.id)?.set_win();
+ instance.next_round();
+
+ Ok(RpcMessage::InstanceState(instance_update(tx, instance)?))
+}
pub fn instance_ready(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result {
let mut instance = instance_get(tx, instance_id)?;
diff --git a/server/src/player.rs b/server/src/player.rs
index 5f6b3259..f5711200 100644
--- a/server/src/player.rs
+++ b/server/src/player.rs
@@ -99,6 +99,16 @@ impl Player {
self
}
+ pub fn set_win(&mut self) -> &mut Player {
+ self.score = Score::Win;
+ self
+ }
+
+ pub fn set_lose(&mut self) -> &mut Player {
+ self.score = Score::Lose;
+ self
+ }
+
pub fn construct_get(&mut self, id: Uuid) -> Result<&mut Construct, Error> {
self.constructs.iter_mut().find(|c| c.id == id).ok_or(err_msg("construct not found"))
}
diff --git a/server/src/rpc.rs b/server/src/rpc.rs
index d8ce6405..09b9cdfd 100644
--- a/server/src/rpc.rs
+++ b/server/src/rpc.rs
@@ -21,7 +21,7 @@ use account;
use construct::{Construct};
use events::{Event};
use game::{Game, game_state, game_skill, game_skill_clear, game_ready};
-use instance::{Instance, instance_state, instance_practice, instance_ready};
+use instance::{Instance, instance_state, instance_practice, instance_ready, instance_abandon};
use item::{Item, ItemInfoCtr, item_info};
use mtx;
use mail;
@@ -88,6 +88,7 @@ enum RpcRequest {
InstanceQueue {},
InstancePractice {},
+ InstanceAbandon { instance_id: Uuid },
InstanceReady { instance_id: Uuid },
InstanceState { instance_id: Uuid },
@@ -184,6 +185,8 @@ impl Connection {
Ok(instance_ready(&mut tx, account, instance_id)?),
RpcRequest::InstanceState { instance_id } =>
Ok(instance_state(&mut tx, instance_id)?),
+ RpcRequest::InstanceAbandon { instance_id } =>
+ Ok(instance_abandon(&mut tx, account, instance_id)?),
RpcRequest::VboxAccept { instance_id, group, index } =>
Ok(RpcMessage::InstanceState(vbox_accept(&mut tx, account, instance_id, group, index)?)),