use alloc::string::String;
use battler_data::Id;
use hashbrown::HashMap;
use serde::{
Deserialize,
Serialize,
};
use serde_string_enum::{
DeserializeLabeledStringEnum,
SerializeLabeledStringEnum,
};
use crate::{
battle::{
Context,
core_battle_effects,
},
effect::fxlang,
};
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
SerializeLabeledStringEnum,
DeserializeLabeledStringEnum,
)]
pub enum FieldEnvironment {
#[default]
#[string = "Normal"]
Normal,
#[string = "Cave"]
Cave,
#[string = "Sand"]
Sand,
#[string = "Water"]
Water,
#[string = "Ice"]
Ice,
#[string = "Sky"]
Sky,
#[string = "Grass"]
Grass,
#[string = "Volcano"]
Volcano,
}
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
SerializeLabeledStringEnum,
DeserializeLabeledStringEnum,
)]
pub enum TimeOfDay {
#[default]
#[string = "Day"]
Day,
#[string = "Morning"]
Morning,
#[string = "Evening"]
Evening,
#[string = "Night"]
Night,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct FieldData {
pub weather: Option<String>,
pub terrain: Option<String>,
#[serde(default)]
pub environment: FieldEnvironment,
#[serde(default)]
pub time: TimeOfDay,
}
#[derive(Debug, Default, Clone)]
pub struct FieldEffectCache {
pub effective_weather: Option<Option<Id>>,
pub effective_terrain: Option<Option<Id>>,
}
pub struct Field {
pub default_weather: Option<Id>,
pub default_terrain: Option<Id>,
pub environment: FieldEnvironment,
pub time: TimeOfDay,
pub weather: Option<Id>,
pub weather_state: fxlang::EffectState,
pub terrain: Option<Id>,
pub terrain_state: fxlang::EffectState,
pub pseudo_weathers: HashMap<Id, fxlang::EffectState>,
pub effect_cache: FieldEffectCache,
}
impl Field {
pub fn new(data: FieldData) -> Self {
Self {
default_weather: data.weather.map(|weather| Id::from(weather)),
default_terrain: data.terrain.map(|terrain| Id::from(terrain)),
environment: data.environment,
time: data.time,
weather: None,
weather_state: fxlang::EffectState::default(),
terrain: None,
terrain_state: fxlang::EffectState::default(),
pseudo_weathers: HashMap::default(),
effect_cache: FieldEffectCache::default(),
}
}
pub fn effective_terrain(context: &mut Context) -> Option<Id> {
if let Some(effective_terrain) = context
.battle()
.field
.effect_cache
.effective_terrain
.clone()
{
return effective_terrain;
}
let effective_terrain = {
if core_battle_effects::run_event_with_options::<_, _, bool>(
context,
fxlang::BattleEvent::SuppressFieldTerrain,
(),
core_battle_effects::RunEventOptions {
return_first_value: true,
..Default::default()
},
) {
None
} else {
context.battle().field.terrain.clone()
}
};
context.battle_mut().field.effect_cache.effective_terrain = Some(effective_terrain.clone());
effective_terrain
}
pub fn effective_weather(context: &mut Context) -> Option<Id> {
if let Some(effective_weather) = context
.battle()
.field
.effect_cache
.effective_weather
.clone()
{
return effective_weather;
}
let effective_weather = {
if core_battle_effects::run_event_with_options::<_, _, bool>(
context,
fxlang::BattleEvent::SuppressFieldWeather,
(),
core_battle_effects::RunEventOptions {
return_first_value: true,
..Default::default()
},
) {
None
} else {
context.battle().field.weather.clone()
}
};
context.battle_mut().field.effect_cache.effective_weather = Some(effective_weather.clone());
effective_weather
}
}