Added piles, cleaned up dragging positioning, various improvements 📈

This commit is contained in:
Seoxi Ryouko
2025-02-27 08:35:14 -06:00
parent 1f7fccb172
commit 4310d3569c
5 changed files with 379 additions and 46 deletions

View File

@ -52,6 +52,9 @@ enum Event {
PlayFromHand(Player), PlayFromHand(Player),
Bounce(Player), Bounce(Player),
Tap(Uuid), Tap(Uuid),
Discard(Player),
Kill(Uuid, bool),
Unkill(Uuid, bool),
} }
#[derive(Serialize, Clone, Debug)] #[derive(Serialize, Clone, Debug)]
@ -82,6 +85,7 @@ pub struct OnePlayerGameState {
turn_player: Player, turn_player: Player,
opponent_cards_in_hand: usize, opponent_cards_in_hand: usize,
you: Player, you: Player,
deck_size: usize,
} }
impl GameState { impl GameState {
@ -101,6 +105,7 @@ impl GameState {
_ => self.hands[0].cards.len(), _ => self.hands[0].cards.len(),
}, },
you: player, you: player,
deck_size: self.deck.len(),
} }
} }
} }
@ -237,7 +242,7 @@ pub fn play_from_hand(game_state: &mut GameState, hand_index: usize, player: Pla
play_uuid, play_uuid,
InPlay { InPlay {
id: card, id: card,
position_x: 5, position_x: 50,
position_y: 50, position_y: 50,
owner: player, owner: player,
tapped: false, tapped: false,
@ -275,3 +280,57 @@ pub fn move_played_card(game_state: &mut GameState, play_id: Uuid, position_x: u
played_card.position_y = position_y; played_card.position_y = position_y;
} }
} }
pub fn discard(game_state: &mut GameState, hand_index: usize, player: Player, shadow: bool) {
let player_hand = match player {
Player::A => &mut game_state.hands[0],
Player::B => &mut game_state.hands[1],
};
game_state.events.push(CountedEvent {
id: game_state.events.len(),
event: Event::Discard(player.clone()),
});
let card = player_hand.cards.remove(hand_index);
if shadow {
game_state.shadow_realm.push(card);
} else {
game_state.discard_pile.push(card);
}
}
pub fn kill(game_state: &mut GameState, play_id: Uuid, shadow: bool) {
let played_card = game_state.play.remove(&play_id).unwrap();
game_state.events.push(CountedEvent {
id: game_state.events.len(),
event: Event::Kill(played_card.id.clone(), shadow),
});
if shadow {
game_state.shadow_realm.push(played_card.id);
} else {
game_state.discard_pile.push(played_card.id);
}
}
pub fn unkill(game_state: &mut GameState, player: Player, pile_index: usize, shadow: bool) {
let card = if shadow {
game_state.shadow_realm.remove(pile_index)
} else {
game_state.discard_pile.remove(pile_index)
};
let play_uuid = Uuid::new_v4();
game_state.events.push(CountedEvent {
id: game_state.events.len(),
event: Event::Unkill(card, shadow),
});
game_state.play.insert(
play_uuid,
InPlay {
id: card,
position_x: 50,
position_y: 50,
owner: player,
tapped: false,
play_id: play_uuid,
},
);
}

View File

@ -4,6 +4,7 @@ mod game;
use game::GameState; use game::GameState;
use game::Player; use game::Player;
use rocket::fs::{relative, FileServer}; use rocket::fs::{relative, FileServer};
use rocket::response::content;
use rocket::response::status::BadRequest; use rocket::response::status::BadRequest;
use rocket::State; use rocket::State;
use std::collections::HashMap; use std::collections::HashMap;
@ -11,11 +12,11 @@ use std::sync::{Arc, Mutex};
use uuid::{uuid, Uuid}; use uuid::{uuid, Uuid};
#[get("/")] #[get("/")]
fn index(player_uuids: &State<PlayerUuids>) -> String { fn index(player_uuids: &State<PlayerUuids>) -> content::RawHtml<String> {
format!( content::RawHtml(format!(
"localhost:8000/{}/\nlocalhost:8000/{}/", "<a href=\"localhost:8000/{}/\">localhost:8000/{}</a><br /><a href=\"localhost:8000/{}/\">localhost:8000/{}</a>",
player_uuids.a, player_uuids.b player_uuids.a, player_uuids.a, player_uuids.b, player_uuids.b
) ))
} }
#[get("/get_events")] #[get("/get_events")]
@ -124,7 +125,108 @@ fn play(
let game_state_mutex = Arc::clone(&game_state_arc.state); let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap(); let mut game_state = game_state_mutex.lock().unwrap();
game::play_from_hand(&mut game_state, index, player.clone()); game::play_from_hand(&mut game_state, index, player.clone());
//println!("{:#?}", game_state); Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/unkill/<index>")]
fn unkill(
uuid: Uuid,
index: usize,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
let player = match player_uuids.map.get(&uuid) {
Some(player) => player,
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
game::unkill(&mut game_state, player.clone(), index, false);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/unbanish/<index>")]
fn unbanish(
uuid: Uuid,
index: usize,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
let player = match player_uuids.map.get(&uuid) {
Some(player) => player,
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
game::unkill(&mut game_state, player.clone(), index, true);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/discard/<index>")]
fn discard(
uuid: Uuid,
index: usize,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
let player = match player_uuids.map.get(&uuid) {
Some(player) => player,
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
game::discard(&mut game_state, index, player.clone(), false);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/forget/<index>")]
fn forget(
uuid: Uuid,
index: usize,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
let player = match player_uuids.map.get(&uuid) {
Some(player) => player,
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
game::discard(&mut game_state, index, player.clone(), true);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/kill/<play_id>")]
fn kill(
uuid: Uuid,
play_id: Uuid,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
match player_uuids.map.get(&uuid) {
Some(_) => (),
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
game::kill(&mut game_state, play_id, false);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/banish/<play_id>")]
fn banish(
uuid: Uuid,
play_id: Uuid,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
match player_uuids.map.get(&uuid) {
Some(_) => (),
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
game::kill(&mut game_state, play_id, true);
Ok(format!("{}", game::get_events(&game_state))) Ok(format!("{}", game::get_events(&game_state)))
} }
@ -282,6 +384,12 @@ fn rocket() -> _ {
bounce, bounce,
tap, tap,
move_card, move_card,
discard,
kill,
forget,
banish,
unkill,
unbanish
], ],
) )
.manage(ArcMutexGameState { .manage(ArcMutexGameState {

View File

@ -13,6 +13,7 @@
<div id="border"></div> <div id="border"></div>
<div id="play"></div> <div id="play"></div>
<div class="hand" id="own-hand"></div> <div class="hand" id="own-hand"></div>
<div id="extra" class="hidden"></div>
</main> </main>
<aside id="view-card-container"> <aside id="view-card-container">
<div id="param-container"> <div id="param-container">
@ -23,5 +24,19 @@
<span id="card-text"></span> <span id="card-text"></span>
</div> </div>
</aside> </aside>
<aside id="piles">
<div class="pile" id="deck">
<img src="./card_back.png" alt="" id="deck" />
<span id="deck-count"></span>
</div>
<div class="pile" id="discard-pile">
<img src="" alt="" id="discard-pile-img" />
<span id="discard-pile-count"></span>
</div>
<div class="pile" id="shadow-realm">
<img src="" alt="" id="shadow-realm-img" />
<span id="shadow-realm-count"></span>
</div>
</aside>
</body> </body>
</html> </html>

View File

@ -11,39 +11,50 @@
const $view-card-container = document.query-selector '#view-card-container' const $view-card-container = document.query-selector '#view-card-container'
const $param = document.query-selector '#param' const $param = document.query-selector '#param'
const $play = document.query-selector '#play' const $play = document.query-selector '#play'
const $discard-pile = document.query-selector '#discard-pile'
const $discard-pile-img = document.query-selector '#discard-pile-img'
const $discard-pile-count = document.query-selector '#discard-pile-count'
const $shadow-realm = document.query-selector '#shadow-realm'
const $shadow-realm-img = document.query-selector '#shadow-realm-img'
const $shadow-realm-count = document.query-selector '#shadow-realm-count'
const $deck = document.query-selector '#deck'
const $deck-count = document.query-selector '#deck-count'
const $extra = document.query-selector '#extra'
const [push-param, pop-param] = (-> const [push-param, pop-param] = (->
param = "" param = ""
clear-param-timer = 0 clear-param-timer = 0
setInterval (-> setInterval (->
clear-param-timer-- if clear-param-timer clear-param-timer-- if clear-param-timer
param := "" unless clear-param-timer param := "" unless clear-param-timer
$param.inner-text = param $param.inner-text = param && "\xa0#param\xa0"
), 100 ), 100
const push-param = -> const push-param = ->
param += it param += it
$param.inner-text = param $param.inner-text = "\xa0#param\xa0"
clear-param-timer := 20 clear-param-timer := 20
const pop-full-param = -> const pop-full-param = ->
ret = param ret = param
param := "" param := ""
$param.inner-text = param $param.inner-text = "\xa0#param\xa0"
if ret == "" if ret == ""
1 1
else else
+ret +ret
[push-param, pop-full-param] [push-param, pop-full-param]
)! )!
play-id-list = ""
const clamp = (n, v, x) -> Math.min (Math.max v, n), x const clamp = (n, v, x) -> Math.min (Math.max v, n), x
const unwrap_uuid = (.replace /^\{|\}$/g '') const unwrap_uuid = (.replace /^\{|\}$/g '')
const get-play-size = -> $play.get-bounding-client-rect! const get-play-size = -> $play.get-bounding-client-rect!
const gen-array = -> Array.from { length: it }, (_, i) -> i const gen-array = -> Array.from { length: it }, (_, i) -> i
const gen-array-of = (it, val) -> Array.from { length: it }, -> val
const cards = await fetch-log \./cards.json .then (.json!) const cards = await fetch-log \./cards.json .then (.json!)
const make-card = -> const $make-card = ->
img = document.create-element \img $img = document.create-element \img
img.src = it $img.src = it
img $img
const make-blank-card = -> make-card \./card_back.png const $make-blank-card = -> $make-card \./card_back.png
const gen-opponent-cards$ = -> const gen-opponent-cards$ = ->
diff = it - $opponent-hand.child-element-count diff = it - $opponent-hand.child-element-count
switch switch
@ -51,7 +62,7 @@
while diff++ while diff++
$opponent-hand.remove-child $opponent-hand.first-child $opponent-hand.remove-child $opponent-hand.first-child
| diff > 0 | diff > 0
$opponent-hand.append ...(gen-array diff .map make-blank-card) $opponent-hand.append ...(gen-array diff .map $make-blank-card)
| _ | _
void void
const get-state = ->> const get-state = ->>
@ -60,7 +71,6 @@
events-json = await fetch \/get_events .then (.text!) events-json = await fetch \/get_events .then (.text!)
events = JSON.parse events-json events = JSON.parse events-json
play-map = new Map player-state.play.map -> [it.id, it] play-map = new Map player-state.play.map -> [it.id, it]
play-id-list = [...player-state.play.map (.play_id)].sort!join \|
return { player-state-json, player-state, events-json, events, play-map } return { player-state-json, player-state, events-json, events, play-map }
const show-card$ = (e) -> const show-card$ = (e) ->
@ -72,17 +82,39 @@
e.target.add-event-listener \mouseleave hide-card$ e.target.add-event-listener \mouseleave hide-card$
state = await get-state! state = await get-state!
const apply-state$ = -> const apply-state$ = ->
{ player-state, play-id-list } = it { player-state } = it
gen-opponent-cards$ player-state.opponent_cards_in_hand gen-opponent-cards$ player-state.opponent_cards_in_hand
if document.body.class-list.contains \my-turn if document.body.class-list.contains \my-turn
document.body.class-list.remove \my-turn if player-state.you != player-state.turn_player document.body.class-list.remove \my-turn if player-state.you != player-state.turn_player
else else
document.body.class-list.add \my-turn if player-state.you == player-state.turn_player document.body.class-list.add \my-turn if player-state.you == player-state.turn_player
$deck-count.inner-text = player-state.deck_size
if player-state.discard_pile.length
top-id = player-state.discard_pile[* - 1]
$discard-pile-img.src = cards[top-id].jpg
$discard-pile-img.set-attribute \data-png cards[top-id].png
else
$discard-pile-img.src = ""
$discard-pile-count.inner-text = player-state.discard_pile.length
if player-state.shadow_realm.length
top-id = player-state.shadow_realm[* - 1]
$shadow-realm-img.src = cards[top-id].jpg
$shadow-realm-img.set-attribute \data-png cards[top-id].png
else
$shadow-realm-img.src = ""
$shadow-realm-count.inner-text = player-state.shadow_realm.length
if $extra.has-attribute \data-pile-type
const list = switch $extra.get-attribute \data-pile-type
| \discard => player-state.discard_pile
| \shadow => player-state.shadow_realm
| \deck => gen-array-of state.player-state.deck_size, null
| _ => (console.log that) || []
open-list list, $extra.get-attribute \data-pile-type
if player-state.hand.length != $own-hand.children.length if player-state.hand.length != $own-hand.children.length
$own-hand.innerHTML = '' $own-hand.innerHTML = ''
player-state.hand.for-each (card-id, index) -> player-state.hand.for-each (card-id, index) ->
card-data = cards[card-id] card-data = cards[card-id]
card = make-card card-data.jpg card = $make-card card-data.jpg
card card
..set-attribute \data-hand-index index ..set-attribute \data-hand-index index
..set-attribute \data-text card-data.txt ..set-attribute \data-text card-data.txt
@ -98,11 +130,10 @@
relative-y = it.position_y relative-y = it.position_y
else else
relative-y = 100 - it.position_y relative-y = 100 - it.position_y
img = make-card card-data.jpg img = $make-card card-data.jpg
img img
..class-list.add \in-play-card ..class-list.add \in-play-card
..style ..style
#..transform = 'translate(-50%, -50%)'
..left = it.position_x + \% ..left = it.position_x + \%
..top = relative-y + \% ..top = relative-y + \%
..set-attribute \data-png card-data.png ..set-attribute \data-png card-data.png
@ -111,6 +142,7 @@
..set-attribute \data-play-y relative-y ..set-attribute \data-play-y relative-y
..set-attribute \draggable \true ..set-attribute \draggable \true
..set-attribute \data-owner it.owner ..set-attribute \data-owner it.owner
..set-attribute \data-owned it.owner == player-state.you
..set-attribute \data-tapped it.tapped ..set-attribute \data-tapped it.tapped
..add-event-listener \mouseenter show-card$ ..add-event-listener \mouseenter show-card$
..add-event-listener \dragstart -> ..add-event-listener \dragstart ->
@ -139,11 +171,49 @@
else else
absolute-y = 100 - y absolute-y = 100 - y
fetch-log "./move/#{it.target.get-attribute \data-play-id}/#x/#absolute-y" fetch-log "./move/#{it.target.get-attribute \data-play-id}/#x/#absolute-y"
#it.target.style.left = new-x + \px
#it.target.style.top = new-y + \px
$play.append-child img $play.append-child img
play-id-list := next-play-id-list
else
player-state.play.for-each ->
$element = document.query-selector "[data-play-id=\"#{it.play_id}\"]"
if it.owner == player-state.you
relative-y = it.position_y
else
relative-y = 100 - it.position_y
$element.set-attribute \data-tapped it.tapped
$element.style
..left = it.position_x + \%
..top = relative-y + \%
$element.set-attribute \data-play-x it.position_x
$element.set-attribute \data-play-y relative-y
apply-state$ state apply-state$ state
const open-list = (list, list-type) -->
const $card-list = list.map (card-id, index) ->
if card-id
ret = $make-card cards[card-id].jpg
ret.set-attribute \data-png cards[card-id].png
ret.set-attribute "data-index" index
ret.set-attribute "data-list-type" list-type
ret.add-event-listener \mouseenter show-card$
ret
else
$make-blank-card!
$extra.innerHTML = ""
$card-list.for-each -> $extra.append it
$extra.set-attribute \data-pile-type list-type
$extra.class-list.remove \hidden
$discard-pile-img.add-event-listener \mouseenter show-card$
$shadow-realm-img.add-event-listener \mouseenter show-card$
$play.add-event-listener \dragover (.prevent-default!)
$discard-pile-img.add-event-listener \click -> open-list state.player-state.discard_pile, \discard
$shadow-realm-img.add-event-listener \click -> open-list state.player-state.shadow_realm, \shadow
$deck.add-event-listener \click -> open-list (gen-array-of state.player-state.deck_size, null), \deck
set-interval (->> set-interval (->>
const new-state = await get-state! const new-state = await get-state!
unless new-state.player-state-json == state.player-state-json unless new-state.player-state-json == state.player-state-json
@ -161,24 +231,51 @@
else if mouse-x < window.inner-width / 3 else if mouse-x < window.inner-width / 3
$view-card-container.class-list.add \right $view-card-container.class-list.add \right
..add-event-listener \keyup -> ..add-event-listener \keyup ->
current-mouse-node = [...document.query-selector-all \:hover][* - 1] $current-mouse-node = [...document.query-selector-all \:hover][* - 1]
switch it.key switch it.key
| \c => fetch-log "./draw/#{pop-param!}" | \c => fetch-log "./draw/#{pop-param!}"
| \e => fetch-log "./pass" | \e => fetch-log "./pass"
| \0 \1 \2 \3 \4 \5 \6 \7 \8 \9 => push-param that | \0 \1 \2 \3 \4 \5 \6 \7 \8 \9 => push-param that
| \t => | \t =>
if current-mouse-node?.has-attribute \data-hand-index if $current-mouse-node?.has-attribute \data-hand-index
fetch-log "./fade/#{current-mouse-node.get-attribute \data-hand-index}" fetch-log "./fade/#{$current-mouse-node.get-attribute \data-hand-index}"
| \y => | \y =>
if current-mouse-node?.has-attribute \data-hand-index if $current-mouse-node?.has-attribute \data-hand-index
fetch-log "./fade_bottom/#{current-mouse-node.get-attribute \data-hand-index}" fetch-log "./fade_bottom/#{$current-mouse-node.get-attribute \data-hand-index}"
| ' ' => | ' ' =>
if current-mouse-node?.has-attribute \data-hand-index if $current-mouse-node?.has-attribute \data-hand-index
fetch-log "./play/#{current-mouse-node.get-attribute \data-hand-index}" fetch-log "./play/#{$current-mouse-node.get-attribute \data-hand-index}"
else if current-mouse-node?.has-attribute \data-play-id else if $current-mouse-node?.has-attribute \data-play-id
fetch-log "./tap/#{current-mouse-node.get-attribute \data-play-id}" if \true == $current-mouse-node.get-attribute \data-tapped
$current-mouse-node.set-attribute \data-tapped \false
else
$current-mouse-node.set-attribute \data-tapped \true
fetch-log "./tap/#{$current-mouse-node.get-attribute \data-play-id}"
else if $current-mouse-node?.has-attribute \data-list-type
switch $current-mouse-node.get-attribute \data-list-type
| \discard
fetch-log "./unkill/#{$current-mouse-node.get-attribute \data-index}"
| \shadow
fetch-log "./unbanish/#{$current-mouse-node.get-attribute \data-index}"
$current-mouse-node.parent-element.remove-child $current-mouse-node
if !$extra.child-element-count
$extra.class-list.add \hidden
$extra.remove-attribute \data-pile-type
| \r => | \r =>
if current-mouse-node?.has-attribute \data-play-id if $current-mouse-node?.has-attribute \data-play-id
fetch-log "./bounce/#{current-mouse-node.get-attribute \data-play-id}" fetch-log "./bounce/#{$current-mouse-node.get-attribute \data-play-id}"
| \d =>
if $current-mouse-node?.has-attribute \data-hand-index
fetch-log "./discard/#{$current-mouse-node.get-attribute \data-hand-index}"
else if $current-mouse-node?.has-attribute \data-play-id
fetch-log "./kill/#{$current-mouse-node.get-attribute \data-play-id}"
| \s =>
if $current-mouse-node?.has-attribute \data-hand-index
fetch-log "./forget/#{$current-mouse-node.get-attribute \data-hand-index}"
else if $current-mouse-node?.has-attribute \data-play-id
fetch-log "./banish/#{$current-mouse-node.get-attribute \data-play-id}"
| \q =>
$extra.class-list.add \hidden
$extra.remove-attribute \data-pile-type
)! )!

View File

@ -1,6 +1,9 @@
@import url('/userstyle.css');
$view-container-side-offset: 5%; $view-container-side-offset: 5%;
$param-container-side-offset: 5%; $param-container-side-offset: 5%;
$img-hand-height: 95%; $img-hand-height: 95%;
/*$img-pile-width: 95%;*/
$hand-height: 14%; $hand-height: 14%;
*, *::before, *::after { *, *::before, *::after {
@ -10,6 +13,7 @@ $hand-height: 14%;
html, body, main { html, body, main {
margin: 0; margin: 0;
padding: 0; padding: 0;
background-color: #000;
} }
body { body {
@ -23,12 +27,12 @@ main {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
position: relative;
} }
.hand { .hand, #extra {
height: $hand-height; height: $hand-height;
width: 100%; width: 100%;
background-color: #0002;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
@ -40,10 +44,27 @@ main {
} }
} }
.hand {
background-color: #fff2;
}
#extra {
transition: height 0.5s;
overflow: hidden;
background-color: #222d;
}
#extra.hidden {
height: 0;
}
aside { aside {
position: absolute; position: absolute;
height: 100%; height: 100%;
top: 0; top: 0;
}
#view-card-container {
left: $view-container-side-offset; left: $view-container-side-offset;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -55,7 +76,7 @@ aside {
} }
} }
.right { #view-card-container.right {
left: initial; left: initial;
right: $view-container-side-offset; right: $view-container-side-offset;
} }
@ -73,39 +94,72 @@ aside {
#param { #param {
font-size: 2rem; font-size: 2rem;
background-color: #fffb;
border-radius: 0.5rem;
padding: 0.5rem 0;
} }
.right #param { .right #param {
text-align: right; text-align: right;
} }
#border { #piles {
display: flex;
flex-direction: column;
justify-content: center;
}
.pile {
position: relative;
height: $hand-height;
display: flex;
justify-content: center;
align-items: center;
img {
height: $img-hand-height;
}
span {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fffb;
border-radius: 0.25rem;
padding: 0.1rem;
}
}
#play::before {
content: " ";
position: absolute; position: absolute;
top: 48%; top: 48%;
bottom: 48%; bottom: 48%;
left: 0; left: 0;
right: 0; right: 0;
background-color: #f002; background-color: inherit;
} }
.my-turn #border { .my-turn #play {
background-color: #0ff2; background-color: #0ff2;
} }
#play { #play {
background-color: #f002;
flex-grow: 1; flex-grow: 1;
}
#play {
position: relative; position: relative;
} }
.in-play-card { .in-play-card {
position: absolute; position: absolute;
transition: all 0.3s; transition: transform 0.3s, top 0.3s, left 0.3s;
transform: translate(-50%, -50%) rotate(0deg);
height: calc(($img-hand-height / 100%) * ($hand-height / 100%) * 100vh); height: calc(($img-hand-height / 100%) * ($hand-height / 100%) * 100vh);
} }
[data-tapped = true] { [data-tapped = true] {
transform: rotate(90deg); transform: translate(-50%, -50%) rotate(90deg);
}
img {
border-radius: 10%;
} }