2023-04-15 17:33:29 +00:00
|
|
|
use anyhow::Result;
|
2022-06-19 10:07:54 +00:00
|
|
|
use std::ops::Deref;
|
2022-06-14 17:11:24 +00:00
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
use num_traits::abs;
|
|
|
|
|
|
|
|
use crate::dynamic_data::Battle;
|
|
|
|
use crate::dynamic_data::Pokemon;
|
|
|
|
use crate::static_data::MoveTarget;
|
2023-04-16 17:57:21 +00:00
|
|
|
use crate::VecExt;
|
2022-06-19 19:34:08 +00:00
|
|
|
|
2023-04-16 17:57:21 +00:00
|
|
|
/// Helper type for the vector of targ ets we will return.
|
2023-06-22 13:43:41 +00:00
|
|
|
pub type TargetList = Vec<Option<Pokemon>>;
|
2022-06-14 17:11:24 +00:00
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
/// This returns all Pokemon in the battle.
|
2022-08-26 16:23:35 +00:00
|
|
|
fn get_all_targets(battle: &Battle) -> TargetList {
|
2022-06-16 15:59:33 +00:00
|
|
|
let mut v = Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
2022-06-14 17:11:24 +00:00
|
|
|
for side in battle.sides() {
|
2022-06-19 10:07:54 +00:00
|
|
|
for pokemon in side.pokemon().deref() {
|
2022-06-14 17:11:24 +00:00
|
|
|
v.push(pokemon.as_ref().cloned());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v
|
|
|
|
}
|
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
/// Little helper function to get the other side. 1 --> 0, 0 --> 1
|
2022-06-14 17:11:24 +00:00
|
|
|
fn get_opposite_side(side: u8) -> u8 {
|
|
|
|
if side == 0 {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
/// Gets all Pokemon that are adjacent to of directly opposite of a Pokemon. This means the target,
|
|
|
|
/// the Pokemon left of it, the Pokemon right of it, and the Pokemon opposite of it.
|
2022-08-26 16:23:35 +00:00
|
|
|
fn get_all_adjacent_opponent(side: u8, index: u8, battle: &Battle) -> TargetList {
|
2022-06-14 17:11:24 +00:00
|
|
|
let left = index as i32 - 1;
|
|
|
|
let right = index + 1;
|
|
|
|
if left < 0 && right >= battle.pokemon_per_side() {
|
|
|
|
return vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
2022-06-16 15:59:33 +00:00
|
|
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
2022-06-14 17:11:24 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
if left >= 0 {
|
|
|
|
return if right < battle.pokemon_per_side() {
|
|
|
|
vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
2022-07-01 15:07:22 +00:00
|
|
|
battle
|
|
|
|
.get_pokemon(get_opposite_side(side), left as u8)
|
|
|
|
.as_ref()
|
|
|
|
.cloned(),
|
2022-06-16 15:59:33 +00:00
|
|
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
2022-07-01 15:07:22 +00:00
|
|
|
battle.get_pokemon(get_opposite_side(side), right).as_ref().cloned(),
|
2022-06-14 17:11:24 +00:00
|
|
|
]
|
|
|
|
} else {
|
|
|
|
vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
2022-06-16 15:59:33 +00:00
|
|
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
2022-07-01 15:07:22 +00:00
|
|
|
battle
|
|
|
|
.get_pokemon(get_opposite_side(side), left as u8)
|
|
|
|
.as_ref()
|
|
|
|
.cloned(),
|
2022-06-14 17:11:24 +00:00
|
|
|
]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
2022-06-16 15:59:33 +00:00
|
|
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
2022-07-01 15:07:22 +00:00
|
|
|
battle.get_pokemon(get_opposite_side(side), right).as_ref().cloned(),
|
2022-06-14 17:11:24 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the Pokemon to the
|
2022-06-19 19:34:08 +00:00
|
|
|
/// left of it, and the Pokemon to the right of it.
|
2022-08-26 16:23:35 +00:00
|
|
|
fn get_all_adjacent(side: u8, index: u8, battle: &Battle) -> TargetList {
|
2022-06-14 17:11:24 +00:00
|
|
|
let left = index as i32 - 1;
|
|
|
|
let right = index + 1;
|
|
|
|
if left < 0 && right >= battle.pokemon_per_side() {
|
|
|
|
return vec![battle.get_pokemon(side, index).as_ref().cloned()];
|
|
|
|
}
|
|
|
|
if left >= 0 {
|
|
|
|
if right < battle.pokemon_per_side() {
|
|
|
|
return vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
vec![
|
|
|
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
|
|
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
/// Gets the target for a specific move target type, given the targeted position.
|
2023-04-15 17:33:29 +00:00
|
|
|
pub fn resolve_targets(side: u8, index: u8, target: MoveTarget, battle: &Battle) -> Result<TargetList> {
|
|
|
|
Ok(match target {
|
2022-06-19 19:34:08 +00:00
|
|
|
// These all resolve to a single position. We let the client deal with where the target is,
|
|
|
|
// and just return the Pokemon at that given target here.
|
2022-06-14 17:11:24 +00:00
|
|
|
MoveTarget::Adjacent
|
|
|
|
| MoveTarget::AdjacentAlly
|
|
|
|
| MoveTarget::AdjacentAllySelf
|
|
|
|
| MoveTarget::AdjacentOpponent
|
|
|
|
| MoveTarget::Any
|
|
|
|
| MoveTarget::RandomOpponent
|
|
|
|
| MoveTarget::SelfUse => {
|
|
|
|
vec![battle.get_pokemon(side, index).as_ref().cloned()]
|
|
|
|
}
|
2022-06-19 19:34:08 +00:00
|
|
|
// If all pokemon are requested, give all Pokemon on the battlefield
|
2022-06-14 17:11:24 +00:00
|
|
|
MoveTarget::All => get_all_targets(battle),
|
2022-06-19 19:34:08 +00:00
|
|
|
// If the adjacent Pokemon are requested, pass those.
|
2022-06-14 17:11:24 +00:00
|
|
|
MoveTarget::AllAdjacent => get_all_adjacent(side, index, battle),
|
2022-06-19 19:34:08 +00:00
|
|
|
// If the adjacent and opponent Pokemon are requested, give those.
|
2022-06-14 17:11:24 +00:00
|
|
|
MoveTarget::AllAdjacentOpponent => get_all_adjacent_opponent(side, index, battle),
|
2022-06-19 19:34:08 +00:00
|
|
|
// If all Pokemon on a side are requested, simply give all Pokemon on the side back, and let
|
|
|
|
// the client deal with what side is passed.
|
2022-06-14 17:11:24 +00:00
|
|
|
MoveTarget::AllAlly | MoveTarget::AllOpponent => {
|
|
|
|
let mut v = Vec::new();
|
2023-04-16 17:57:21 +00:00
|
|
|
for pokemon in battle.sides().get_res(side as usize)?.pokemon().deref() {
|
2022-06-14 17:11:24 +00:00
|
|
|
v.push(pokemon.as_ref().cloned());
|
|
|
|
}
|
|
|
|
v
|
|
|
|
}
|
2023-04-15 17:33:29 +00:00
|
|
|
})
|
2022-06-14 17:11:24 +00:00
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// Checks whether a given side and index are valid for a given move target and user.
|
2022-06-14 17:11:24 +00:00
|
|
|
pub fn is_valid_target(side: u8, index: u8, target: MoveTarget, user: &Pokemon) -> bool {
|
|
|
|
// If the user is not on the field, nothing is a valid target
|
2023-04-15 12:34:42 +00:00
|
|
|
let user_side = match user.get_battle_side_index() {
|
|
|
|
Some(side) => side,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
let user_index = match user.get_battle_index() {
|
|
|
|
Some(index) => index,
|
|
|
|
None => return false,
|
|
|
|
};
|
2022-06-14 17:11:24 +00:00
|
|
|
|
|
|
|
match target {
|
|
|
|
MoveTarget::Adjacent | MoveTarget::AllAdjacent => {
|
2023-04-15 12:34:42 +00:00
|
|
|
let diff = abs(index as i32 - user_index as i32);
|
2022-06-14 17:11:24 +00:00
|
|
|
if diff == 0 {
|
2023-04-15 12:34:42 +00:00
|
|
|
return user_side != side;
|
2022-06-14 17:11:24 +00:00
|
|
|
}
|
|
|
|
diff <= 1
|
|
|
|
}
|
|
|
|
MoveTarget::AdjacentAlly => {
|
2023-04-15 12:34:42 +00:00
|
|
|
if user_side != side {
|
2022-06-14 17:11:24 +00:00
|
|
|
false
|
|
|
|
} else {
|
2023-04-15 12:34:42 +00:00
|
|
|
abs(index as i32 - user_index as i32) == 1
|
2022-06-14 17:11:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MoveTarget::AdjacentAllySelf => {
|
2023-04-15 12:34:42 +00:00
|
|
|
if user_side != side {
|
2022-06-14 17:11:24 +00:00
|
|
|
false
|
|
|
|
} else {
|
2023-04-15 12:34:42 +00:00
|
|
|
abs(index as i32 - user_index as i32) <= 1
|
2022-06-14 17:11:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MoveTarget::AdjacentOpponent | MoveTarget::AllAdjacentOpponent => {
|
2023-04-15 12:34:42 +00:00
|
|
|
if user_side == side {
|
2022-06-14 17:11:24 +00:00
|
|
|
false
|
|
|
|
} else {
|
2023-04-15 12:34:42 +00:00
|
|
|
abs(index as i32 - user_index as i32) <= 1
|
2022-06-14 17:11:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MoveTarget::All | MoveTarget::Any | MoveTarget::RandomOpponent => true,
|
2023-04-15 12:34:42 +00:00
|
|
|
MoveTarget::AllAlly => user_side == side,
|
|
|
|
MoveTarget::AllOpponent => user_side != side,
|
|
|
|
MoveTarget::SelfUse => user_side == side && user_index == index,
|
2022-06-14 17:11:24 +00:00
|
|
|
}
|
|
|
|
}
|