Automatically generate script name resolver.
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2023-06-30 13:44:50 +02:00
parent 12cd2ef33e
commit 037e7af16f
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
19 changed files with 485 additions and 187 deletions

View File

@ -3,6 +3,7 @@ name = "gen7_scripts"
version = "0.1.0"
authors = ["Deukhoofd <Deukhoofd@gmail.com>"]
edition = "2021"
build = "build.rs"
[lib]
crate-type = ["cdylib"]
@ -14,4 +15,7 @@ atomic_float = "0.1.0"
[dev-dependencies]
pkmn_lib_interface = { path = "../pkmn_lib_interface", features = ["mock_data"] }
mockall = "0.11.2"
mockall = "0.11.2"
[build-dependencies]
syn = { version = "2.0.22", features = ["full"] }

127
gen_7_scripts/build.rs Normal file
View File

@ -0,0 +1,127 @@
use std::io::Write;
fn main() {
let mut output_file = std::fs::File::create("src/registered_scripts.rs").unwrap();
write!(
output_file,
r"// Autogenerated file. Do not edit.
use alloc::boxed::Box;
use pkmn_lib_interface::app_interface::{{get_hash, StringKey}};
use pkmn_lib_interface::handling::{{Script, ScriptCategory}};
macro_rules! resolve_match {{
(
$mid:expr,
$(
$script:ty,
)*
) => (
match $mid {{
$(
const {{ get_hash(<$script>::get_const_name()) }} => {{
return Some(Box::new(<$script>::new()))
}}
)*
_ => {{}}
}}
)
}}
pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option<Box<dyn Script>> {{
match category {{"
)
.unwrap();
write_category("moves", "Move", &mut output_file);
write_category("abilities", "Ability", &mut output_file);
write_category("status", "Status", &mut output_file);
write_category("pokemon", "Pokemon", &mut output_file);
write_category("battle", "Battle", &mut output_file);
write_category("weather", "Weather", &mut output_file);
write_category("side", "Side", &mut output_file);
write_category(
"item_battle_triggers",
"ItemBattleTrigger",
&mut output_file,
);
write!(
output_file,
r#"
}}
None
}}
"#
)
.unwrap();
}
fn write_category(path: &str, category: &str, output_file: &mut std::fs::File) {
write!(
output_file,
r"
ScriptCategory::{} => {{
resolve_match! {{
name.hash().unwrap(),
",
category
)
.unwrap();
write_scripts(path, output_file);
write!(
output_file,
r" }}
}},"
)
.unwrap();
}
fn write_scripts(path: &str, output_file: &mut std::fs::File) {
let move_files = std::fs::read_dir(format!("src/{}", path))
.unwrap()
.map(|f| f.unwrap().path())
.filter(|f| f.extension().unwrap() == "rs")
.map(|f| f.file_stem().unwrap().to_str().unwrap().to_string())
.collect::<Vec<_>>();
for file in move_files {
println!("cargo:rerun-if-changed=src/{}/{}.rs", path, file);
let parsed =
syn::parse_file(&std::fs::read_to_string(format!("src/{}/{}.rs", path, file)).unwrap())
.unwrap();
// Now we need to find every impl Script for X { ... } block inside parsed
let script_impls = parsed
.items
.iter()
.filter_map(|item| match item {
syn::Item::Impl(impl_block) => match impl_block.trait_ {
Some((_, ref path, _)) => {
if path.segments[0].ident == "Script" {
Some(impl_block)
} else {
None
}
}
None => None,
},
_ => None,
})
.collect::<Vec<_>>();
for script_impl in script_impls {
match script_impl.self_ty.as_ref() {
syn::Type::Path(p) => {
let ident = p.path.segments[0].ident.to_string();
writeln!(
output_file,
" crate::{}::{}::{},",
path, file, ident
)
.unwrap();
}
_ => {}
}
}
}
}

View File

@ -18,6 +18,7 @@ pub mod registered_scripts;
pub(crate) mod common_usings;
pub mod moves;
pub mod pokemon;
pub mod side;
pub mod util_scripts;
pub(crate) mod utils;
pub mod weather;

View File

@ -1,4 +1,5 @@
use crate::common_usings::*;
use crate::pokemon::assurance_data::AssuranceData;
use pkmn_lib_interface::PkmnResult;
script!(Assurance, "assurance");
@ -29,10 +30,7 @@ impl Script for Assurance {
.get(data.target_side() as usize)
.unwrap()
.clone();
side.add_volatile(Box::new(AssuranceData {
for_position: data.target_index(),
has_hit: AtomicBool::new(false),
}))?;
side.add_volatile(AssuranceData::create_for_assurance(data.target_index()))?;
}
Ok(())
}
@ -48,7 +46,7 @@ impl Script for Assurance {
target.battle_side()?.as_ref(),
AssuranceData::get_const_name(),
)? {
if s.has_hit.load(Ordering::Relaxed) {
if s.has_hit() {
*base_power *= 2;
}
}
@ -59,50 +57,3 @@ impl Script for Assurance {
self
}
}
script!(
AssuranceData,
"assurance_data",
for_position: u8,
has_hit: AtomicBool
);
impl Script for AssuranceData {
fn new() -> Self {
Self {
for_position: 0,
has_hit: AtomicBool::new(false),
}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::OnEndTurn, ScriptCapabilities::OnDamage]
}
fn on_end_turn(&self) -> PkmnResult<()> {
let side = self.get_owner().unwrap().as_side();
side.remove_volatile(self)?;
Ok(())
}
fn on_damage(
&self,
pokemon: Pokemon,
_source: DamageSource,
_old_health: u32,
_new_health: u32,
) -> PkmnResult<()> {
if pokemon.battle_index()? == self.for_position {
self.has_hit.store(true, Ordering::Relaxed);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -1,6 +1,5 @@
use crate::common_usings::*;
use crate::moves::light_screen::LightScreenEffect;
use crate::moves::reflect::ReflectEffect;
use crate::side::aurora_veil_effect::AuroraVeilEffect;
use crate::weather::hail::Hail;
use pkmn_lib_interface::PkmnResult;
@ -46,62 +45,3 @@ impl Script for AuroraVeil {
self
}
}
script!(AuroraVeilEffect, "aurora_veil_effect", turns: AtomicU32);
impl Script for AuroraVeilEffect {
fn new() -> Self {
Self {
turns: Default::default(),
}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[
ScriptCapabilities::ChangeIncomingDamage,
ScriptCapabilities::OnEndTurn,
]
}
fn change_incoming_damage(
&self,
mv: ExecutingMove,
target: Pokemon,
hit: u8,
damage: &mut u32,
) -> PkmnResult<()> {
if mv.get_hit_data(&target, hit)?.is_critical()? {
return Ok(());
}
let side = self.get_owner().unwrap().as_side();
if side.has_volatile(ReflectEffect::get_const_name())?
&& mv.use_move().category() == MoveCategory::Physical
{
return Ok(());
}
if side.has_volatile(LightScreenEffect::get_const_name())?
&& mv.use_move().category() == MoveCategory::Special
{
return Ok(());
}
let mut modifier = 2.0;
if target.battle()?.unwrap().pokemon_per_side()? > 1 {
modifier = 1.5
}
*damage = (*damage as f32 / modifier) as u32;
Ok(())
}
fn on_end_turn(&self) -> PkmnResult<()> {
// TODO
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -1,4 +1,5 @@
use crate::common_usings::*;
use crate::pokemon::flinch_effect::FlinchEffect;
script!(Flinch, "flinch");
@ -28,30 +29,4 @@ impl Script for Flinch {
fn as_any(&self) -> &dyn Any {
self
}
}
script!(FlinchEffect, "flinch_effect");
impl Script for FlinchEffect {
fn new() -> Self {
Self {}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::PreventMove]
}
fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) -> PkmnResult<()> {
*prevent = true;
mv.user().remove_volatile(self)?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
}

View File

@ -0,0 +1,33 @@
use crate::common_usings::*;
use pkmn_lib_interface::PkmnResult;
script!(IncreasedCriticalStage, "increased_critical_stage");
impl Script for IncreasedCriticalStage {
fn new() -> Self {
Self {}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::ChangeCriticalStage]
}
fn change_critical_stage(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
stage: &mut u8,
) -> PkmnResult<()> {
*stage += 1;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -1,4 +0,0 @@
// TODO: Implementation
use crate::script;
script!(LightScreenEffect, "light_screen_effect");

View File

@ -11,8 +11,8 @@ pub mod change_target_stats;
pub mod cure_party_status;
pub mod drain;
pub mod flinch;
pub mod light_screen;
pub mod multi_hit_move;
pub mod reflect;
pub mod struggle;
pub mod heal_each_end_of_turn;
pub mod increased_critical_stage;
pub mod multi_hit_move;
pub mod prevent_foes_exit;
pub mod struggle;

View File

@ -0,0 +1,34 @@
use crate::common_usings::*;
use crate::pokemon::prevent_foes_exit::PreventFoesExitEffect;
script!(PreventFoesExist, "prevent_foes_exit");
impl Script for PreventFoesExist {
fn new() -> Self {
Self {}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::OnSecondaryEffect]
}
fn on_secondary_effect(
&self,
executing_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
) -> PkmnResult<()> {
executing_move
.user()
.add_volatile(Box::new(PreventFoesExitEffect::new()))?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -0,0 +1,61 @@
use crate::common_usings::*;
script!(
AssuranceData,
"assurance_data",
for_position: u8,
has_hit: AtomicBool
);
impl Script for AssuranceData {
fn new() -> Self {
Self {
for_position: 0,
has_hit: AtomicBool::new(false),
}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::OnEndTurn, ScriptCapabilities::OnDamage]
}
fn on_end_turn(&self) -> PkmnResult<()> {
let side = self.get_owner().unwrap().as_side();
side.remove_volatile(self)?;
Ok(())
}
fn on_damage(
&self,
pokemon: Pokemon,
_source: DamageSource,
_old_health: u32,
_new_health: u32,
) -> PkmnResult<()> {
if pokemon.battle_index()? == self.for_position {
self.has_hit.store(true, Ordering::Relaxed);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl AssuranceData {
pub fn create_for_assurance(for_position: u8) -> Box<dyn Script> {
Box::new(Self {
for_position,
has_hit: AtomicBool::new(false),
})
}
pub fn has_hit(&self) -> bool {
self.has_hit.load(Ordering::Relaxed)
}
}

View File

@ -0,0 +1,27 @@
use crate::common_usings::*;
script!(FlinchEffect, "flinch_effect");
impl Script for FlinchEffect {
fn new() -> Self {
Self {}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::PreventMove]
}
fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) -> PkmnResult<()> {
*prevent = true;
mv.user().remove_volatile(self)?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -1,2 +1,6 @@
pub mod assurance_data;
pub mod flinch_effect;
pub mod heal_each_end_of_turn;
pub mod infatuated;
pub mod prevent_foes_exit;
pub mod reflect_effect;

View File

@ -0,0 +1,34 @@
use crate::common_usings::*;
script!(PreventFoesExitEffect, "prevent_foes_exit");
impl Script for PreventFoesExitEffect {
fn new() -> Self {
Self {}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[
ScriptCapabilities::PreventOpponentSwitch,
ScriptCapabilities::PreventOpponentRunAway,
]
}
fn prevent_opponent_switch(&self, _choice: TurnChoice, prevent: &mut bool) -> PkmnResult<()> {
*prevent = true;
Ok(())
}
fn prevent_opponent_run_away(&self, _choice: TurnChoice, prevent: &mut bool) -> PkmnResult<()> {
*prevent = true;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -1,10 +1,8 @@
use crate::moves::*;
use crate::pokemon;
use crate::pokemon::*;
// Autogenerated file. Do not edit.
use alloc::boxed::Box;
use pkmn_lib_interface::app_interface::{get_hash, StringKey};
use pkmn_lib_interface::handling::{Script, ScriptCategory};
use pkmn_lib_interface::println;
macro_rules! resolve_match {
(
@ -25,49 +23,73 @@ macro_rules! resolve_match {
}
pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option<Box<dyn Script>> {
println!("Getting script {:?}", name);
match category {
ScriptCategory::Move => {
resolve_match! {
name.hash().unwrap(),
acrobatics::Acrobatics,
acupressure::Acupressure,
after_you::AfterYou,
assist::Assist,
assurance::Assurance,
attract::Attract,
aurora_veil::AuroraVeil,
automize::Automize,
change_all_target_stats::ChangeAllTargetStats,
change_target_stats::ChangeTargetAttack,
change_target_stats::ChangeTargetDefense,
change_target_stats::ChangeTargetSpecialAttack,
change_target_stats::ChangeTargetSpecialDefense,
change_target_stats::ChangeTargetSpeed,
cure_party_status::CurePartyStatus,
drain::Drain,
flinch::Flinch,
crate::moves::automize::Automize,
crate::moves::prevent_foes_exit::PreventFoesExist,
crate::moves::attract::Attract,
crate::moves::assist::Assist,
crate::moves::acupressure::Acupressure,
crate::moves::struggle::Struggle,
crate::moves::assurance::Assurance,
crate::moves::cure_party_status::CurePartyStatus,
crate::moves::multi_hit_move::MultiHitMove,
crate::moves::heal_each_end_of_turn::HealEachEndOfTurn,
multi_hit_move::MultiHitMove,
struggle::Struggle,
};
}
ScriptCategory::Ability => {}
ScriptCategory::Status => {}
crate::moves::aurora_veil::AuroraVeil,
crate::moves::change_all_target_stats::ChangeAllTargetStats,
crate::moves::after_you::AfterYou,
crate::moves::drain::Drain,
crate::moves::acrobatics::Acrobatics,
crate::moves::flinch::Flinch,
crate::moves::increased_critical_stage::IncreasedCriticalStage,
}
},
ScriptCategory::Ability => {
resolve_match! {
name.hash().unwrap(),
}
},
ScriptCategory::Status => {
resolve_match! {
name.hash().unwrap(),
}
},
ScriptCategory::Pokemon => {
resolve_match! {
name.hash().unwrap(),
infatuated::Infatuated,
pokemon::heal_each_end_of_turn::HealEachEndOfTurnEffect,
crate::pokemon::prevent_foes_exit::PreventFoesExitEffect,
crate::pokemon::assurance_data::AssuranceData,
crate::pokemon::flinch_effect::FlinchEffect,
crate::pokemon::heal_each_end_of_turn::HealEachEndOfTurnEffect,
crate::pokemon::infatuated::Infatuated,
}
}
},
ScriptCategory::Battle => {
resolve_match! {name.hash().unwrap(), crate::util_scripts::ForceEffectTriggerScript,}
}
ScriptCategory::Side => {}
ScriptCategory::ItemBattleTrigger => {}
ScriptCategory::Weather => {}
resolve_match! {
name.hash().unwrap(),
}
},
ScriptCategory::Weather => {
resolve_match! {
name.hash().unwrap(),
crate::weather::hail::Hail,
}
},
ScriptCategory::Side => {
resolve_match! {
name.hash().unwrap(),
crate::side::light_screen::LightScreenEffect,
crate::side::aurora_veil_effect::AuroraVeilEffect,
}
},
ScriptCategory::ItemBattleTrigger => {
resolve_match! {
name.hash().unwrap(),
}
},
}
None
}
}

View File

@ -0,0 +1,63 @@
use crate::common_usings::*;
use crate::pokemon::reflect_effect::ReflectEffect;
use crate::script;
use crate::side::light_screen::LightScreenEffect;
script!(AuroraVeilEffect, "aurora_veil_effect", pub(crate) turns: AtomicU32);
impl Script for AuroraVeilEffect {
fn new() -> Self {
Self {
turns: Default::default(),
}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[
ScriptCapabilities::ChangeIncomingDamage,
ScriptCapabilities::OnEndTurn,
]
}
fn change_incoming_damage(
&self,
mv: ExecutingMove,
target: Pokemon,
hit: u8,
damage: &mut u32,
) -> PkmnResult<()> {
if mv.get_hit_data(&target, hit)?.is_critical()? {
return Ok(());
}
let side = self.get_owner().unwrap().as_side();
if side.has_volatile(ReflectEffect::get_const_name())?
&& mv.use_move().category() == MoveCategory::Physical
{
return Ok(());
}
if side.has_volatile(LightScreenEffect::get_const_name())?
&& mv.use_move().category() == MoveCategory::Special
{
return Ok(());
}
let mut modifier = 2.0;
if target.battle()?.unwrap().pokemon_per_side()? > 1 {
modifier = 1.5
}
*damage = (*damage as f32 / modifier) as u32;
Ok(())
}
fn on_end_turn(&self) -> PkmnResult<()> {
// TODO
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -0,0 +1,24 @@
// TODO: Implementation
use crate::script;
use core::any::Any;
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
script!(LightScreenEffect, "light_screen_effect");
impl Script for LightScreenEffect {
fn new() -> Self {
Self {}
}
fn get_name(&self) -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[]
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -0,0 +1,2 @@
pub mod aurora_veil_effect;
pub mod light_screen;