Added deck search and more hotkeys🔍

This commit is contained in:
Seoxi Ryouko
2025-02-28 06:24:45 -06:00
parent be5a969600
commit 67057773ae
5 changed files with 149 additions and 20 deletions

View File

@ -5,12 +5,14 @@ specifically designed to be used when players share a deck
definitely not a shameless untap clone
# todo
+ Add drag-and-drop from hand and piles
+ Add hotkeys for every zone (Almost done!)
+ Add hotkeys for every zone (*Really* almost done!)
+ ~~Add untap all hotkey~~
+ Add viewing top of deck
+ ~~Add searching deck~~
+ Add score values (usable for life counters)
+ Make events visible
# maybe todo
+ Add drag-and-drop from hand and piles
+ Make deck information, piles, and score info json-configurable
+ Use cookies instead of hardcoded url uuid

View File

@ -58,6 +58,9 @@ enum Event {
Unkill(Uuid, bool),
TransferDeadCard(Uuid, bool),
UntapAll(Player),
ViewDeck(Player),
Yoink(Player),
YoinkMill(Uuid),
}
#[derive(Serialize, Clone, Debug)]
@ -168,6 +171,32 @@ pub fn draw(game_state: &mut GameState, count: usize, player: Player) {
);
}
pub fn yoink(game_state: &mut GameState, deck_index: usize, player: Player) {
let player_hand = match player {
Player::A => &mut game_state.hands[0],
_ => &mut game_state.hands[1],
};
game_state.events.push(CountedEvent {
id: game_state.events.len(),
event: Event::Yoink(player.clone()),
});
player_hand.cards.push(game_state.deck.remove(deck_index).unwrap());
}
pub fn yoink_mill(game_state: &mut GameState, deck_index: usize, shadow: bool) {
let card = game_state.deck.remove(deck_index).unwrap();
game_state.events.push(CountedEvent {
id: game_state.events.len(),
event: Event::YoinkMill(card.clone()),
});
if shadow {
game_state.shadow_realm.push(card);
} else {
game_state.discard_pile.push(card);
}
}
pub fn shuffle(game_state: &mut GameState, player: Player) {
game_state.events.push(CountedEvent {
id: game_state.events.len(),
@ -384,3 +413,15 @@ pub fn untap_all(game_state: &mut GameState, player: Player) {
}
}
}
pub fn get_deck(game_state: &mut GameState, player: Player) -> String {
game_state.events.push(CountedEvent {
id: game_state.events.len(),
event: Event::ViewDeck(player),
});
let deck_copy = game_state.deck.clone();
//let copy_slice = deck_copy.make_contiguous();
//copy_slice.sort();
/*let final_card_list = copy_slice.into_iter().map(|card| card.braced().to_string()).collect::<Vec<String>>();*/
serde_json::to_string(&deck_copy).unwrap()
}

View File

@ -26,7 +26,7 @@ fn get_events(game_state_arc: &State<ArcMutexGameState>) -> String {
format!("{}", game::get_events(&game_state))
}
#[post("/<uuid>/shuffle")]
#[get("/<uuid>/shuffle")]
fn shuffle(
uuid: Uuid,
game_state_arc: &State<ArcMutexGameState>,
@ -247,6 +247,57 @@ fn unshadow(
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/yoink/<index>")]
fn yoink(
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::yoink(&mut game_state, index, player.clone());
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/yoink_mill/<index>")]
fn yoink_mill(
uuid: Uuid,
index: usize,
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::yoink_mill(&mut game_state, index, false);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/yoink_xmill/<index>")]
fn yoink_xmill(
uuid: Uuid,
index: usize,
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::yoink_mill(&mut game_state, index, true);
Ok(format!("{}", game::get_events(&game_state)))
}
#[get("/<uuid>/undiscard/<index>")]
fn undiscard(
uuid: Uuid,
@ -316,6 +367,24 @@ fn get_state(
))
}
#[get("/<uuid>/get_deck")]
fn get_deck(
uuid: Uuid,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap();
let player = match player_uuids.map.get(&uuid) {
Some(player) => player,
None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
};
Ok(format!(
"{}",
game::get_deck(&mut game_state, player.clone())
))
}
#[get("/<uuid>/untap_all")]
fn untap_all(
uuid: Uuid,
@ -427,7 +496,7 @@ struct PlayerUuids {
#[launch]
fn rocket() -> _ {
let mut game_state = game::new();
let game_state = game::new();
//game::draw(&mut game_state, 7, Player::A);
//game::draw(&mut game_state, 7, Player::B);
let game_state_arc = Arc::new(Mutex::new(game_state));
@ -482,6 +551,10 @@ fn rocket() -> _ {
undiscard,
remember,
untap_all,
get_deck,
yoink,
yoink_mill,
yoink_xmill,
],
)
.manage(ArcMutexGameState {

View File

@ -26,7 +26,7 @@
</aside>
<aside id="piles">
<div class="pile" id="deck">
<img src="./card_back.png" alt="" id="deck" />
<img src="./card_back.png" alt="" id="deck-img" />
<span id="deck-count"></span>
</div>
<div class="pile" id="discard-pile">

View File

@ -11,7 +11,6 @@
const $view-card-container = document.query-selector '#view-card-container'
const $param = document.query-selector '#param'
const $play = document.query-selector '#play'
window.$play = 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'
@ -19,6 +18,7 @@
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-img = document.query-selector '#deck-img'
const $deck-count = document.query-selector '#deck-count'
const $extra = document.query-selector '#extra'
const [push-param, pop-param] = (->
@ -82,7 +82,7 @@
$view-card.style.opacity = 1
e.target.add-event-listener \mouseleave hide-card$
state = await get-state!
const apply-state$ = ->
const apply-state$ = ->>
{ player-state } = it
gen-opponent-cards$ player-state.opponent_cards_in_hand
if document.body.class-list.contains \my-turn
@ -109,7 +109,8 @@
| \discard => player-state.discard_pile
| \shadow => player-state.shadow_realm
| \deck => gen-array-of state.player-state.deck_size, null
| _ => (console.log that) || []
| \deck-revealed => await fetch-log \./get_deck .then (.json!)
| _ => (console.error that) || []
open-list list, $extra.get-attribute \data-pile-type
if player-state.hand.length != $own-hand.children.length
$own-hand.innerHTML = ''
@ -212,8 +213,11 @@
$play.add-event-listener \dragover (.prevent-default!)
$discard-pile-img.add-event-listener \click -> open-list state.player-state.discard_pile, \discard
$discard-pile-count.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
$shadow-realm-count.add-event-listener \click -> open-list state.player-state.shadow_realm, \shadow
$deck-img.add-event-listener \click -> open-list (gen-array-of state.player-state.deck_size, null), \deck
$deck-count.add-event-listener \click -> open-list (gen-array-of state.player-state.deck_size, null), \deck
set-interval (->>
const new-state = await get-state!
@ -234,8 +238,12 @@
..add-event-listener \keyup ->
$current-mouse-node = [...document.query-selector-all \:hover][* - 1]
switch it.key.to-lower-case!
| \v =>
fetch-log \./shuffle
if $extra.has-attribute \data-pile-type and \deck-revealed == $extra.get-attribute \data-pile-type
$extra.class-list.add \hidden
| \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
| \t =>
if $current-mouse-node?.has-attribute \data-hand-index
@ -256,6 +264,8 @@
switch $current-mouse-node.get-attribute \data-list-type
| \discard
fetch-log "./unkill/#{$current-mouse-node.get-attribute \data-index}"
| \deck , \deck-revealed
return # will add play button
| \shadow
fetch-log "./unbanish/#{$current-mouse-node.get-attribute \data-index}"
$current-mouse-node.parent-element.remove-child $current-mouse-node
@ -269,8 +279,8 @@
switch $current-mouse-node.get-attribute \data-list-type
| \discard
fetch-log "./undiscard/#{$current-mouse-node.get-attribute \data-index}"
| \deck
void #fetch-log "./unshadow/#{$current-mouse-node.get-attribute \data-index}"
| \deck , \deck-revealed
fetch-log "./yoink/#{$current-mouse-node.get-attribute \data-index}"
| \shadow
fetch-log "./remember/#{$current-mouse-node.get-attribute \data-index}"
$current-mouse-node.parent-element.remove-child $current-mouse-node
@ -285,11 +295,11 @@
else if $current-mouse-node?.has-attribute \data-list-type
switch $current-mouse-node.get-attribute \data-list-type
| \discard
return #fetch-log "./unkill/#{$current-mouse-node.get-attribute \data-index}"
| \deck
void #fetch-log "./unkill/#{$current-mouse-node.get-attribute \data-index}"
return
| \deck , \deck-revealed
fetch-log "./yoink_mill/#{$current-mouse-node.get-attribute \data-index}"
| \shadow
fetch-log "./unshadow/#{$current-mouse-node.get-attribute \data-index}"
fetch-log "./undiscard/#{$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
@ -303,10 +313,10 @@
switch $current-mouse-node.get-attribute \data-list-type
| \discard
fetch-log "./shadow/#{$current-mouse-node.get-attribute \data-index}"
| \deck
void #fetch-log "./unbanish/#{$current-mouse-node.get-attribute \data-index}"
| \deck , \deck-revealed
fetch-log "./yoink_xmill/#{$current-mouse-node.get-attribute \data-index}"
| \shadow
return #fetch-log "./unshadow/#{$current-mouse-node.get-attribute \data-index}"
return
$current-mouse-node.parent-element.remove-child $current-mouse-node
if !$extra.child-element-count
$extra.class-list.add \hidden
@ -315,10 +325,13 @@
$extra.class-list.add \hidden
$extra.remove-attribute \data-pile-type
| \x =>
console.log
if it.shift-key || state.player-state.turn_player == state.player-state.you
fetch-log \./untap_all
[...$play.children]
.filter -> \true == it.get-attribute \data-owned
.for-each -> it.set-attribute \data-tapped false
| \f =>
fetch-log \./get_deck .then ->>
const deck = await it.json!
open-list deck, \deck-revealed
)!