firecore_battle/host/
moves.rs1use core::{cmp::Reverse, hash::Hash};
2use rand::Rng;
3use std::collections::BTreeMap;
4
5use pokedex::{
6 moves::{Priority},
7 pokemon::{
8 stat::{BaseStat, StatType},
9 },
10};
11
12use crate::{
13 moves::BattleMove,
14 pokemon::{Indexed, PokemonIdentifier},
15};
16
17use super::{collections::BattleMap, party::BattleParty, player::BattlePlayer};
18
19#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub enum MovePriority<ID: Ord> {
21 First(ID, usize),
22 Second(Reverse<Priority>, Reverse<BaseStat>, Option<u16>),
23}
24
25pub fn move_queue<ID: Clone + Ord + Hash, R: Rng, T>(
26 players: &mut BattleMap<ID, BattlePlayer<ID, T>>,
27 random: &mut R,
28) -> Vec<Indexed<ID, BattleMove<ID>>> {
29 let mut queue = BTreeMap::new();
30
31 for mut player in players.values_mut() {
32 queue_player(&mut queue, &mut player.party, random)
33 }
34
35 queue.into_values().collect()
36}
37
38fn queue_player<ID: Clone + Ord, R: Rng, T>(
39 queue: &mut BTreeMap<MovePriority<ID>, Indexed<ID, BattleMove<ID>>>,
40 party: &mut BattleParty<ID, T>,
41 random: &mut R,
42) {
43 for index in 0..party.active.len() {
44 if let Some(pokemon) = party.active.get_mut(index).and_then(Option::as_mut) {
45 if let Some(action) = pokemon.queued_move.take() {
46 if let Some(instance) = party.active(index) {
47 let pokemon = PokemonIdentifier(party.id().clone(), index);
48
49 let mut priority = match action {
50 BattleMove::Move(index, ..) => MovePriority::Second(
51 Reverse(
52 instance
53 .moves
54 .get(index)
55 .map(|i| i.0.priority)
56 .unwrap_or_default(),
57 ),
58 Reverse(instance.stat(StatType::Speed)),
59 None,
60 ),
61 _ => MovePriority::First(party.id().clone(), index),
62 };
63
64 fn tie_break<ID: Ord, R: Rng>(
65 queue: &mut BTreeMap<MovePriority<ID>, Indexed<ID, BattleMove<ID>>>,
66 random: &mut R,
67 priority: &mut MovePriority<ID>,
68 ) {
69 if let MovePriority::Second(.., shift) = priority {
70 *shift = Some(random.gen());
71 }
72 if queue.contains_key(priority) {
73 tie_break(queue, random, priority);
74 }
75 }
76
77 if queue.contains_key(&priority) {
78 tie_break(queue, random, &mut priority);
79 }
80
81 queue.insert(priority, Indexed(pokemon, action));
82 }
83 }
84 }
85 }
86}