Some more functionality for battling, check if choice is valid, implement target resolvers.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
8746f03500
commit
a33369afcc
|
@ -5,7 +5,18 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
pub enum TurnChoice<'a> {
|
pub enum TurnChoice<'a> {
|
||||||
Move {
|
Move {
|
||||||
user: &'a Pokemon<'a>,
|
user: &'a Pokemon<'a>,
|
||||||
used_move: Box<LearnedMove>,
|
used_move: Box<LearnedMove<'a>>,
|
||||||
|
target_side: u8,
|
||||||
|
target_index: u8,
|
||||||
|
},
|
||||||
|
Item {
|
||||||
|
user: &'a Pokemon<'a>,
|
||||||
|
},
|
||||||
|
Switch {
|
||||||
|
user: &'a Pokemon<'a>,
|
||||||
|
},
|
||||||
|
Flee {
|
||||||
|
user: &'a Pokemon<'a>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +24,9 @@ impl<'a> TurnChoice<'a> {
|
||||||
pub fn user(&self) -> &'a Pokemon<'a> {
|
pub fn user(&self) -> &'a Pokemon<'a> {
|
||||||
match self {
|
match self {
|
||||||
TurnChoice::Move { user, .. } => user,
|
TurnChoice::Move { user, .. } => user,
|
||||||
|
TurnChoice::Item { user, .. } => user,
|
||||||
|
TurnChoice::Switch { user, .. } => user,
|
||||||
|
TurnChoice::Flee { user, .. } => user,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
pub mod choice_queue;
|
pub mod choice_queue;
|
||||||
|
pub mod target_resolver;
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
use crate::dynamic_data::models::battle::Battle;
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::static_data::MoveTarget;
|
||||||
|
use num_traits::abs;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub type TargetList<'a> = Vec<Option<Arc<RwLock<Pokemon<'a>>>>>;
|
||||||
|
|
||||||
|
fn get_all_targets<'b>(battle: &Battle<'b>) -> TargetList<'b> {
|
||||||
|
let mut v =
|
||||||
|
Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
||||||
|
for side in battle.sides() {
|
||||||
|
for pokemon in side.pokemon() {
|
||||||
|
v.push(pokemon.as_ref().cloned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_opposite_side(side: u8) -> u8 {
|
||||||
|
if side == 0 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_all_adjacent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> TargetList<'b> {
|
||||||
|
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(),
|
||||||
|
battle
|
||||||
|
.get_pokemon(get_opposite_side(side), index)
|
||||||
|
.as_ref()
|
||||||
|
.cloned(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
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(),
|
||||||
|
battle
|
||||||
|
.get_pokemon(get_opposite_side(side), index)
|
||||||
|
.as_ref()
|
||||||
|
.cloned(),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
||||||
|
battle
|
||||||
|
.get_pokemon(get_opposite_side(side), index)
|
||||||
|
.as_ref()
|
||||||
|
.cloned(),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![
|
||||||
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||||
|
battle
|
||||||
|
.get_pokemon(get_opposite_side(side), index)
|
||||||
|
.as_ref()
|
||||||
|
.cloned(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_all_adjacent_opponent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> TargetList<'b> {
|
||||||
|
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(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_targets<'b>(
|
||||||
|
side: u8,
|
||||||
|
index: u8,
|
||||||
|
target: MoveTarget,
|
||||||
|
battle: &Battle<'b>,
|
||||||
|
) -> TargetList<'b> {
|
||||||
|
match target {
|
||||||
|
MoveTarget::Adjacent
|
||||||
|
| MoveTarget::AdjacentAlly
|
||||||
|
| MoveTarget::AdjacentAllySelf
|
||||||
|
| MoveTarget::AdjacentOpponent
|
||||||
|
| MoveTarget::Any
|
||||||
|
| MoveTarget::RandomOpponent
|
||||||
|
| MoveTarget::SelfUse => {
|
||||||
|
vec![battle.get_pokemon(side, index).as_ref().cloned()]
|
||||||
|
}
|
||||||
|
MoveTarget::All => get_all_targets(battle),
|
||||||
|
MoveTarget::AllAdjacent => get_all_adjacent(side, index, battle),
|
||||||
|
MoveTarget::AllAdjacentOpponent => get_all_adjacent_opponent(side, index, battle),
|
||||||
|
MoveTarget::AllAlly | MoveTarget::AllOpponent => {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for pokemon in battle.sides()[side as usize].pokemon() {
|
||||||
|
v.push(pokemon.as_ref().cloned());
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid_target(side: u8, index: u8, target: MoveTarget, user: &Pokemon) -> bool {
|
||||||
|
let user_side = user.get_battle_side_index();
|
||||||
|
let user_index = user.get_battle_index();
|
||||||
|
// If the user is not on the field, nothing is a valid target
|
||||||
|
if user_side.is_none() || user_index.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match target {
|
||||||
|
MoveTarget::Adjacent | MoveTarget::AllAdjacent => {
|
||||||
|
let diff = abs(index as i32 - user_index.unwrap() as i32);
|
||||||
|
if diff == 0 {
|
||||||
|
return user_side.unwrap() != side;
|
||||||
|
}
|
||||||
|
diff <= 1
|
||||||
|
}
|
||||||
|
MoveTarget::AdjacentAlly => {
|
||||||
|
if user_side.unwrap() != side {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
abs(index as i32 - user_index.unwrap() as i32) == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MoveTarget::AdjacentAllySelf => {
|
||||||
|
if user_side.unwrap() != side {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
abs(index as i32 - user_index.unwrap() as i32) <= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MoveTarget::AdjacentOpponent | MoveTarget::AllAdjacentOpponent => {
|
||||||
|
if user_side.unwrap() == side {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
abs(index as i32 - user_index.unwrap() as i32) <= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MoveTarget::All | MoveTarget::Any | MoveTarget::RandomOpponent => true,
|
||||||
|
MoveTarget::AllAlly => user_side.unwrap() == side,
|
||||||
|
MoveTarget::AllOpponent => user_side.unwrap() != side,
|
||||||
|
MoveTarget::SelfUse => user_side.unwrap() == side && user_index.unwrap() == index,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
|
use crate::dynamic_data::choices::TurnChoice;
|
||||||
use crate::dynamic_data::event_hooks::event_hook::EventHook;
|
use crate::dynamic_data::event_hooks::event_hook::EventHook;
|
||||||
use crate::dynamic_data::flow::choice_queue::ChoiceQueue;
|
use crate::dynamic_data::flow::choice_queue::ChoiceQueue;
|
||||||
|
use crate::dynamic_data::flow::target_resolver::is_valid_target;
|
||||||
use crate::dynamic_data::history::history_holder::HistoryHolder;
|
use crate::dynamic_data::history::history_holder::HistoryHolder;
|
||||||
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
||||||
use crate::dynamic_data::models::battle_party::BattleParty;
|
use crate::dynamic_data::models::battle_party::BattleParty;
|
||||||
use crate::dynamic_data::models::battle_random::BattleRandom;
|
use crate::dynamic_data::models::battle_random::BattleRandom;
|
||||||
use crate::dynamic_data::models::battle_result::BattleResult;
|
use crate::dynamic_data::models::battle_result::BattleResult;
|
||||||
use crate::dynamic_data::models::battle_side::BattleSide;
|
use crate::dynamic_data::models::battle_side::BattleSide;
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
||||||
|
@ -123,6 +126,18 @@ impl<'a> Battle<'a> {
|
||||||
&self.current_turn_queue
|
&self.current_turn_queue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_pokemon(&self, side: u8, index: u8) -> &Option<Arc<RwLock<Pokemon<'a>>>> {
|
||||||
|
let side = self.sides.get(side as usize);
|
||||||
|
if side.is_none() {
|
||||||
|
return &None;
|
||||||
|
}
|
||||||
|
let pokemon = side.unwrap().pokemon().get(index as usize);
|
||||||
|
if pokemon.is_none() {
|
||||||
|
return &None;
|
||||||
|
}
|
||||||
|
pokemon.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn can_slot_be_filled(&self, side: u8, index: u8) -> bool {
|
pub fn can_slot_be_filled(&self, side: u8, index: u8) -> bool {
|
||||||
for party in &self.parties {
|
for party in &self.parties {
|
||||||
if party.is_responsible_for_index(side, index) && party.has_pokemon_not_in_field() {
|
if party.is_responsible_for_index(side, index) && party.has_pokemon_not_in_field() {
|
||||||
|
@ -165,6 +180,34 @@ impl<'a> Battle<'a> {
|
||||||
}
|
}
|
||||||
self.has_ended = true;
|
self.has_ended = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_use(&self, choice: &TurnChoice) -> bool {
|
||||||
|
// If the user is not usable, we obviously can;t use the choice.
|
||||||
|
if !choice.user().is_usable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if let TurnChoice::Move {
|
||||||
|
used_move,
|
||||||
|
target_side,
|
||||||
|
target_index,
|
||||||
|
user,
|
||||||
|
} = choice
|
||||||
|
{
|
||||||
|
// TODO: Hook to change number of PP needed.
|
||||||
|
if used_move.remaining_pp() < 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if !is_valid_target(
|
||||||
|
*target_side,
|
||||||
|
*target_index,
|
||||||
|
used_move.move_data().target(),
|
||||||
|
user,
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VolatileScripts<'a> for Battle<'a> {
|
impl<'a> VolatileScripts<'a> for Battle<'a> {
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub struct ExecutingMove<'a, 'b> {
|
||||||
number_of_hits: u8,
|
number_of_hits: u8,
|
||||||
hits: Vec<HitData>,
|
hits: Vec<HitData>,
|
||||||
user: &'a Pokemon<'b>,
|
user: &'a Pokemon<'b>,
|
||||||
chosen_move: &'a LearnedMove,
|
chosen_move: &'a LearnedMove<'a>,
|
||||||
use_move: &'a MoveData,
|
use_move: &'a MoveData,
|
||||||
script: ScriptContainer,
|
script: ScriptContainer,
|
||||||
targets: Vec<Option<&'a Pokemon<'b>>>,
|
targets: Vec<Option<&'a Pokemon<'b>>>,
|
||||||
|
|
|
@ -1,2 +1,40 @@
|
||||||
|
use crate::static_data::MoveData;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LearnedMove {}
|
pub struct LearnedMove<'a> {
|
||||||
|
move_data: &'a MoveData,
|
||||||
|
max_pp: u8,
|
||||||
|
remaining_pp: u8,
|
||||||
|
learn_method: MoveLearnMethod,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum MoveLearnMethod {
|
||||||
|
Unknown = 0,
|
||||||
|
Level = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LearnedMove<'a> {
|
||||||
|
pub fn new(move_data: &'a MoveData, learn_method: MoveLearnMethod) -> Self {
|
||||||
|
Self {
|
||||||
|
move_data,
|
||||||
|
max_pp: move_data.base_usages(),
|
||||||
|
remaining_pp: move_data.base_usages(),
|
||||||
|
learn_method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_data(&self) -> &MoveData {
|
||||||
|
self.move_data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_pp(&self) -> u8 {
|
||||||
|
self.max_pp
|
||||||
|
}
|
||||||
|
pub fn remaining_pp(&self) -> u8 {
|
||||||
|
self.remaining_pp
|
||||||
|
}
|
||||||
|
pub fn learn_method(&self) -> MoveLearnMethod {
|
||||||
|
self.learn_method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ pub struct Pokemon<'a> {
|
||||||
|
|
||||||
battle_data: Option<PokemonBattleData<'a>>,
|
battle_data: Option<PokemonBattleData<'a>>,
|
||||||
|
|
||||||
moves: [Option<LearnedMove>; MAX_MOVES],
|
moves: [Option<LearnedMove<'a>>; MAX_MOVES],
|
||||||
allowed_experience: bool,
|
allowed_experience: bool,
|
||||||
|
|
||||||
types: Vec<u8>,
|
types: Vec<u8>,
|
||||||
|
|
|
@ -2,16 +2,16 @@ use crate::static_data::SecondaryEffect;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum MoveCategory {
|
pub enum MoveCategory {
|
||||||
Physical,
|
Physical = 0,
|
||||||
Special,
|
Special = 1,
|
||||||
Status,
|
Status = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum MoveTarget {
|
pub enum MoveTarget {
|
||||||
Adjacent,
|
Adjacent = 0,
|
||||||
AdjacentAlly,
|
AdjacentAlly,
|
||||||
AdjacentAllySelf,
|
AdjacentAllySelf,
|
||||||
AdjacentOpponent,
|
AdjacentOpponent,
|
||||||
|
@ -69,6 +69,36 @@ impl MoveData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &StringKey {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
pub fn move_type(&self) -> u8 {
|
||||||
|
self.move_type
|
||||||
|
}
|
||||||
|
pub fn category(&self) -> MoveCategory {
|
||||||
|
self.category
|
||||||
|
}
|
||||||
|
pub fn base_power(&self) -> u8 {
|
||||||
|
self.base_power
|
||||||
|
}
|
||||||
|
pub fn accuracy(&self) -> u8 {
|
||||||
|
self.accuracy
|
||||||
|
}
|
||||||
|
pub fn base_usages(&self) -> u8 {
|
||||||
|
self.base_usages
|
||||||
|
}
|
||||||
|
pub fn target(&self) -> MoveTarget {
|
||||||
|
self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn priority(&self) -> i8 {
|
||||||
|
self.priority
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn secondary_effect(&self) -> &SecondaryEffect {
|
||||||
|
&self.secondary_effect
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, key: &str) -> bool {
|
pub fn has_flag(&self, key: &str) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue