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 definitely not a shameless untap clone
# todo # todo
+ Add drag-and-drop from hand and piles + Add hotkeys for every zone (*Really* almost done!)
+ Add hotkeys for every zone (Almost done!)
+ ~~Add untap all hotkey~~ + ~~Add untap all hotkey~~
+ Add viewing top of deck + Add viewing top of deck
+ ~~Add searching deck~~
+ Add score values (usable for life counters) + Add score values (usable for life counters)
+ Make events visible
# maybe todo # maybe todo
+ Add drag-and-drop from hand and piles
+ Make deck information, piles, and score info json-configurable + Make deck information, piles, and score info json-configurable
+ Use cookies instead of hardcoded url uuid + Use cookies instead of hardcoded url uuid

View File

@ -58,6 +58,9 @@ enum Event {
Unkill(Uuid, bool), Unkill(Uuid, bool),
TransferDeadCard(Uuid, bool), TransferDeadCard(Uuid, bool),
UntapAll(Player), UntapAll(Player),
ViewDeck(Player),
Yoink(Player),
YoinkMill(Uuid),
} }
#[derive(Serialize, Clone, Debug)] #[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) { pub fn shuffle(game_state: &mut GameState, player: Player) {
game_state.events.push(CountedEvent { game_state.events.push(CountedEvent {
id: game_state.events.len(), 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)) format!("{}", game::get_events(&game_state))
} }
#[post("/<uuid>/shuffle")] #[get("/<uuid>/shuffle")]
fn shuffle( fn shuffle(
uuid: Uuid, uuid: Uuid,
game_state_arc: &State<ArcMutexGameState>, game_state_arc: &State<ArcMutexGameState>,
@ -247,6 +247,57 @@ fn unshadow(
Ok(format!("{}", game::get_events(&game_state))) 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>")] #[get("/<uuid>/undiscard/<index>")]
fn undiscard( fn undiscard(
uuid: Uuid, 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")] #[get("/<uuid>/untap_all")]
fn untap_all( fn untap_all(
uuid: Uuid, uuid: Uuid,
@ -427,7 +496,7 @@ struct PlayerUuids {
#[launch] #[launch]
fn rocket() -> _ { 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::A);
//game::draw(&mut game_state, 7, Player::B); //game::draw(&mut game_state, 7, Player::B);
let game_state_arc = Arc::new(Mutex::new(game_state)); let game_state_arc = Arc::new(Mutex::new(game_state));
@ -482,6 +551,10 @@ fn rocket() -> _ {
undiscard, undiscard,
remember, remember,
untap_all, untap_all,
get_deck,
yoink,
yoink_mill,
yoink_xmill,
], ],
) )
.manage(ArcMutexGameState { .manage(ArcMutexGameState {

View File

@ -26,7 +26,7 @@
</aside> </aside>
<aside id="piles"> <aside id="piles">
<div class="pile" id="deck"> <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> <span id="deck-count"></span>
</div> </div>
<div class="pile" id="discard-pile"> <div class="pile" id="discard-pile">

View File

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