diff --git a/WORKLOG.md b/WORKLOG.md
index 298e552d..5956d1f7 100644
--- a/WORKLOG.md
+++ b/WORKLOG.md
@@ -4,8 +4,6 @@
*PRODUCTION*
* can't reset password without knowing password =\
-* ws gzip encoding
-
* concede round
* look into ruin event bug
@@ -50,7 +48,13 @@
* Graphical status effects instead of text
* theme toasts
+
* rework vecs into sets
+ * constructs
+ * effects
+ * parent
+ * children
+
* remove names so games/instances are copy
* consolidate game and instance
diff --git a/client/src/components/game.ctrl.btns.top.jsx b/client/src/components/game.ctrl.btns.top.jsx
index 55c4caa0..3128d40d 100644
--- a/client/src/components/game.ctrl.btns.top.jsx
+++ b/client/src/components/game.ctrl.btns.top.jsx
@@ -20,12 +20,17 @@ const addState = connect(
return ws.sendGameOfferDraw(game.id);
}
+ function sendConcede() {
+ return ws.sendGameConcede(game.id);
+ }
+
return {
game,
account,
sendAbandon,
sendDraw,
+ sendConcede,
animating,
};
},
@@ -49,11 +54,12 @@ function GameCtrlTopBtns(args) {
leave,
sendAbandon,
sendDraw,
+ sendConcede,
animating,
} = args;
const finished = game && game.phase === 'Finished';
- const { abandonState, drawState } = this.state;
+ const { abandonState, drawState, concedeState } = this.state;
const player = game.players.find(p => p.id === account.id);
const drawOffered = player && player.draw_offered;
@@ -70,6 +76,12 @@ function GameCtrlTopBtns(args) {
setTimeout(() => this.setState({ drawState: false }), 2000);
};
+ const concedeStateTrue = e => {
+ e.stopPropagation();
+ this.setState({ concedeState: true });
+ setTimeout(() => this.setState({ concedeState: false }), 2000);
+ };
+
const abandonClasses = `abandon ${abandonState ? 'confirming' : ''}`;
const abandonText = abandonState ? 'Confirm' : 'Abandon';
const abandonAction = abandonState ? sendAbandon : abandonStateTrue;
@@ -83,9 +95,15 @@ function GameCtrlTopBtns(args) {
const drawAction = drawState ? sendDraw : drawStateTrue;
const drawBtn = ;
+ const concedeClasses = `draw ${concedeState ? 'confirming' : ''}`;
+ const concedeText = concedeState ? 'Round' : 'Concede';
+ const concedeAction = concedeState ? sendConcede : concedeStateTrue;
+ const concedeBtn = ;
+
return (
{abandonBtn}
+ {concedeBtn}
{drawBtn}
);
diff --git a/client/src/socket.jsx b/client/src/socket.jsx
index 959bfc30..f36d23f6 100644
--- a/client/src/socket.jsx
+++ b/client/src/socket.jsx
@@ -138,6 +138,11 @@ function createSocket(events) {
events.setActiveSkill(null);
}
+ function sendGameConcede(gameId) {
+ send(['GameConcede', { game_id: gameId }]);
+ events.setActiveSkill(null);
+ }
+
function sendGameTarget(gameId, constructId, skillId) {
send(['GameTarget', { game_id: gameId, construct_id: constructId, skill_id: skillId }]);
events.setActiveSkill(null);
@@ -391,6 +396,7 @@ function createSocket(events) {
sendGameSkill,
sendGameSkillClear,
sendGameOfferDraw,
+ sendGameConcede,
sendGameTarget,
sendInstanceAbandon,
diff --git a/server/src/game.rs b/server/src/game.rs
index 86fed074..ddc701e4 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -349,6 +349,18 @@ impl Game {
return Ok(self);
}
+ fn concede(mut self, player_id: Uuid) -> Result {
+ if self.phase != Phase::Skill {
+ return Err(err_msg("game not in skill phase"));
+ }
+
+ self.player_by_id(player_id)?
+ .forfeit();
+
+ return Ok(self.finish());
+ }
+
+
fn clear_skill(&mut self, player_id: Uuid) -> Result<&mut Game, Error> {
self.player_by_id(player_id)?;
if self.phase != Phase::Skill {
@@ -940,6 +952,16 @@ pub fn game_offer_draw(tx: &mut Transaction, account: &Account, game_id: Uuid) -
Ok(game)
}
+pub fn game_concede(tx: &mut Transaction, account: &Account, game_id: Uuid) -> Result {
+ let game = game_get(tx, game_id)?
+ .concede(account.id)?;
+
+ game_update(tx, &game)?;
+
+ Ok(game)
+}
+
+
pub fn game_skill_clear(tx: &mut Transaction, account: &Account, game_id: Uuid) -> Result {
let mut game = game_get(tx, game_id)?;
diff --git a/server/src/rpc.rs b/server/src/rpc.rs
index 948a07f4..1dc1e037 100644
--- a/server/src/rpc.rs
+++ b/server/src/rpc.rs
@@ -22,7 +22,7 @@ use account::{Account};
use account;
use construct::{Construct};
use events::{Event};
-use game::{Game, game_state, game_skill, game_skill_clear, game_ready, game_offer_draw};
+use game::{Game, game_state, game_skill, game_skill_clear, game_ready, game_offer_draw, game_concede};
use instance::{Instance, ChatState, instance_state, instance_practice, instance_ready, instance_abandon, demo};
use item::{Item, ItemInfoCtr, item_info};
use mtx;
@@ -92,6 +92,7 @@ pub enum RpcRequest {
GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Uuid, skill: Skill },
GameSkillClear { game_id: Uuid },
GameOfferDraw { game_id: Uuid },
+ GameConcede { game_id: Uuid },
AccountState {},
AccountShop {},
@@ -227,6 +228,9 @@ impl Connection {
RpcRequest::GameReady { id } =>
Ok(RpcMessage::GameState(game_ready(&mut tx, account, id)?)),
+ RpcRequest::GameConcede { game_id } =>
+ Ok(RpcMessage::GameState(game_concede(&mut tx, account, game_id)?)),
+
RpcRequest::GameOfferDraw { game_id } =>
Ok(RpcMessage::GameState(game_offer_draw(&mut tx, account, game_id)?)),