2026-02-13 08:16:41 -08:00
|
|
|
use log::{debug, info, trace};
|
2026-02-08 23:47:57 -08:00
|
|
|
use spacetimedb::{ReducerContext, Table, ViewContext, reducer, view};
|
|
|
|
|
|
2026-02-11 10:14:02 -08:00
|
|
|
use crate::tables::{player::player, *};
|
2026-02-08 23:47:57 -08:00
|
|
|
use jong_types::*;
|
|
|
|
|
|
|
|
|
|
pub fn deal_hands(ctx: &ReducerContext, lobby_id: u32) {
|
|
|
|
|
let players = ctx.db.player().lobby_id().filter(lobby_id);
|
|
|
|
|
let bots = ctx.db.bot().lobby_id().filter(lobby_id);
|
|
|
|
|
|
|
|
|
|
let mut wall = ctx.db.wall().lobby_id().find(lobby_id).unwrap();
|
|
|
|
|
|
|
|
|
|
// FIXME rectify deal orders
|
|
|
|
|
for mut player in players {
|
|
|
|
|
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
|
|
|
|
|
wall = ctx.db.wall().lobby_id().update(wall);
|
2026-02-12 17:06:28 -08:00
|
|
|
tiles.sort_by_key(|t| t.tile);
|
2026-02-11 10:16:21 -08:00
|
|
|
player.hand = tiles;
|
2026-02-08 23:47:57 -08:00
|
|
|
ctx.db.player().id().update(player);
|
|
|
|
|
}
|
|
|
|
|
for mut bot in bots {
|
|
|
|
|
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
|
|
|
|
|
wall = ctx.db.wall().lobby_id().update(wall);
|
2026-02-12 17:06:28 -08:00
|
|
|
tiles.sort_by_key(|t| t.tile);
|
2026-02-11 10:16:21 -08:00
|
|
|
bot.hand = tiles;
|
2026-02-08 23:47:57 -08:00
|
|
|
ctx.db.bot().id().update(bot);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-13 06:10:09 -08:00
|
|
|
#[reducer]
|
|
|
|
|
pub fn draw_tile(ctx: &ReducerContext) {
|
|
|
|
|
let mut player = ctx.db.player().identity().find(ctx.sender).unwrap();
|
|
|
|
|
let mut wall = ctx.db.wall().lobby_id().find(player.lobby_id).unwrap();
|
|
|
|
|
|
|
|
|
|
// TODO if no more tiles, exhaust somehow
|
|
|
|
|
|
|
|
|
|
player.drawn_tile = wall.tiles.pop();
|
|
|
|
|
|
|
|
|
|
ctx.db.wall().lobby_id().update(wall);
|
|
|
|
|
ctx.db.player().id().update(player);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-13 08:16:41 -08:00
|
|
|
// TODO make sure this can't be called or just error here?
|
|
|
|
|
#[reducer]
|
|
|
|
|
pub fn discard_tile(ctx: &ReducerContext, tile_id: u32) -> Result<(), String> {
|
|
|
|
|
let mut player = ctx.db.player().identity().find(ctx.sender).unwrap();
|
|
|
|
|
let mut lobby = ctx.db.lobby().id().find(player.lobby_id).unwrap();
|
|
|
|
|
|
|
|
|
|
let dealt_tile = if let Some(drawn) = player.drawn_tile
|
|
|
|
|
&& drawn.id == tile_id
|
|
|
|
|
{
|
|
|
|
|
drawn
|
|
|
|
|
} else if let Some((i, _)) = player
|
|
|
|
|
.hand
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.find(|(_, t)| t.id == tile_id)
|
|
|
|
|
{
|
|
|
|
|
player.hand.remove(i)
|
|
|
|
|
} else {
|
|
|
|
|
return Err(format!(
|
|
|
|
|
"player {} attempted to deal nonexistant tile {}",
|
|
|
|
|
player.id, tile_id
|
|
|
|
|
));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
player.pond.push(dealt_tile);
|
|
|
|
|
player.drawn_tile = None;
|
|
|
|
|
lobby.turn_state = TurnState::RonChiiPonKan;
|
|
|
|
|
|
|
|
|
|
let player = ctx.db.player().id().update(player);
|
|
|
|
|
ctx.db.lobby().id().update(lobby);
|
|
|
|
|
|
|
|
|
|
debug!("player {} discarded tile {:?}", player.id, dealt_tile.tile);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[reducer]
|
|
|
|
|
pub fn skip_call(ctx: &ReducerContext) {
|
|
|
|
|
trace!("skip_call");
|
|
|
|
|
|
|
|
|
|
let mut player = ctx.db.player().identity().find(ctx.sender).unwrap();
|
|
|
|
|
let mut lobby = ctx.db.lobby().id().find(player.lobby_id).unwrap();
|
|
|
|
|
|
|
|
|
|
lobby.turn_state = TurnState::Tsumo;
|
|
|
|
|
lobby.current_idx += 1;
|
|
|
|
|
if lobby.current_idx >= 3 {
|
|
|
|
|
lobby.current_idx = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME where better can this go
|
|
|
|
|
bot_moves(ctx, &mut lobby);
|
|
|
|
|
|
|
|
|
|
ctx.db.player().id().update(player);
|
|
|
|
|
ctx.db.lobby().id().update(lobby);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn bot_moves(ctx: &ReducerContext, lobby: &mut Lobby) {
|
|
|
|
|
let mut wall = ctx.db.wall().lobby_id().find(lobby.id).unwrap();
|
|
|
|
|
if let Some(PlayerOrBot::Bot { id }) = lobby.players.get(lobby.current_idx as usize + 1) {
|
|
|
|
|
let mut bot = ctx.db.bot().id().find(id).unwrap();
|
|
|
|
|
bot.pond.push(wall.tiles.pop().unwrap());
|
|
|
|
|
ctx.db.bot().id().update(bot);
|
|
|
|
|
lobby.turn_state = TurnState::RonChiiPonKan;
|
|
|
|
|
} else {
|
|
|
|
|
lobby.turn_state = TurnState::Tsumo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lobby.current_idx += 1;
|
|
|
|
|
if lobby.current_idx >= 3 {
|
|
|
|
|
lobby.current_idx = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 10:16:21 -08:00
|
|
|
// #[view(name = view_player_hand, public)]
|
|
|
|
|
// pub fn view_player_hand(ctx: &ViewContext) -> Option<Hand> {
|
|
|
|
|
// ctx.db
|
|
|
|
|
// .player()
|
|
|
|
|
// .identity()
|
|
|
|
|
// .find(ctx.sender)
|
|
|
|
|
// .map(|p| ctx.db.hand().id().find(p.hand_id))?
|
|
|
|
|
// }
|
2026-02-08 23:47:57 -08:00
|
|
|
|
|
|
|
|
// #[reducer]
|
|
|
|
|
// pub fn sort_hand(ctx: &ReducerContext) {
|
|
|
|
|
// todo!()
|
|
|
|
|
// }
|