Merge branch 'pc_editing' of git.owlcode.tech:sergiotarxz/GEmeTool
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "pokeemerald"]
|
||||
path = pokeemerald
|
||||
url = https://github.com/pret/pokeemerald
|
2
Build.PL
@ -16,7 +16,9 @@ my $build = Module::Build->new(
|
||||
'DBI' => 0,
|
||||
'Moo' => 0,
|
||||
'namespace::clean' => 0,
|
||||
'Cairo::GObject' => 0,
|
||||
'UUID::URandom' => 0,
|
||||
'Glib' => 0,
|
||||
},
|
||||
);
|
||||
$build->create_build_script;
|
||||
|
31
create_shiny_folder.pl
Normal file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Path::Tiny;
|
||||
|
||||
my $pokemons_dir = path 'pokeemerald/graphics/pokemon/';
|
||||
my $tempdir = Path::Tiny->tempdir;
|
||||
my $shiny_dir = path 'resources/shiny';
|
||||
$shiny_dir->mkpath;
|
||||
for my $pokemon_dir ( $pokemons_dir->children ) {
|
||||
my $bpp = $tempdir->child( $pokemon_dir->basename . '.4bpp' );
|
||||
say $pokemon_dir->basename;
|
||||
my $front = $pokemon_dir->child('front.png');
|
||||
my $shiny = $pokemon_dir->child('shiny.pal');
|
||||
if ($pokemon_dir->basename eq 'unown') {
|
||||
$front = $pokemon_dir->child('z/front.png');
|
||||
}
|
||||
if ($pokemon_dir->basename eq 'castform') {
|
||||
$front = $pokemon_dir->child('normal/front.png');
|
||||
$shiny = $pokemon_dir->child('normal/shiny.pal');
|
||||
}
|
||||
system './pokeemerald/tools/gbagfx/gbagfx',
|
||||
$front, $bpp;
|
||||
system './pokeemerald/tools/gbagfx/gbagfx',
|
||||
$bpp, $shiny_dir->child( $pokemon_dir->basename . '.png' ),
|
||||
'-palette', $shiny, '-mwidth', 8, '-object';
|
||||
}
|
82
create_species_data.pl
Normal file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use v5.16.1;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Path::Tiny;
|
||||
use Data::Dumper;
|
||||
|
||||
my $output_file = path('lib/Rsaves/Constants/Emerald/SpeciesData.pm');
|
||||
my $input_file = path('pokeemerald/src/data/pokemon/species_info.h');
|
||||
my $fh_output = $output_file->openw;
|
||||
open my $fh_input, '-|', 'cpp', $input_file;
|
||||
|
||||
print $fh_output <<'EOF';
|
||||
package Rsaves::Constants::Emerald::SpeciesData;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
EOF
|
||||
|
||||
$Data::Dumper::Terse = 1;
|
||||
|
||||
my %all_species_data;
|
||||
{
|
||||
my $species;
|
||||
my %species_data;
|
||||
while (defined (my $line = <$fh_input>)) {
|
||||
if ($line =~ /^\s*\[SPECIES_(\w+)\]\s*=/) {
|
||||
if (defined $species) {
|
||||
$all_species_data{$species} = {%species_data};
|
||||
}
|
||||
%species_data = ();
|
||||
$species = $1;
|
||||
if ($species eq 'NONE') {
|
||||
$species = undef;
|
||||
}
|
||||
}
|
||||
if (defined $species) {
|
||||
if ($line =~ /\.growthRate\s*=\s*(\w+)/) {
|
||||
my $growth_rate = $1;
|
||||
$species_data{growth_rate} = $1;
|
||||
}
|
||||
if ($line =~ /\.genderRatio\s*=\s*(\w+)/) {
|
||||
my $gender_ratio = $1;
|
||||
if ($gender_ratio eq 'min' && $line =~ /(\w+) \* 255/) {
|
||||
$gender_ratio = $1;
|
||||
$gender_ratio *= 255 / 100;
|
||||
$gender_ratio = int($gender_ratio);
|
||||
if ($gender_ratio > 254) {
|
||||
$gender_ratio = 254;
|
||||
}
|
||||
}
|
||||
if ($gender_ratio eq 'MON_FEMALE') {
|
||||
$gender_ratio = 254;
|
||||
}
|
||||
if ($gender_ratio eq 'MON_MALE') {
|
||||
$gender_ratio = 0;
|
||||
}
|
||||
if ($gender_ratio eq 'MON_GENDERLESS') {
|
||||
$gender_ratio = 255;
|
||||
}
|
||||
$species_data{gender_ratio} = $gender_ratio
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
print $fh_output 'our %SPECIES_DATA = %{';
|
||||
my $dumper = Data::Dumper::Dumper \%all_species_data;
|
||||
chomp($dumper);
|
||||
print $fh_output $dumper;
|
||||
say $fh_output '};';
|
||||
|
||||
say $fh_output '1;';
|
||||
system 'perltidy', '-b', $output_file;
|
||||
1;
|
23
lib/GEmeTool/Constants.pm
Normal file
@ -0,0 +1,23 @@
|
||||
package GEmeTool::Constants;
|
||||
|
||||
our @wallpapers = (
|
||||
'FOREST',
|
||||
'CITY',
|
||||
'DESERT',
|
||||
'SAVANNA',
|
||||
'CRAG',
|
||||
'VOLCANO',
|
||||
'SNOW',
|
||||
'CAVE',
|
||||
'BEACH',
|
||||
'SEAFLOOR',
|
||||
'RIVER',
|
||||
'SKY',
|
||||
'POLKADOT',
|
||||
'POKECENTER',
|
||||
'MACHINE',
|
||||
'PLAIN',
|
||||
'FRIENDS'
|
||||
);
|
||||
|
||||
1;
|
@ -15,6 +15,7 @@ use Moo;
|
||||
|
||||
use GEmeTool::Log qw/logger/;
|
||||
use namespace::clean;
|
||||
use GEmeTool::Save::PokemonPC;
|
||||
|
||||
has __saves => ( is => 'rw' );
|
||||
|
||||
@ -26,6 +27,8 @@ has _initial_rematches => ( is => 'rw' );
|
||||
|
||||
has _initial_flags => ( is => 'rw' );
|
||||
|
||||
has _pc => ( is => 'rw' );
|
||||
|
||||
sub instance {
|
||||
my $class = shift;
|
||||
my $input_file = shift;
|
||||
@ -217,4 +220,18 @@ sub _get_flags_hash_by_id {
|
||||
);
|
||||
return @final_hash;
|
||||
}
|
||||
|
||||
sub get_pc_system {
|
||||
my $self = shift;
|
||||
if (defined $self->_pc) {
|
||||
return $self->_pc;
|
||||
}
|
||||
my $pc = Rsaves::read_pc_storage($self->_get_current_save);
|
||||
my $return = GEmeTool::Save::PokemonPC->new(_pc => $pc, _save => sub {
|
||||
my $pc = shift;
|
||||
Rsaves::save_pc_changes($self->_get_current_save, $pc)
|
||||
});
|
||||
$self->_pc($return);
|
||||
return $return;
|
||||
}
|
||||
1;
|
||||
|
359
lib/GEmeTool/Save/Pokemon.pm
Normal file
@ -0,0 +1,359 @@
|
||||
package GEmeTool::Save::Pokemon;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Moo;
|
||||
use Rsaves;
|
||||
use Rsaves::Constants::Emerald::Species;
|
||||
use Rsaves::Constants::Emerald::SpeciesData;
|
||||
|
||||
has _pokemon => ( is => 'rw', );
|
||||
|
||||
sub species {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
my $pokemon = $self->_pokemon;
|
||||
my $substruct_0 = $pokemon->{substructures}[0];
|
||||
if ( defined $arg ) {
|
||||
$substruct_0->{species} = $arg;
|
||||
}
|
||||
return $substruct_0->{species};
|
||||
}
|
||||
|
||||
sub ivs {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
my $current_value =
|
||||
$self->_pokemon->{substructures}[3]{ivs_egg_status_and_ability};
|
||||
my @stats = (
|
||||
'HP', 'Attack',
|
||||
'Defense', 'Speed',
|
||||
'Special Attack', 'Special Defense'
|
||||
);
|
||||
if ( defined $arg ) {
|
||||
if ( defined $arg->{HP} ) {
|
||||
$current_value &= ~0x1f;
|
||||
$current_value |= ( $arg->{HP} & 0x1f );
|
||||
}
|
||||
if ( defined $arg->{Attack} ) {
|
||||
$current_value &= ~( 0x1f << 5 );
|
||||
$current_value |= ( ( $arg->{Attack} & 0x1f ) << 5 );
|
||||
}
|
||||
if ( defined $arg->{Defense} ) {
|
||||
$current_value &= ~( 0x1f << 10 );
|
||||
$current_value |= ( ( $arg->{Defense} & 0x1f ) << 10 );
|
||||
}
|
||||
if ( defined $arg->{Speed} ) {
|
||||
$current_value &= ~( 0x1f << 15 );
|
||||
$current_value |= ( ( $arg->{Speed} & 0x1f ) << 15 );
|
||||
}
|
||||
if ( defined $arg->{SpecialAttack} ) {
|
||||
$current_value &= ~( 0x1f << 20 );
|
||||
$current_value |= ( ( $arg->{SpecialAttack} & 0x1f ) << 20 );
|
||||
}
|
||||
if ( defined $arg->{SpecialDefense} ) {
|
||||
$current_value &= ~( 0x1f << 25 );
|
||||
$current_value |= ( ( $arg->{SpecialDefense} & 0x1f ) << 25 );
|
||||
}
|
||||
$self->_pokemon->{substructures}[3]{ivs_egg_status_and_ability} =
|
||||
$current_value;
|
||||
}
|
||||
my $ivs_egg_status_and_ability = $current_value;
|
||||
return {
|
||||
HP => $ivs_egg_status_and_ability & 0x1F,
|
||||
Attack => ( $ivs_egg_status_and_ability >> 5 ) & 0x1F,
|
||||
Defense => ( $ivs_egg_status_and_ability >> 10 ) & 0x1F,
|
||||
Speed => ( $ivs_egg_status_and_ability >> 15 ) & 0x1F,
|
||||
SpecialDefense => ( $ivs_egg_status_and_ability >> 25 ) & 0x1F,
|
||||
SpecialAttack => ( $ivs_egg_status_and_ability >> 20 ) & 0x1F,
|
||||
};
|
||||
}
|
||||
|
||||
sub evs {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
my $pokemon = $self->_pokemon;
|
||||
my $substructure = $pokemon->{substructures}[2];
|
||||
if (defined $arg) {
|
||||
if (defined $arg->{HP}) {
|
||||
$substructure->{hp_ev} = $arg->{HP};
|
||||
}
|
||||
if (defined $arg->{Attack}) {
|
||||
$substructure->{attack_ev} = $arg->{Attack};
|
||||
}
|
||||
if (defined $arg->{Defense}) {
|
||||
$substructure->{defense_ev} = $arg->{Defense};
|
||||
}
|
||||
if (defined $arg->{Speed}) {
|
||||
$substructure->{speed_ev} = $arg->{Speed};
|
||||
}
|
||||
if (defined $arg->{SpecialAttack}) {
|
||||
$substructure->{special_attack_ev} = $arg->{SpecialAttack};
|
||||
}
|
||||
if (defined $arg->{SpecialDefense}) {
|
||||
$substructure->{special_defense_ev} = $arg->{SpecialDefense};
|
||||
}
|
||||
}
|
||||
return {
|
||||
HP => $pokemon->{substructures}[2]{hp_ev},
|
||||
Attack => $pokemon->{substructures}[2]{attack_ev},
|
||||
Defense => $pokemon->{substructures}[2]{defense_ev},
|
||||
Speed => $pokemon->{substructures}[2]{speed_ev},
|
||||
SpecialAttack => $pokemon->{substructures}[2]{special_attack_ev},
|
||||
SpecialDefense => $pokemon->{substructures}[2]{special_defense_ev},
|
||||
};
|
||||
}
|
||||
|
||||
sub level {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
my $pokemon = $self->_pokemon;
|
||||
my $growth_func = sub {
|
||||
my $n = shift;
|
||||
if ( $n == 1 ) {
|
||||
return 1;
|
||||
}
|
||||
return $self->growth_function->($n);
|
||||
};
|
||||
if ( defined $arg ) {
|
||||
$pokemon->{substructures}[0]{experience} = $growth_func->($arg);
|
||||
}
|
||||
my $experience = $pokemon->{substructures}[0]{experience};
|
||||
my $level = 1;
|
||||
while ( $level <= 100 && int( $growth_func->($level) ) <= $experience ) {
|
||||
$level++;
|
||||
}
|
||||
$level -= 1;
|
||||
|
||||
return $level;
|
||||
}
|
||||
|
||||
sub growth_function {
|
||||
my $self = shift;
|
||||
my $growth = $self->growth;
|
||||
if ( $growth eq 'GROWTH_FAST' ) {
|
||||
return \&_exp_fast;
|
||||
}
|
||||
if ( $growth eq 'GROWTH_MEDIUM_FAST' ) {
|
||||
return \&_exp_medium_fast;
|
||||
}
|
||||
if ( $growth eq 'GROWTH_MEDIUM_SLOW' ) {
|
||||
return \&_exp_medium_slow;
|
||||
}
|
||||
if ( $growth eq 'GROWTH_SLOW' ) {
|
||||
return \&_exp_slow;
|
||||
}
|
||||
if ( $growth eq 'GROWTH_ERRATIC' ) {
|
||||
return \&_exp_erratic;
|
||||
}
|
||||
if ( $growth eq 'GROWTH_FLUCTUATING' ) {
|
||||
return \&_exp_fluctuating;
|
||||
}
|
||||
}
|
||||
|
||||
sub gender_ratio {
|
||||
my $self = shift;
|
||||
my $pokemon_name = $self->pokemon_name;
|
||||
my %pokemon_data = %Rsaves::Constants::Emerald::SpeciesData::SPECIES_DATA;
|
||||
my $data = $pokemon_data{$pokemon_name};
|
||||
my $gender_ratio = $data->{gender_ratio};
|
||||
return $gender_ratio;
|
||||
}
|
||||
|
||||
sub gender {
|
||||
|
||||
# 0 male
|
||||
# 1 female
|
||||
# 2 genderless
|
||||
my $self = shift;
|
||||
my $pokemon = $self->_pokemon;
|
||||
my $personality = shift // $pokemon->{personality};
|
||||
my $gender_ratio = $self->gender_ratio;
|
||||
if ( $gender_ratio == 0 ) {
|
||||
return 0;
|
||||
}
|
||||
if ( $gender_ratio == 254 ) {
|
||||
return 1;
|
||||
}
|
||||
if ( $gender_ratio == 255 ) {
|
||||
return 2;
|
||||
}
|
||||
if ( $gender_ratio <= ( $personality & 0xff ) ) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub personality {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
my $pokemon = $self->_pokemon;
|
||||
if ( defined $arg ) {
|
||||
$self->_pokemon->{personality} = $arg;
|
||||
}
|
||||
return $pokemon->{personality};
|
||||
}
|
||||
|
||||
sub growth {
|
||||
my $self = shift;
|
||||
my $pokemon_name = $self->pokemon_name;
|
||||
my %pokemon_data = %Rsaves::Constants::Emerald::SpeciesData::SPECIES_DATA;
|
||||
my $data = $pokemon_data{$pokemon_name};
|
||||
return $data->{growth_rate};
|
||||
}
|
||||
|
||||
sub _square {
|
||||
return $_[0]**2;
|
||||
}
|
||||
|
||||
sub _cube {
|
||||
return $_[0]**3;
|
||||
}
|
||||
|
||||
sub _exp_slow {
|
||||
my $n = shift;
|
||||
return ( 5 * _cube($n) ) / 4;
|
||||
}
|
||||
|
||||
sub _exp_fast {
|
||||
my $n = shift;
|
||||
return ( 4 * _cube($n) ) / 5;
|
||||
}
|
||||
|
||||
sub _exp_medium_fast {
|
||||
return _cube( $_[0] );
|
||||
}
|
||||
|
||||
sub _exp_medium_slow {
|
||||
my $n = shift;
|
||||
|
||||
#define EXP_MEDIUM_SLOW(n)((6 * CUBE(n)) / 5 - (15 * SQUARE(n)) + (100 * n) - 140) // (6 * (n)^3) / 5 - (15 * (n)^2) + (100 * n) - 140
|
||||
my $return =
|
||||
( ( 6 * _cube($n) ) / 5 - ( 15 * _square($n) ) + ( 100 * $n ) - 140 );
|
||||
return $return;
|
||||
}
|
||||
|
||||
sub _exp_erratic {
|
||||
my $n = shift;
|
||||
if ( $n <= 50 ) {
|
||||
return ( ( 100 - $n ) * _cube($n) / 50 );
|
||||
}
|
||||
if ( $n <= 68 ) {
|
||||
return ( ( 150 - $n ) * _cube($n) / 100 );
|
||||
}
|
||||
if ( $n <= 98 ) {
|
||||
return ( ( 1911 - 10 * $n ) / 3 * _cube($n) / 500 );
|
||||
}
|
||||
return ( ( 160 - $n ) * _cube($n) / 100 );
|
||||
}
|
||||
|
||||
sub _exp_fluctuating {
|
||||
my $n = shift;
|
||||
if ( $n <= 15 ) {
|
||||
return ( ( ( $n + 1 ) / 3 + 24 ) * _cube($n) / 50 );
|
||||
}
|
||||
if ( $n <= 36 ) {
|
||||
return ( ( $n + 14 ) * _cube($n) / 50 );
|
||||
}
|
||||
return ( ( ( $n / 2 ) + 32 ) * _cube($n) / 50 );
|
||||
}
|
||||
|
||||
sub pokemon_name {
|
||||
my $self = shift;
|
||||
return $Rsaves::Constants::Emerald::Species::SPECIES[ $self->species ];
|
||||
}
|
||||
|
||||
sub nickname {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
if ( defined $arg ) {
|
||||
die "Invalid nickname" if length $arg != 10;
|
||||
$self->_pokemon->{nickname} = $arg;
|
||||
}
|
||||
return $self->_pokemon->{nickname};
|
||||
}
|
||||
|
||||
sub get_icon {
|
||||
my $self = shift;
|
||||
my $pokemon_name =
|
||||
$Rsaves::Constants::Emerald::Species::SPECIES[ $self->species ];
|
||||
if ( lc($pokemon_name) eq 'unown' ) {
|
||||
return "pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/z/icon.png";
|
||||
}
|
||||
return "pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/icon.png";
|
||||
}
|
||||
|
||||
sub generate_personality {
|
||||
my $self = shift;
|
||||
my $target_shiny = shift;
|
||||
my $target_gender = shift;
|
||||
my $target_nature = shift;
|
||||
my $otid = $self->otid;
|
||||
my $should_search_gender = 0;
|
||||
my $personality;
|
||||
if ( defined $target_gender
|
||||
&& !( grep { $self->gender_ratio eq $_ } ( 0, 254, 255 ) ) )
|
||||
{
|
||||
$should_search_gender = 1;
|
||||
}
|
||||
if ( defined $target_gender && $target_gender != 0 && $target_gender != 1 )
|
||||
{
|
||||
die "Incorrect gender $target_gender.";
|
||||
}
|
||||
if ( defined $target_nature
|
||||
&& ( $target_nature < 0 || $target_nature > 24 ) )
|
||||
{
|
||||
die "Incorrect nature $target_nature.";
|
||||
}
|
||||
for ( my $i = 0 ; $i < 0xffffffff ; $i++ ) {
|
||||
if ( defined $target_nature && $i % 25 != $target_nature ) {
|
||||
next;
|
||||
}
|
||||
if ( defined $target_shiny
|
||||
&& !( !!$target_shiny == !!Rsaves::is_shiny( $otid, $i ) ) )
|
||||
{
|
||||
next;
|
||||
}
|
||||
if ( $should_search_gender && $self->gender($i) != $target_gender ) {
|
||||
next;
|
||||
}
|
||||
$personality = $i;
|
||||
last;
|
||||
}
|
||||
if ( !defined $personality ) {
|
||||
warn "Could not find personality combination, this is a bug.";
|
||||
}
|
||||
return $personality;
|
||||
}
|
||||
|
||||
sub otid {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
my $pokemon = $self->_pokemon;
|
||||
if ( defined $arg ) {
|
||||
$pokemon->{otid} = $arg;
|
||||
}
|
||||
return $pokemon->{otid};
|
||||
}
|
||||
|
||||
sub get_front {
|
||||
my $self = shift;
|
||||
my $pokemon_name =
|
||||
$Rsaves::Constants::Emerald::Species::SPECIES[ $self->species ];
|
||||
if ( Rsaves::pokemon_is_shiny( $self->_pokemon ) ) {
|
||||
return "resources/shiny/@{[lc($pokemon_name)]}.png";
|
||||
}
|
||||
if ( lc($pokemon_name) eq 'castform' ) {
|
||||
return
|
||||
"pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/normal/front.png";
|
||||
}
|
||||
if ( lc($pokemon_name) eq 'unown' ) {
|
||||
return
|
||||
"pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/z/front.png";
|
||||
}
|
||||
return "pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/front.png";
|
||||
}
|
||||
1;
|
69
lib/GEmeTool/Save/PokemonBox.pm
Normal file
@ -0,0 +1,69 @@
|
||||
package GEmeTool::Save::PokemonBox;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Moo;
|
||||
|
||||
use GEmeTool::Save::Pokemon;
|
||||
|
||||
has _wallpaper => (
|
||||
is => 'rw',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has _name => (
|
||||
is => 'rw',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has _box => (
|
||||
is => 'rw',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has number => ( is => 'ro', );
|
||||
|
||||
has _pokemons => ( is => 'rw', );
|
||||
|
||||
sub wallpaper {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
if ( defined $arg ) {
|
||||
${ $self->_wallpaper } = $arg;
|
||||
}
|
||||
return ${ $self->_wallpaper };
|
||||
}
|
||||
|
||||
sub name {
|
||||
my $self = shift;
|
||||
my $arg = shift;
|
||||
if ( defined $arg ) {
|
||||
${ $self->_name } = $arg;
|
||||
}
|
||||
return ${ $self->_name };
|
||||
}
|
||||
|
||||
sub get_pokemon {
|
||||
my $self = shift;
|
||||
my $number = shift;
|
||||
my $pokemons = $self->_pokemons;
|
||||
if ( !defined $pokemons ) {
|
||||
$pokemons = [];
|
||||
$self->_pokemons($pokemons);
|
||||
}
|
||||
if ( $number < 0 || $number > 29 ) {
|
||||
die
|
||||
"Pokemon boxes can only hold pokemon from 0 to 29, index $number invalid.";
|
||||
}
|
||||
if ( defined $pokemons->[$number] ) {
|
||||
return $pokemons->[$number];
|
||||
}
|
||||
my $return =
|
||||
GEmeTool::Save::Pokemon->new( _pokemon => $self->_box->[$number] );
|
||||
$pokemons->[$number] = $return;
|
||||
return $return;
|
||||
}
|
||||
1;
|
67
lib/GEmeTool/Save/PokemonPC.pm
Normal file
@ -0,0 +1,67 @@
|
||||
package GEmeTool::Save::PokemonPC;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Moo;
|
||||
use Rsaves;
|
||||
|
||||
use GEmeTool::Save::PokemonBox;
|
||||
|
||||
has _pc => (
|
||||
is => 'rw',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has _save => (
|
||||
is => 'rw',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has _boxes => ( is => 'rw', );
|
||||
|
||||
sub boxes {
|
||||
my $self = shift;
|
||||
my $pc = $self->_pc;
|
||||
my @boxes;
|
||||
for ( my $i = 0 ; $i < 14 ; $i++ ) {
|
||||
$boxes[$i] = $self->get_box($i);
|
||||
}
|
||||
return \@boxes;
|
||||
}
|
||||
|
||||
sub get_box {
|
||||
my $self = shift;
|
||||
my $number = shift;
|
||||
my $boxes = $self->_boxes;
|
||||
if ( !defined $boxes ) {
|
||||
$self->_boxes( [] );
|
||||
$boxes = $self->_boxes;
|
||||
}
|
||||
if ( $number < 0 || $number > 13 ) {
|
||||
die "Bad box number $number.";
|
||||
}
|
||||
if ( defined $boxes->[$number] ) {
|
||||
return $boxes->[$number];
|
||||
}
|
||||
my $pc = $self->_pc;
|
||||
my $wallpaper = \$pc->{wallpapers}[$number];
|
||||
my $name = \$pc->{boxes_names}[$number];
|
||||
my $box = $pc->{boxes}[$number];
|
||||
my $return = GEmeTool::Save::PokemonBox->new(
|
||||
_wallpaper => $wallpaper,
|
||||
_name => $name,
|
||||
_box => $box,
|
||||
number => $number,
|
||||
);
|
||||
$boxes->[$number] = $return;
|
||||
return $return;
|
||||
}
|
||||
|
||||
sub save {
|
||||
my $self = shift;
|
||||
$self->_save->( $self->_pc );
|
||||
}
|
||||
1;
|
@ -11,9 +11,11 @@ use Glib::IO;
|
||||
use Glib::Object::Introspection;
|
||||
use Data::Dumper;
|
||||
use Path::Tiny;
|
||||
|
||||
use GEmeTool::Options;
|
||||
use GEmeTool::Save;
|
||||
use GEmeTool::View::LogWindow;
|
||||
use GEmeTool::View::PokemonPCWindow;
|
||||
|
||||
use Moo;
|
||||
|
||||
@ -31,63 +33,54 @@ Glib::Object::Introspection->setup(
|
||||
|
||||
use namespace::clean;
|
||||
|
||||
has _win => (
|
||||
is => 'rw',
|
||||
);
|
||||
has _win => ( is => 'rw', );
|
||||
|
||||
has _options => (
|
||||
is => 'rw',
|
||||
);
|
||||
has _options => ( is => 'rw', );
|
||||
|
||||
has _app => (
|
||||
is => 'rw',
|
||||
);
|
||||
has _app => ( is => 'rw', );
|
||||
|
||||
has _save => (
|
||||
is => 'rw',
|
||||
);
|
||||
has _save => ( is => 'rw', );
|
||||
|
||||
has _save_as => (
|
||||
is => 'rw',
|
||||
);
|
||||
has _save_as_action => ( is => 'rw', );
|
||||
has _pc_action => ( is => 'rw', );
|
||||
|
||||
has _file => (
|
||||
is => 'rw',
|
||||
);
|
||||
has _file => ( is => 'rw', );
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
my $options = GEmeTool::Options->new;
|
||||
$self->_options($options);
|
||||
my $app = Gtk4::Application->new( 'tech.owlcode.GEmeTool', 'default-flags' );
|
||||
my $app =
|
||||
Gtk4::Application->new( 'tech.owlcode.GEmeTool', 'default-flags' );
|
||||
$self->_app($app);
|
||||
$app->signal_connect( activate => sub {
|
||||
$self->activate;
|
||||
} );
|
||||
$app->signal_connect(
|
||||
activate => sub {
|
||||
$self->activate;
|
||||
}
|
||||
);
|
||||
$app->run;
|
||||
}
|
||||
|
||||
sub activate {
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
my $display = Gdk::Display::get_default();
|
||||
my $icon_theme = Gtk4::IconTheme::get_for_display($display);
|
||||
$icon_theme->set_search_path(
|
||||
path(__FILE__)->parent->parent->child('resources/icons')->absolute );
|
||||
Gtk4::Window::set_default_icon_name('gemetool');
|
||||
|
||||
|
||||
my $menu = Glib::IO::Menu->new;
|
||||
my $about = Glib::IO::SimpleAction->new( 'about', undef );
|
||||
my $open = Glib::IO::SimpleAction->new( 'open', undef );
|
||||
my $logs = Glib::IO::SimpleAction->new( 'view_logs', undef );
|
||||
my $save_as = Glib::IO::SimpleAction->new( 'save_as', undef );
|
||||
$save_as->set_enabled(0);
|
||||
my $menu = Glib::IO::Menu->new;
|
||||
my $about = Glib::IO::SimpleAction->new( 'about', undef );
|
||||
my $open = Glib::IO::SimpleAction->new( 'open', undef );
|
||||
my $logs = Glib::IO::SimpleAction->new( 'view_logs', undef );
|
||||
my $pc_action = Glib::IO::SimpleAction->new( 'view_pc', undef );
|
||||
my $save_as_action = Glib::IO::SimpleAction->new( 'save_as', undef );
|
||||
$save_as_action->set_enabled(0);
|
||||
$pc_action->set_enabled(0);
|
||||
my $app = $self->_app;
|
||||
$app->add_action($about);
|
||||
$app->add_action($open);
|
||||
$app->add_action($logs);
|
||||
$app->add_action($save_as);
|
||||
$self->_save_as($save_as);
|
||||
$app->add_action($pc_action);
|
||||
$app->add_action($save_as_action);
|
||||
$self->_save_as_action($save_as_action);
|
||||
$self->_pc_action($pc_action);
|
||||
my $save;
|
||||
my $extra;
|
||||
my $save_menu_item = Glib::IO::MenuItem->new( 'Save as', 'app.save_as' );
|
||||
@ -96,15 +89,23 @@ sub activate {
|
||||
$self->activate_open;
|
||||
}
|
||||
);
|
||||
$save_as->signal_connect(
|
||||
$save_as_action->signal_connect(
|
||||
activate => sub {
|
||||
$self->activate_save;
|
||||
}
|
||||
);
|
||||
$pc_action->signal_connect(
|
||||
activate => sub {
|
||||
$self->activate_view_pc;
|
||||
}
|
||||
);
|
||||
$logs->signal_connect(
|
||||
activate => sub {
|
||||
my $win = $self->_win;
|
||||
GEmeTool::View::LogWindow->new(app => $self->_app, main_window => $self)->start;
|
||||
GEmeTool::View::LogWindow->new(
|
||||
app => $self->_app,
|
||||
main_window => $self
|
||||
)->start;
|
||||
}
|
||||
);
|
||||
|
||||
@ -112,11 +113,14 @@ sub activate {
|
||||
|
||||
my $about_menu_item = Glib::IO::MenuItem->new( 'About', 'app.about' );
|
||||
my $open_menu_item = Glib::IO::MenuItem->new( 'Open', 'app.open' );
|
||||
my $logs_menu_item = Glib::IO::MenuItem->new( 'View logs', 'app.view_logs' );
|
||||
my $submenu_file = Glib::IO::Menu->new;
|
||||
my $submenu_view = Glib::IO::Menu->new;
|
||||
my $submenu_help = Glib::IO::Menu->new;
|
||||
my $logs_menu_item =
|
||||
Glib::IO::MenuItem->new( 'View logs', 'app.view_logs' );
|
||||
my $pc_menu_item = Glib::IO::MenuItem->new( 'View pc', 'app.view_pc' );
|
||||
my $submenu_file = Glib::IO::Menu->new;
|
||||
my $submenu_view = Glib::IO::Menu->new;
|
||||
my $submenu_help = Glib::IO::Menu->new;
|
||||
$submenu_help->append_item($about_menu_item);
|
||||
$submenu_view->append_item($pc_menu_item);
|
||||
$submenu_view->append_item($logs_menu_item);
|
||||
$submenu_file->append_item($open_menu_item);
|
||||
$submenu_file->append_item($save_menu_item);
|
||||
@ -139,56 +143,57 @@ sub activate {
|
||||
}
|
||||
|
||||
sub activate_open {
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
my $cancellable = Glib::IO::Cancellable->new;
|
||||
my $dialog = Gtk4::FileDialog->new;
|
||||
my $options = $self->_options;
|
||||
my $win = $self->_win;
|
||||
my $last_dir = $options->get_last_dir_open;
|
||||
if (defined $last_dir && -d $last_dir) {
|
||||
my $dialog = Gtk4::FileDialog->new;
|
||||
my $options = $self->_options;
|
||||
my $win = $self->_win;
|
||||
my $last_dir = $options->get_last_dir_open;
|
||||
if ( defined $last_dir && -d $last_dir ) {
|
||||
my $curdir = Glib::IO::File::new_for_path($last_dir);
|
||||
$dialog->set_initial_folder($curdir);
|
||||
}
|
||||
$dialog->open(
|
||||
$win, $cancellable,
|
||||
$win,
|
||||
$cancellable,
|
||||
sub {
|
||||
my ( $self_dialog, $res ) = @_;
|
||||
if ($res->had_error) {
|
||||
if ( $res->had_error ) {
|
||||
return;
|
||||
}
|
||||
my $file = $dialog->open_finish($res);
|
||||
return if !defined $file;
|
||||
$file = path( $file->get_path );
|
||||
$self->_file($file);
|
||||
$options->set_last_dir_open($file->parent.'');
|
||||
$options->set_last_dir_open( $file->parent . '' );
|
||||
$self->start_editing_file;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
sub activate_save {
|
||||
my $self = shift;
|
||||
my $win = $self->_win;
|
||||
my $dialog = Gtk4::FileDialog->new;
|
||||
my $options = $self->_options;
|
||||
my $self = shift;
|
||||
my $win = $self->_win;
|
||||
my $dialog = Gtk4::FileDialog->new;
|
||||
my $options = $self->_options;
|
||||
my $last_dir = $options->get_last_dir_open;
|
||||
if (defined $last_dir && -d $last_dir) {
|
||||
if ( defined $last_dir && -d $last_dir ) {
|
||||
my $curdir = Glib::IO::File::new_for_path($last_dir);
|
||||
$dialog->set_initial_folder($curdir);
|
||||
$dialog->set_initial_name( path($self->_file)->basename );
|
||||
$dialog->set_initial_name( path( $self->_file )->basename );
|
||||
}
|
||||
$dialog->save(
|
||||
$win, undef,
|
||||
sub {
|
||||
my ( $self_dialog, $res ) = @_;
|
||||
if ($res->had_error) {
|
||||
if ( $res->had_error ) {
|
||||
return;
|
||||
}
|
||||
my $file = $dialog->save_finish($res);
|
||||
return if !defined $file;
|
||||
$file = path( $file->get_path );
|
||||
$options->set_last_dir_save($file->parent.'');
|
||||
$self->_save->save( $file);
|
||||
$options->set_last_dir_save( $file->parent . '' );
|
||||
$self->_save->save($file);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -202,20 +207,21 @@ sub save {
|
||||
sub open_file {
|
||||
my $self = shift;
|
||||
my $file = shift;
|
||||
if (!-e $file) {
|
||||
if ( !-e $file ) {
|
||||
return;
|
||||
}
|
||||
$file = path( $file );
|
||||
$file = path($file);
|
||||
$self->_file($file);
|
||||
$self->start_editing_file;
|
||||
}
|
||||
|
||||
sub start_editing_file {
|
||||
my $self = shift;
|
||||
my $file = $self->_file;
|
||||
my $save_as = $self->_save_as;
|
||||
my $box_app = Gtk4::Box->new( 'vertical', 0 );
|
||||
$self->_save(GEmeTool::Save->instance($file));
|
||||
my $self = shift;
|
||||
my $file = $self->_file;
|
||||
my $save_as_action = $self->_save_as_action;
|
||||
my $pc_action = $self->_pc_action;
|
||||
my $box_app = Gtk4::Box->new( 'vertical', 0 );
|
||||
$self->_save( GEmeTool::Save->instance($file) );
|
||||
my $save_obj = $self->_save;
|
||||
|
||||
my $search = Gtk4::SearchBar->new;
|
||||
@ -229,11 +235,10 @@ sub start_editing_file {
|
||||
|
||||
my $populate_func = sub {
|
||||
my $box_flags = Gtk4::Box->new( 'vertical', 0 );
|
||||
for my $rematch (@{$self->_save->get_rematches_save})
|
||||
{
|
||||
my $name = $rematch->{name};
|
||||
my $value = $rematch->{value};
|
||||
my $id = $rematch->{id};
|
||||
for my $rematch ( @{ $self->_save->get_rematches_save } ) {
|
||||
my $name = $rematch->{name};
|
||||
my $value = $rematch->{value};
|
||||
my $id = $rematch->{id};
|
||||
my $buffer = $entry->get_buffer;
|
||||
my $search_text = uc( $buffer->get_text );
|
||||
next unless index( $name, $search_text ) >= 0;
|
||||
@ -242,24 +247,24 @@ sub start_editing_file {
|
||||
$toggle->signal_connect(
|
||||
toggled => sub {
|
||||
my $active = $toggle->get_active;
|
||||
$self->_save->set_rematch($id, $active);
|
||||
$self->_save->set_rematch( $id, $active );
|
||||
}
|
||||
);
|
||||
$box_flags->append($toggle);
|
||||
}
|
||||
for my $flag (@{$self->_save->get_flags_save}) {
|
||||
my $name = $flag->{name};
|
||||
my $value = $flag->{value};
|
||||
my $id = $flag->{id};
|
||||
for my $flag ( @{ $self->_save->get_flags_save } ) {
|
||||
my $name = $flag->{name};
|
||||
my $value = $flag->{value};
|
||||
my $id = $flag->{id};
|
||||
my $buffer = $entry->get_buffer;
|
||||
my $search_text = uc( $buffer->get_text );
|
||||
next unless index( $name, $search_text ) >= 0;
|
||||
my $toggle = Gtk4::ToggleButton->new_with_label($name);
|
||||
$toggle->set_active( $value );
|
||||
$toggle->set_active($value);
|
||||
$toggle->signal_connect(
|
||||
toggled => sub {
|
||||
my $active = $toggle->get_active;
|
||||
$self->_save->set_flag($id, $active);
|
||||
$self->_save->set_flag( $id, $active );
|
||||
}
|
||||
);
|
||||
|
||||
@ -276,7 +281,8 @@ sub start_editing_file {
|
||||
$box_app->append($scroll);
|
||||
my $win = $self->_win;
|
||||
$win->set_child($box_app);
|
||||
$save_as->set_enabled(1);
|
||||
$save_as_action->set_enabled(1);
|
||||
$pc_action->set_enabled(1);
|
||||
|
||||
}
|
||||
|
||||
@ -311,4 +317,9 @@ sub activate_about {
|
||||
# $about->set_titlebar($header_bar);
|
||||
$about->present;
|
||||
}
|
||||
|
||||
sub activate_view_pc {
|
||||
my $self = shift;
|
||||
GEmeTool::View::PokemonPCWindow->new( _save => $self->_save )->start;
|
||||
}
|
||||
1;
|
||||
|
482
lib/GEmeTool/View/PokemonEditorWindow.pm
Normal file
@ -0,0 +1,482 @@
|
||||
package GEmeTool::View::PokemonEditorWindow;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Moo;
|
||||
|
||||
use Glib::Object::Introspection;
|
||||
use Glib::IO;
|
||||
use Path::Tiny;
|
||||
|
||||
use Rsaves;
|
||||
use Rsaves::Constants::Emerald::Species;
|
||||
use Rsaves::Constants::Emerald::Natures;
|
||||
|
||||
Glib::Object::Introspection->setup(
|
||||
basename => 'Gtk',
|
||||
version => '4.0',
|
||||
package => 'Gtk4',
|
||||
);
|
||||
|
||||
Glib::Object::Introspection->setup(
|
||||
basename => 'Gdk',
|
||||
version => '4.0',
|
||||
package => 'Gdk',
|
||||
);
|
||||
|
||||
has pokemon => (
|
||||
is => 'ro',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has _win => ( is => 'rw', );
|
||||
|
||||
has _selected_species => ( is => 'rw', );
|
||||
|
||||
has _save_callbacks => ( is => 'rw', default => sub { [] } );
|
||||
|
||||
has _current_personality => ( is => 'rw' );
|
||||
|
||||
has _iv_buffers => ( is => 'rw', default => sub { {} } );
|
||||
has _ev_buffers => ( is => 'rw', default => sub { {} } );
|
||||
|
||||
my $root = path(__FILE__)->parent->parent->parent->parent;
|
||||
my $width = 600;
|
||||
my $height = 400;
|
||||
|
||||
my @stats =
|
||||
( 'HP', 'Attack', 'Defense', 'Speed', 'SpecialAttack', 'SpecialDefense' );
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
my $window = Gtk4::Window->new;
|
||||
$self->_win($window);
|
||||
$self->draw;
|
||||
$window->present;
|
||||
}
|
||||
|
||||
sub onSave {
|
||||
my $self = shift;
|
||||
my $func = shift;
|
||||
my $save_callbacks = $self->_save_callbacks;
|
||||
push @$save_callbacks, $func;
|
||||
}
|
||||
|
||||
sub draw {
|
||||
my $self = shift;
|
||||
my $window = $self->_win;
|
||||
$window->set_resizable(0);
|
||||
my $pokemon = $self->pokemon;
|
||||
$window->set_title( 'Editing Pokémon '
|
||||
. Rsaves::translate_3rd_encoding( $pokemon->nickname ) );
|
||||
$self->_current_personality( $pokemon->personality );
|
||||
my $grid = Gtk4::Grid->new;
|
||||
$grid->set_column_homogeneous(1);
|
||||
my $canvas = Gtk4::DrawingArea->new;
|
||||
$canvas->set_content_width(267);
|
||||
$canvas->set_content_height(267);
|
||||
$canvas->set_valign('start');
|
||||
$canvas->set_halign('start');
|
||||
$canvas->set_draw_func(
|
||||
sub {
|
||||
my $canvas = shift;
|
||||
my $cairo = shift;
|
||||
my $width = shift;
|
||||
my $height = shift;
|
||||
$cairo->scale( $width / 64, $height / 64 );
|
||||
my $surface = Cairo::ImageSurface->create_from_png(
|
||||
$root->child( $pokemon->get_front ) );
|
||||
$cairo->set_source_surface( $surface, 0, 0 );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
}
|
||||
);
|
||||
$grid->attach( $canvas, 0, 0, 2, 2 );
|
||||
my @species = (@Rsaves::Constants::Emerald::Species::SPECIES);
|
||||
my $string_list = Gtk4::StringList->new( [@species] );
|
||||
my $save_button = Gtk4::Button->new_with_label('Save changes');
|
||||
$self->_selected_species( $pokemon->species );
|
||||
my $box_right_image = Gtk4::Box->new( 'vertical', 1 );
|
||||
$box_right_image->set_margin_top(30);
|
||||
$box_right_image->set_valign('start');
|
||||
$box_right_image->set_halign('start');
|
||||
my $box_ev = Gtk4::Box->new('vertical', 1);
|
||||
$grid->attach( $box_right_image, 2, 0, 2, 2 );
|
||||
$grid->attach( $box_ev, 4, 0, 2, 2 );
|
||||
$box_ev->append(Gtk4::Label->new('Select EV'));
|
||||
$self->create_select_level($box_ev);
|
||||
$self->create_select_evs($box_ev);
|
||||
$self->create_change_nickname_entry($box_right_image);
|
||||
$save_button->signal_connect(
|
||||
clicked => sub {
|
||||
$pokemon->species( $self->_selected_species );
|
||||
$pokemon->personality( $self->_current_personality );
|
||||
$self->recalculate_ivs;
|
||||
$self->recalculate_evs;
|
||||
for my $func ( @{ $self->_save_callbacks } ) {
|
||||
$func->();
|
||||
}
|
||||
$self->draw;
|
||||
}
|
||||
);
|
||||
$self->draw_dropdown_pokemon_list($box_right_image);
|
||||
$box_right_image->append(Gtk4::Label->new('Select IV'));
|
||||
$self->create_select_ivs($box_right_image);
|
||||
$self->create_modify_personality($grid);
|
||||
$grid->attach( $save_button, 4, 7, 1, 1 );
|
||||
$window->set_child($grid);
|
||||
}
|
||||
|
||||
sub create_select_level {
|
||||
my $self = shift;
|
||||
my $box = shift;
|
||||
my $pokemon = $self->pokemon;
|
||||
my $box_level = Gtk4::Box->new('horizontal', 10);
|
||||
$box_level->append(Gtk4::Label->new('Lvl:'));
|
||||
my $entry = Gtk4::Entry->new;
|
||||
$entry->set_input_purpose('digits');
|
||||
$entry->get_buffer->set_text($pokemon->level, length $pokemon->level);
|
||||
$box_level->append($entry);
|
||||
$self->onSave( sub {
|
||||
my $text = $entry->get_buffer->get_text;
|
||||
if ($text !~ /^[0-9]+$/) {
|
||||
return;
|
||||
}
|
||||
if ($text > 100) {
|
||||
$text = 100;
|
||||
}
|
||||
if ($text < 2) {
|
||||
$text = 2;
|
||||
}
|
||||
$pokemon->level($text);
|
||||
});
|
||||
$box->append($box_level);
|
||||
}
|
||||
|
||||
sub recalculate_evs {
|
||||
my $self = shift;
|
||||
my $pokemon = $self->pokemon;
|
||||
for my $key ( @stats ) {
|
||||
my $text = $self->_ev_buffers->{$key}->get_text;
|
||||
next if $text !~ /^[0-9]+$/;
|
||||
if ($text > 255) {
|
||||
$text = 255;
|
||||
}
|
||||
if ($text < 0) {
|
||||
$text = 0;
|
||||
}
|
||||
$pokemon->evs(
|
||||
{
|
||||
$key => $text,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub recalculate_ivs {
|
||||
my $self = shift;
|
||||
my $pokemon = $self->pokemon;
|
||||
for my $key ( @stats ) {
|
||||
my $text = $self->_iv_buffers->{$key}->get_text;
|
||||
next if $text !~ /^[0-9]+$/;
|
||||
if ($text > 31) {
|
||||
$text = 31;
|
||||
}
|
||||
if ($text < 0) {
|
||||
$text = 0;
|
||||
}
|
||||
$pokemon->ivs(
|
||||
{
|
||||
$key => $text,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub create_select_evs {
|
||||
my $self = shift;
|
||||
my $box = shift;
|
||||
my $ev_buffers = $self->_ev_buffers;
|
||||
my $evs = $self->pokemon->evs;
|
||||
|
||||
for my $stat (@stats) {
|
||||
my $box_stat = Gtk4::Box->new( 'horizontal', 10 );
|
||||
my $entry = Gtk4::Entry->new;
|
||||
$entry->set_input_purpose('digits');
|
||||
$entry->get_buffer->set_text( $evs->{$stat}, length $evs->{$stat} );
|
||||
$box_stat->append( Gtk4::Label->new($stat) );
|
||||
$box_stat->append($entry);
|
||||
$ev_buffers->{$stat} = $entry->get_buffer;
|
||||
$box->append($box_stat);
|
||||
}
|
||||
}
|
||||
|
||||
sub create_select_ivs {
|
||||
my $self = shift;
|
||||
my $box = shift;
|
||||
my $iv_buffers = $self->_iv_buffers;
|
||||
my $ivs = $self->pokemon->ivs;
|
||||
|
||||
for my $stat (@stats) {
|
||||
my $box_stat = Gtk4::Box->new( 'horizontal', 10 );
|
||||
my $entry = Gtk4::Entry->new;
|
||||
$entry->set_input_purpose('digits');
|
||||
$entry->get_buffer->set_text( $ivs->{$stat}, length $ivs->{$stat} );
|
||||
$box_stat->append( Gtk4::Label->new($stat) );
|
||||
$box_stat->append($entry);
|
||||
$iv_buffers->{$stat} = $entry->get_buffer;
|
||||
$box->append($box_stat);
|
||||
}
|
||||
}
|
||||
|
||||
sub create_modify_personality {
|
||||
my $self = shift;
|
||||
my $grid = shift;
|
||||
my $button = Gtk4::Button->new_with_label('Edit personality');
|
||||
$button->signal_connect(
|
||||
clicked => sub {
|
||||
$self->open_window_personality;
|
||||
}
|
||||
);
|
||||
$button->set_valign('start');
|
||||
$button->set_halign('start');
|
||||
$grid->attach( $button, 2, 2, 1, 1 );
|
||||
}
|
||||
|
||||
sub open_window_personality {
|
||||
my $self = shift;
|
||||
my $window = Gtk4::Window->new;
|
||||
$window->set_default_size( 600, 600 );
|
||||
my $scroll = Gtk4::ScrolledWindow->new;
|
||||
my $box_window = Gtk4::Box->new( 'vertical', 1 );
|
||||
$box_window->append( Gtk4::Label->new('Select shiny') );
|
||||
|
||||
my $box_shiny = Gtk4::Box->new( 'horizontal', 1 );
|
||||
my $shiny_dont_mind = Gtk4::ToggleButton->new_with_label('Do not matter');
|
||||
my $shiny_yes = Gtk4::ToggleButton->new_with_label('Yes');
|
||||
my $shiny_no = Gtk4::ToggleButton->new_with_label('No');
|
||||
|
||||
$shiny_dont_mind->set_active(1);
|
||||
|
||||
$shiny_yes->set_group($shiny_dont_mind);
|
||||
$shiny_no->set_group($shiny_dont_mind);
|
||||
|
||||
$box_shiny->append($shiny_dont_mind);
|
||||
$box_shiny->append($shiny_yes);
|
||||
$box_shiny->append($shiny_no);
|
||||
|
||||
$box_window->append($box_shiny);
|
||||
$box_window->append( Gtk4::Label->new('Select gender') );
|
||||
|
||||
my $box_gender = Gtk4::Box->new( 'horizontal', 1 );
|
||||
my $gender_dont_mind = Gtk4::ToggleButton->new_with_label('Do not matter');
|
||||
my $gender_male = Gtk4::ToggleButton->new_with_label('Male');
|
||||
my $gender_female = Gtk4::ToggleButton->new_with_label('Female');
|
||||
|
||||
$gender_female->set_group($gender_male);
|
||||
$gender_dont_mind->set_group($gender_male);
|
||||
|
||||
$gender_dont_mind->set_active(1);
|
||||
|
||||
$box_gender->append($gender_dont_mind);
|
||||
$box_gender->append($gender_male);
|
||||
$box_gender->append($gender_female);
|
||||
|
||||
$box_window->append($box_gender);
|
||||
|
||||
$box_window->append( Gtk4::Label->new('Select nature') );
|
||||
|
||||
my $box_natures = Gtk4::Box->new( 'vertical', 1 );
|
||||
my @natures = @Rsaves::Constants::Emerald::Natures::NATURES;
|
||||
my %toggle_nature =
|
||||
map { $_ => Gtk4::ToggleButton->new_with_label($_) } @natures;
|
||||
|
||||
my $nature_dont_mind = Gtk4::ToggleButton->new_with_label('Do not matter');
|
||||
$nature_dont_mind->set_active(1);
|
||||
|
||||
$box_natures->append($nature_dont_mind);
|
||||
|
||||
for my $nature (@natures) {
|
||||
my $toggle = $toggle_nature{$nature};
|
||||
$toggle->set_group($nature_dont_mind);
|
||||
$box_natures->append($toggle);
|
||||
}
|
||||
|
||||
$box_window->append($box_natures);
|
||||
|
||||
my $button_generate = Gtk4::Button->new_with_label('Generate personality');
|
||||
$button_generate->signal_connect(
|
||||
clicked => sub {
|
||||
my @gender_buttons = ( $gender_male, $gender_female );
|
||||
my $target_shiny = undef;
|
||||
my $target_gender = undef;
|
||||
my $target_nature = undef;
|
||||
if ( $shiny_yes->get_active ) {
|
||||
$target_shiny = 1;
|
||||
}
|
||||
if ( $shiny_no->get_active ) {
|
||||
$target_shiny = 0;
|
||||
}
|
||||
for my $i ( 0 .. 1 ) {
|
||||
if ( $gender_buttons[$i]->get_active ) {
|
||||
$target_gender = $i;
|
||||
last;
|
||||
}
|
||||
}
|
||||
for my $i ( 0 .. 24 ) {
|
||||
if ( $toggle_nature{ $natures[$i] }->get_active ) {
|
||||
$target_nature = $i;
|
||||
last;
|
||||
}
|
||||
}
|
||||
my $personality =
|
||||
$self->pokemon->generate_personality( $target_shiny,
|
||||
$target_gender, $target_nature );
|
||||
if ( defined $personality ) {
|
||||
$self->_current_personality($personality);
|
||||
}
|
||||
$window->close;
|
||||
}
|
||||
);
|
||||
$box_window->append($button_generate);
|
||||
$scroll->set_child($box_window);
|
||||
$window->set_child($scroll);
|
||||
$window->present;
|
||||
}
|
||||
|
||||
sub create_change_nickname_entry {
|
||||
my $self = shift;
|
||||
my $box = shift;
|
||||
my $pokemon = $self->pokemon;
|
||||
my $label = Gtk4::Label->new('Change the nickname:');
|
||||
my $entry = Gtk4::Entry->new;
|
||||
my $nickname = Rsaves::translate_3rd_encoding( $pokemon->nickname );
|
||||
my $box_nickname = Gtk4::Box->new( 'horizontal', 10 );
|
||||
$entry->get_buffer->set_text( $nickname, length $nickname );
|
||||
$entry->set_halign('start');
|
||||
$entry->set_valign('start');
|
||||
$label->set_halign('start');
|
||||
$label->set_valign('start');
|
||||
$box_nickname->append($label);
|
||||
$box_nickname->append($entry);
|
||||
$box->append($box_nickname);
|
||||
$self->onSave(
|
||||
sub {
|
||||
my $translated_nickname =
|
||||
Rsaves::to_3rd_encoding( $entry->get_buffer->get_text );
|
||||
if ( length $translated_nickname < 10 ) {
|
||||
$translated_nickname .= chr(0xff);
|
||||
my $length = length $translated_nickname;
|
||||
$translated_nickname .= ( chr(0x00) ) x ( 10 - $length );
|
||||
}
|
||||
if ( length $translated_nickname > 10 ) {
|
||||
$translated_nickname = substr $translated_nickname, 0, 10;
|
||||
}
|
||||
$pokemon->nickname($translated_nickname);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
sub draw_dropdown_pokemon_list {
|
||||
my $self = shift;
|
||||
my $box = shift;
|
||||
my $pokemon = $self->pokemon;
|
||||
my $button_box = Gtk4::Box->new( 'horizontal', 1 );
|
||||
my $box_popover = Gtk4::Box->new( 'vertical', 1 );
|
||||
my $search_bar = Gtk4::SearchBar->new;
|
||||
my $entry_search = Gtk4::SearchEntry->new;
|
||||
my $button = Gtk4::ToggleButton->new;
|
||||
my $popover_dropdown = Gtk4::Popover->new;
|
||||
my $label_pokemon =
|
||||
$self->label_pokemon( $pokemon->pokemon_name, $button_box );
|
||||
my $scroll = Gtk4::ScrolledWindow->new;
|
||||
my $box_pokemons = Gtk4::Box->new( 'vertical', 1 );
|
||||
my @species = (@Rsaves::Constants::Emerald::Species::SPECIES);
|
||||
|
||||
my $func_on_select_dropdown = sub {
|
||||
my $number = shift;
|
||||
$label_pokemon->set_text( $species[$number] );
|
||||
$self->_selected_species($number);
|
||||
$popover_dropdown->popdown;
|
||||
};
|
||||
$entry_search->signal_connect(
|
||||
'search-changed' => sub {
|
||||
my $box_pokemons = Gtk4::Box->new( 'vertical', 1 );
|
||||
$box_pokemons->set_vexpand(1);
|
||||
$self->fill_dropdown( $box_pokemons, $func_on_select_dropdown,
|
||||
$entry_search->get_text );
|
||||
$scroll->set_child($box_pokemons);
|
||||
}
|
||||
);
|
||||
|
||||
$button_box->append($label_pokemon);
|
||||
$button_box->append( Gtk4::Image->new_from_icon_name('pan-down-symbolic') );
|
||||
$button->set_child($button_box);
|
||||
$search_bar->set_child($entry_search);
|
||||
$search_bar->set_search_mode(1);
|
||||
$box_popover->append($search_bar);
|
||||
$box_pokemons->set_vexpand(1);
|
||||
$self->fill_dropdown( $box_pokemons, $func_on_select_dropdown );
|
||||
$scroll->set_child($box_pokemons);
|
||||
$box_popover->append($scroll);
|
||||
$box_popover->set_vexpand(1);
|
||||
$popover_dropdown->set_child($box_popover);
|
||||
$button->signal_connect(
|
||||
clicked => sub {
|
||||
$popover_dropdown->popup;
|
||||
}
|
||||
);
|
||||
$popover_dropdown->set_size_request( 100, 400 );
|
||||
$button_box->append($popover_dropdown);
|
||||
my $label_button = Gtk4::Label->new('Change species:');
|
||||
my $box_dropdown = Gtk4::Box->new( 'horizontal', 10 );
|
||||
$box_dropdown->append($label_button);
|
||||
$box_dropdown->append($button);
|
||||
$box->append($box_dropdown);
|
||||
$label_button->set_valign('start');
|
||||
$label_button->set_halign('start');
|
||||
$button->set_valign('start');
|
||||
$button->set_halign('start');
|
||||
}
|
||||
|
||||
sub fill_dropdown {
|
||||
my $self = shift;
|
||||
my $box = shift;
|
||||
my $func = shift;
|
||||
my $filter = shift;
|
||||
my @species = (@Rsaves::Constants::Emerald::Species::SPECIES);
|
||||
for ( my $i = 0 ; $i < scalar @species ; $i++ ) {
|
||||
my $number = $i;
|
||||
if ( defined $filter
|
||||
&& !( index( lc( $species[$i] ), lc($filter) ) >= 0 ) )
|
||||
{
|
||||
next;
|
||||
}
|
||||
my $label = Gtk4::Button->new_with_label( $species[$i] );
|
||||
my $controller_gesture = Gtk4::GestureClick->new;
|
||||
$controller_gesture->set_button(1);
|
||||
$controller_gesture->signal_connect(
|
||||
pressed => sub {
|
||||
$func->($number);
|
||||
}
|
||||
);
|
||||
$label->add_controller($controller_gesture);
|
||||
$box->append($label);
|
||||
}
|
||||
}
|
||||
|
||||
sub label_pokemon {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $button_box = shift;
|
||||
my $label = Gtk4::Label->new($name);
|
||||
$label->set_hexpand(1);
|
||||
$label->set_halign('start');
|
||||
return $label;
|
||||
}
|
||||
1;
|
436
lib/GEmeTool/View/PokemonPCWindow.pm
Normal file
@ -0,0 +1,436 @@
|
||||
package GEmeTool::View::PokemonPCWindow;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Cairo::GObject;
|
||||
use Glib;
|
||||
use Glib::Object::Introspection;
|
||||
use Glib::IO;
|
||||
use Path::Tiny;
|
||||
use Math::Trig;
|
||||
use Rsaves;
|
||||
|
||||
use Moo;
|
||||
|
||||
use GEmeTool::View::PokemonEditorWindow;
|
||||
|
||||
Glib::Object::Introspection->setup(
|
||||
basename => 'Gtk',
|
||||
version => '4.0',
|
||||
package => 'Gtk4',
|
||||
);
|
||||
|
||||
Glib::Object::Introspection->setup(
|
||||
basename => 'Gdk',
|
||||
version => '4.0',
|
||||
package => 'Gdk',
|
||||
);
|
||||
|
||||
has _save => (
|
||||
is => 'ro',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has _win => (
|
||||
is => 'rw',
|
||||
);
|
||||
|
||||
has _current_box => ( is => 'rw', );
|
||||
|
||||
my $BOX_X = 275;
|
||||
my $BOX_Y = 50;
|
||||
my $BOX_WIDTH = 312;
|
||||
my $BOX_HEIGHT = 340;
|
||||
|
||||
my $ARROW_X = 28;
|
||||
my $ARROW_Y = 6;
|
||||
my $ARROW_WIDTH = 16;
|
||||
my $ARROW_HEIGHT = 32;
|
||||
my ($CLOSE_BOX_X, $CLOSE_BOX_Y, $CLOSE_BOX_WIDTH, $CLOSE_BOX_HEIGHT) = (420, 0, 180, 40);
|
||||
|
||||
has _cursor_position => ( is => 'rw' );
|
||||
|
||||
my $root = path(__FILE__)->parent->parent->parent->parent;
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
my $gtk_window = Gtk4::Window->new;
|
||||
$self->_win($gtk_window);
|
||||
my $controller_motion = Gtk4::EventControllerMotion->new;
|
||||
my $controller_gesture = Gtk4::GestureClick->new;
|
||||
my $save = $self->_save;
|
||||
my $pc = $save->get_pc_system;
|
||||
my $box = $pc->get_box(0);
|
||||
my $headerbar = Gtk4::HeaderBar->new;
|
||||
$headerbar->set_decoration_layout('');
|
||||
my $title_grid = Gtk4::Grid->new;
|
||||
$title_grid->attach(Gtk4::Label->new('Pokémon Storage System'), 0, 0, 12, 1);
|
||||
my $save_button = Gtk4::Button->new_with_label('Save');
|
||||
$save_button->signal_connect(clicked => sub {
|
||||
$self->_save->get_pc_system->save;
|
||||
});
|
||||
$title_grid->attach($save_button, 0, 1, 2, 1);
|
||||
$headerbar->set_title_widget($title_grid);
|
||||
$gtk_window->set_titlebar($headerbar);
|
||||
$controller_gesture->set_button(1);
|
||||
$self->_current_box($box);
|
||||
$controller_gesture->signal_connect(
|
||||
pressed => sub {
|
||||
$self->_on_primary_click(@_);
|
||||
}
|
||||
);
|
||||
$controller_motion->signal_connect(
|
||||
motion => sub {
|
||||
my ( $x, $y ) = @_[ 1, 2 ];
|
||||
$self->_cursor_position( [ $x, $y ] );
|
||||
}
|
||||
);
|
||||
my $canvas = Gtk4::DrawingArea->new;
|
||||
$canvas->add_controller($controller_motion);
|
||||
$canvas->add_controller($controller_gesture);
|
||||
my $scale_factor_pc = 2.5;
|
||||
my ( $width, $height ) = map { $_ * $scale_factor_pc } ( 256, 158 );
|
||||
$gtk_window->set_default_size( $width, $height );
|
||||
$gtk_window->set_resizable(0);
|
||||
$canvas->set_draw_func(
|
||||
sub {
|
||||
my $canvas = shift;
|
||||
my $cairo = shift;
|
||||
my $width = shift;
|
||||
my $height = shift;
|
||||
|
||||
my $selected_pokemon = $self->get_selected_pokemon;
|
||||
$self->draw_pc( $cairo, $scale_factor_pc );
|
||||
{
|
||||
my $output_box =
|
||||
Cairo::ImageSurface->create( 'argb32', $BOX_WIDTH,
|
||||
$BOX_HEIGHT );
|
||||
my $box_context = Cairo::Context->create($output_box);
|
||||
$self->draw_box($box_context);
|
||||
$self->draw_pokemon( $box_context, $selected_pokemon );
|
||||
$self->draw_box_name($box_context);
|
||||
$cairo->set_source_surface( $output_box, $BOX_X, $BOX_Y );
|
||||
$cairo->paint;
|
||||
}
|
||||
$self->draw_pokemon_details( $cairo, $selected_pokemon );
|
||||
$self->draw_not_implemented($cairo);
|
||||
$self->draw_cursor($cairo);
|
||||
}
|
||||
);
|
||||
$gtk_window->set_child($canvas);
|
||||
$gtk_window->present;
|
||||
Glib::Timeout->add(
|
||||
1000 / 15,
|
||||
sub {
|
||||
$canvas->queue_draw;
|
||||
return 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
sub draw_not_implemented {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
$cairo->rectangle(200, 0, 180, 40);
|
||||
$cairo->set_source_rgb(0, 0, 0);
|
||||
$cairo->fill;
|
||||
$cairo->set_source_rgb(1, 1, 1);
|
||||
$cairo->set_font_size(20);
|
||||
$cairo->move_to( 200, 30);
|
||||
$cairo->text_path("Not implemented");
|
||||
$cairo->fill;
|
||||
}
|
||||
|
||||
|
||||
sub _on_primary_click {
|
||||
my $self = shift;
|
||||
my ( $gesture, $n_press, $x, $y ) = @_;
|
||||
return if $self->_check_click_next_prev_box( $gesture, $n_press, $x, $y );
|
||||
return if $self->_check_click_close_box($gesture, $n_press, $x, $y);
|
||||
return if $self->_check_selected_pokemon;
|
||||
}
|
||||
|
||||
sub _check_selected_pokemon {
|
||||
my $self = shift;
|
||||
if (defined $self->get_selected_pokemon) {
|
||||
my $editor = GEmeTool::View::PokemonEditorWindow->new(pokemon => $self->get_selected_pokemon);
|
||||
$editor->start;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _check_click_close_box {
|
||||
my $self = shift;
|
||||
my ( $gesture, $n_press, $x, $y ) = @_;
|
||||
my $match_x = $x >= $CLOSE_BOX_X && $x <= $CLOSE_BOX_WIDTH + $CLOSE_BOX_X;
|
||||
my $match_y = $y >= $CLOSE_BOX_Y && $y <= $CLOSE_BOX_HEIGHT + $CLOSE_BOX_Y;
|
||||
if ($match_x && $match_y) {
|
||||
$self->_win->close;
|
||||
return 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub _check_click_next_prev_box {
|
||||
my $self = shift;
|
||||
my ( $gesture, $n_press, $x, $y ) = @_;
|
||||
|
||||
return if $x < $BOX_X;
|
||||
return if $y < $BOX_Y;
|
||||
|
||||
$x -= $BOX_X;
|
||||
$y -= $BOX_Y;
|
||||
|
||||
return if $x >= $BOX_WIDTH;
|
||||
return if $y >= $BOX_HEIGHT;
|
||||
|
||||
my $x_matches =
|
||||
$x >= $BOX_WIDTH - $ARROW_X && $x <= $BOX_WIDTH - $ARROW_X + $ARROW_WIDTH;
|
||||
my $y_matches = $y >= $ARROW_Y && $y <= $ARROW_Y + $ARROW_HEIGHT;
|
||||
if ( $x_matches && $y_matches ) {
|
||||
my $box = $self->_current_box;
|
||||
my $save = $self->_save;
|
||||
my $pc = $save->get_pc_system;
|
||||
if ( $box->number == 13 ) {
|
||||
$self->_current_box( $pc->get_box(0) );
|
||||
return 1;
|
||||
}
|
||||
$self->_current_box( $pc->get_box( $box->number + 1 ) );
|
||||
return 1;
|
||||
}
|
||||
$x_matches = $x >= $ARROW_X - $ARROW_WIDTH && $x <= $ARROW_X;
|
||||
$y_matches = $y >= $ARROW_Y && $y <= $ARROW_Y + $ARROW_HEIGHT;
|
||||
if ( $x_matches && $y_matches ) {
|
||||
my $box = $self->_current_box;
|
||||
my $save = $self->_save;
|
||||
my $pc = $save->get_pc_system;
|
||||
if ( $box->number == 0 ) {
|
||||
$self->_current_box( $pc->get_box(13) );
|
||||
return 1;
|
||||
}
|
||||
$self->_current_box( $pc->get_box( $box->number - 1 ) );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub draw_pokemon_details {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
my $selected_pokemon = shift;
|
||||
return if !defined $selected_pokemon;
|
||||
return if $selected_pokemon->species == 0;
|
||||
my $output_image = Cairo::ImageSurface->create( 'argb32', 64, 64 );
|
||||
my $image_context = Cairo::Context->create($output_image);
|
||||
my $surface = Cairo::ImageSurface->create_from_png(
|
||||
$root->child( $selected_pokemon->get_front ) );
|
||||
my $scale_factor = 2;
|
||||
$cairo->scale( ($scale_factor) x 2 );
|
||||
$image_context->set_source_surface( $surface, 0, 0 );
|
||||
$image_context->get_source()->set_filter('nearest');
|
||||
$image_context->paint;
|
||||
$cairo->set_source_surface( $output_image, 20, 30 );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
|
||||
my $pokemon_species = $Rsaves::Constants::Emerald::Species::SPECIES[$selected_pokemon->species];
|
||||
$cairo->select_font_face( 'Sans', 'normal', 'normal' );
|
||||
$cairo->set_source_rgb( 1, 1, 1 );
|
||||
$cairo->set_font_size(8);
|
||||
$cairo->move_to( 5, 120 );
|
||||
$cairo->text_path(Rsaves::translate_3rd_encoding($selected_pokemon->nickname));
|
||||
$cairo->fill;
|
||||
|
||||
$cairo->move_to( 5, 128 );
|
||||
$cairo->text_path('/'.$pokemon_species);
|
||||
$cairo->set_source_rgb( 1, 1, 1 );
|
||||
$cairo->fill;
|
||||
# $cairo->set_source_rgb( 0, 0, 0 );
|
||||
# $cairo->set_line_width(0.8);
|
||||
# $cairo->stroke;
|
||||
$cairo->move_to( 6, 140 );
|
||||
my $gender = $selected_pokemon->gender;
|
||||
$cairo->set_font_size(15);
|
||||
if ($gender == 0) {
|
||||
$cairo->text_path("♂");
|
||||
$cairo->set_source_rgb( 0, 0, 1 );
|
||||
$cairo->fill;
|
||||
}
|
||||
if ($gender == 1) {
|
||||
$cairo->text_path("♀");
|
||||
$cairo->set_source_rgb( 1, 0, 0 );
|
||||
$cairo->fill;
|
||||
}
|
||||
$cairo->set_source_rgb( 1, 1, 1 );
|
||||
$cairo->set_font_size(8);
|
||||
$cairo->move_to( 18, 138 );
|
||||
$cairo->text_path("Lv@{[$selected_pokemon->level]}");
|
||||
$cairo->set_source_rgb( 1, 1, 1 );
|
||||
$cairo->fill;
|
||||
|
||||
$cairo->scale( ( 1 / $scale_factor ) x 2 );
|
||||
|
||||
}
|
||||
|
||||
sub draw_pc {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
my $scale_factor = shift;
|
||||
$cairo->scale( ($scale_factor) x 2 );
|
||||
my $surface = Cairo::ImageSurface->create_from_png(
|
||||
$root->child('resources/pc_background.png') );
|
||||
$cairo->set_source_surface( $surface, 0, 0 );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
$cairo->scale( ( 1 / $scale_factor ) x 2 );
|
||||
}
|
||||
|
||||
sub draw_cursor {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
my $cursor_png = $root->child('resources/hand_cursor.png');
|
||||
my $surface = Cairo::ImageSurface->create_from_png($cursor_png);
|
||||
my $output_image = Cairo::ImageSurface->create( 'argb32', 32, 32 );
|
||||
my $image_context = Cairo::Context->create($output_image);
|
||||
my $cursor_position = $self->_cursor_position;
|
||||
return if !defined $cursor_position;
|
||||
my $scale_factor = 0.95 * 2;
|
||||
$cairo->scale( ($scale_factor) x 2 );
|
||||
my ( $x, $y ) = map { $_ / $scale_factor } @$cursor_position;
|
||||
$x -= 10;
|
||||
$y -= 20;
|
||||
$image_context->set_source_surface( $surface, 0, 0 );
|
||||
$image_context->get_source()->set_filter('nearest');
|
||||
$image_context->paint;
|
||||
my $p = 25;
|
||||
$cairo->set_source_surface( $output_image, $x, $y, );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
$cairo->scale( ( 1 / $scale_factor ) x 2 );
|
||||
}
|
||||
|
||||
sub draw_box_name {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
my $save = $self->_save;
|
||||
my $pc = $save->get_pc_system;
|
||||
my $box = $self->_current_box;
|
||||
my $name = Rsaves::translate_3rd_encoding( $box->name );
|
||||
my $scale_factor = 0.95 * 2;
|
||||
$cairo->scale( $scale_factor, $scale_factor );
|
||||
$cairo->set_source_rgb( 0, 0, 0 );
|
||||
$cairo->select_font_face( 'monospace', 'normal', 'normal' );
|
||||
$cairo->set_font_size(20);
|
||||
$cairo->move_to( 75 - ( length($name) * 5 ), 19 );
|
||||
$cairo->show_text($name);
|
||||
$cairo->scale( ( 1 / $scale_factor ) x 2 );
|
||||
}
|
||||
|
||||
sub draw_pokemon {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
my $selected_pokemon = shift;
|
||||
my $save = $self->_save;
|
||||
my $pc = $save->get_pc_system;
|
||||
my $box = $self->_current_box;
|
||||
my $scale_factor = 0.95 * 2;
|
||||
$cairo->scale( $scale_factor, $scale_factor );
|
||||
|
||||
for ( my $i = 0 ; $i < 5 ; $i++ ) {
|
||||
|
||||
# ROW
|
||||
for ( my $j = 0 ; $j < 6 ; $j++ ) {
|
||||
|
||||
# COLUMN
|
||||
my $pokemon = $box->get_pokemon( $i * 6 + $j );
|
||||
my $is_selected =
|
||||
defined $selected_pokemon && $pokemon eq $selected_pokemon;
|
||||
my $pokemon_image = $root->child( $pokemon->get_icon );
|
||||
my $p = 25;
|
||||
my $x = $j * ( $p + 1 );
|
||||
my $y = 20 + ( ( $p - 3 ) * $i );
|
||||
|
||||
if ($is_selected) {
|
||||
$cairo->set_source_rgb( 1, 1, 0 );
|
||||
$cairo->arc( $x + 5 + 11, $y + 10 + 11, 22 / 2, 0, pi * 2 );
|
||||
$cairo->fill;
|
||||
}
|
||||
|
||||
my $surface = Cairo::ImageSurface->create_from_png($pokemon_image);
|
||||
my $output_image = Cairo::ImageSurface->create( 'argb32', 32, 32 );
|
||||
my $image_context = Cairo::Context->create($output_image);
|
||||
$image_context->set_source_surface( $surface, 0, 0 );
|
||||
$image_context->get_source()->set_filter('nearest');
|
||||
$image_context->paint;
|
||||
$cairo->set_source_surface( $output_image, $x, $y );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
}
|
||||
}
|
||||
$cairo->scale( ( 1 / $scale_factor ) x 2 );
|
||||
}
|
||||
|
||||
sub get_selected_pokemon {
|
||||
my $self = shift;
|
||||
my $cursor_position = $self->_cursor_position;
|
||||
return if !defined $cursor_position;
|
||||
my ( $x, $y ) = @$cursor_position;
|
||||
|
||||
return if $x < $BOX_X;
|
||||
return if $y < $BOX_Y;
|
||||
|
||||
$x -= $BOX_X;
|
||||
$y -= $BOX_Y;
|
||||
|
||||
return if $x >= $BOX_WIDTH - 13;
|
||||
return if $y >= $BOX_HEIGHT;
|
||||
|
||||
my $scale_factor = 0.95 * 2;
|
||||
( $x, $y ) = map { $_ / $scale_factor } ( $x, $y );
|
||||
return if $y <= 20;
|
||||
$y -= 20;
|
||||
|
||||
my $p = 25;
|
||||
my $i = int( $y / ( $p - 3 ) );
|
||||
my $j = int( $x / ( $p + 1 ) );
|
||||
my $save = $self->_save;
|
||||
my $pc = $save->get_pc_system;
|
||||
my $box = $self->_current_box;
|
||||
my $number = $i * 6 + $j;
|
||||
return if $number > 29;
|
||||
my $pokemon = $box->get_pokemon($number);
|
||||
return $pokemon;
|
||||
}
|
||||
|
||||
sub draw_box {
|
||||
my $self = shift;
|
||||
my $cairo = shift;
|
||||
my $surface = Cairo::ImageSurface->create_from_png(
|
||||
$root->child('resources/forest.png') );
|
||||
|
||||
$cairo->scale( 2, 2 );
|
||||
$cairo->set_source_surface( $surface, 0, 0 );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
|
||||
$cairo->paint;
|
||||
$surface = Cairo::ImageSurface->create_from_png(
|
||||
$root->child('resources/right_arrow_pc.png') );
|
||||
$cairo->set_source_surface(
|
||||
$surface,
|
||||
$BOX_WIDTH / 2 - $ARROW_X / 2,
|
||||
$ARROW_Y / 2
|
||||
);
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
$cairo->scale( -1, 1 );
|
||||
$cairo->set_source_surface( $surface, -$ARROW_X / 2, $ARROW_Y / 2 );
|
||||
$cairo->get_source()->set_filter('nearest');
|
||||
$cairo->paint;
|
||||
$cairo->scale( -1, 1 );
|
||||
$cairo->scale( 1 / 2, 1 / 2 );
|
||||
|
||||
}
|
||||
1;
|
173
lib/Rsaves.pm
@ -8,15 +8,18 @@ use warnings;
|
||||
use feature 'signatures';
|
||||
|
||||
use Data::Dumper;
|
||||
use utf8;
|
||||
|
||||
use Rsaves::Constants::Ruby::Flags
|
||||
qw/$FLAG_SYS_HAS_EON_TICKET $FLAG_LEGENDARY_BATTLE_COMPLETED $FLAG_HIDE_LEGEND_MON_CAVE_OF_ORIGIN/;
|
||||
use Rsaves::Constants::Ruby::Vars qw/ $VAR_MIRAGE_RND_H $VAR_CAVE_OF_ORIGIN_B4F_STATE $VARS_START/;
|
||||
use Rsaves::Constants::Ruby::Vars
|
||||
qw/ $VAR_MIRAGE_RND_H $VAR_CAVE_OF_ORIGIN_B4F_STATE $VARS_START/;
|
||||
use Rsaves::Constants::Global
|
||||
qw/$SAPPHIRE_VERSION $RUBY_VERSION $EMERALD_VERSION $FIRERED_VERSION $LEAFGREEN_VERSION $COLOSSEUM_VERSION/;
|
||||
|
||||
use Rsaves::Constants::Firered::Flags qw/$FLAG_RECEIVED_AURORA_TICKET $FLAG_ENABLE_SHIP_BIRTH_ISLAND $FLAG_FOUGHT_DEOXYS $FLAG_DEOXYS_FLEW_AWAY/;
|
||||
use Rsaves::Constants::Firered::Vars qw/$VAR_MAP_SCENE_CERULEAN_CITY_RIVAL/;
|
||||
use Rsaves::Constants::Firered::Flags
|
||||
qw/$FLAG_RECEIVED_AURORA_TICKET $FLAG_ENABLE_SHIP_BIRTH_ISLAND $FLAG_FOUGHT_DEOXYS $FLAG_DEOXYS_FLEW_AWAY/;
|
||||
use Rsaves::Constants::Firered::Vars qw/$VAR_MAP_SCENE_CERULEAN_CITY_RIVAL/;
|
||||
use Rsaves::Constants::MoveAttributes qw/get_move_attributes/;
|
||||
use Exporter;
|
||||
|
||||
@ -57,22 +60,22 @@ my $PC_BUFFER_G = 11;
|
||||
my $PC_BUFFER_H = 12;
|
||||
my $PC_BUFFER_I = 13;
|
||||
my ( $FEMALE, $MALE ) = ( 1, 0 );
|
||||
my $FLAGS_OFFSET_RUBY = hex '1220';
|
||||
my $FLAGS_OFFSET_FIRERED = 0x0ee0;
|
||||
my $FLAGS_OFFSET_EMERALD = 0x1270;
|
||||
my $TRAINER_FLAG_START = hex '500';
|
||||
my $NUMBER_OF_TRAINERS = 693;
|
||||
my $KEY_ITEMS_OFFSET_RUBY = 0x5b0;
|
||||
my $KEY_ITEMS_OFFSET_FIRERED = 0x03b8;
|
||||
my $MAX_KEY_ITEMS_RUBY = 20;
|
||||
my $MAX_KEY_ITEMS_FIRERED = 30;
|
||||
my $ITEM_EON_TICKET = 275;
|
||||
my $ITEM_AURORA_TICKET = 371;
|
||||
my $POKEMON_NAME_LENGTH = 10;
|
||||
my $OT_NAME_LENGTH = 7;
|
||||
my $BOX_NAME_LENGTH = 9;
|
||||
my $RUBY_VARS_START = 0x1340;
|
||||
my $FIRERED_VARS_START = 0x1000;
|
||||
my $FLAGS_OFFSET_RUBY = hex '1220';
|
||||
my $FLAGS_OFFSET_FIRERED = 0x0ee0;
|
||||
my $FLAGS_OFFSET_EMERALD = 0x1270;
|
||||
my $TRAINER_FLAG_START = hex '500';
|
||||
my $NUMBER_OF_TRAINERS = 693;
|
||||
my $KEY_ITEMS_OFFSET_RUBY = 0x5b0;
|
||||
my $KEY_ITEMS_OFFSET_FIRERED = 0x03b8;
|
||||
my $MAX_KEY_ITEMS_RUBY = 20;
|
||||
my $MAX_KEY_ITEMS_FIRERED = 30;
|
||||
my $ITEM_EON_TICKET = 275;
|
||||
my $ITEM_AURORA_TICKET = 371;
|
||||
my $POKEMON_NAME_LENGTH = 10;
|
||||
my $OT_NAME_LENGTH = 7;
|
||||
my $BOX_NAME_LENGTH = 9;
|
||||
my $RUBY_VARS_START = 0x1340;
|
||||
my $FIRERED_VARS_START = 0x1000;
|
||||
|
||||
my %CHECKSUM_BYTES = (
|
||||
$TRAINER_INFO => hex 'F80',
|
||||
@ -114,9 +117,11 @@ sub parse_version_name {
|
||||
}
|
||||
|
||||
sub pokemon_fill_pp($pokemon) {
|
||||
|
||||
# Not taking pp bonuses in account, work for other day.
|
||||
for my $number_movement (0..3) {
|
||||
my $movement_id = $pokemon->{substructures}[1]{movements}[$number_movement];
|
||||
for my $number_movement ( 0 .. 3 ) {
|
||||
my $movement_id =
|
||||
$pokemon->{substructures}[1]{movements}[$number_movement];
|
||||
my $pp = get_move_attributes($movement_id)->{'pp'};
|
||||
$pokemon->{substructures}[1]{pp}[$number_movement] = $pp;
|
||||
}
|
||||
@ -137,6 +142,18 @@ sub calculate_shiny_personality {
|
||||
return ( $wanted_high_personality << 16 ) | _lowhalf_u32($personality);
|
||||
}
|
||||
|
||||
sub pokemon_is_shiny {
|
||||
my $pokemon = shift;
|
||||
return is_shiny(@{$pokemon}{ 'otid', 'personality' });
|
||||
}
|
||||
|
||||
sub is_shiny {
|
||||
my $otid = shift;
|
||||
my $personality = shift;
|
||||
return ( _lowhalf_u32($personality) ^ _hihalf_u32($personality)
|
||||
^ _lowhalf_u32($otid) ^ _hihalf_u32($otid) ) < 8;
|
||||
}
|
||||
|
||||
sub get_first_super_data {
|
||||
my $save = shift;
|
||||
my @sections = _find_sections_save( $save, 1 .. 4 );
|
||||
@ -273,11 +290,11 @@ sub _write_pokemon_fh {
|
||||
print $fh pack 'V', $pokemon->{personality};
|
||||
print $fh pack 'V', $pokemon->{otid};
|
||||
my $nickname = $pokemon->{nickname};
|
||||
if (length $nickname < 10) {
|
||||
if ( length $nickname < 10 ) {
|
||||
$nickname .= chr(0xff);
|
||||
my $to_add = 10 - length $nickname;
|
||||
for (my $i = 0; $i < $to_add; $i++) {
|
||||
$nickname .= chr(int(rand(256)));
|
||||
for ( my $i = 0 ; $i < $to_add ; $i++ ) {
|
||||
$nickname .= chr( int( rand(256) ) );
|
||||
}
|
||||
}
|
||||
print $fh $nickname;
|
||||
@ -430,7 +447,7 @@ sub _pokemon_checksum_substructures_fh {
|
||||
for ( 0 .. 3 ) {
|
||||
for ( 0 .. 5 ) {
|
||||
read $fh, my $read, 2 or die "Unable to read";
|
||||
$checksum = 0xffff & (( unpack 'v', $read ) + $checksum );
|
||||
$checksum = 0xffff & ( ( unpack 'v', $read ) + $checksum );
|
||||
}
|
||||
}
|
||||
return $checksum;
|
||||
@ -464,10 +481,20 @@ sub _write_pokemon_substruct_fh {
|
||||
$translate_real_table{$char} = chr($counter);
|
||||
$counter++;
|
||||
}
|
||||
$counter = 0xa1;
|
||||
for my $char ( '0' .. '9' ) {
|
||||
$translate_encoding_table{ chr($counter) } = $char;
|
||||
$translate_real_table{$char} = chr($counter);
|
||||
$counter++;
|
||||
}
|
||||
$translate_real_table{'♂'} = chr(0xB5);
|
||||
$translate_real_table{'♀'} = chr(0xB6);
|
||||
$translate_real_table{'-'} = chr(0xae);
|
||||
$translate_real_table{'.'} = chr(0xad);
|
||||
$translate_encoding_table{ chr(0xB5) } = '♂';
|
||||
$translate_encoding_table{ chr(0xB6) } = '♀';
|
||||
$translate_encoding_table{ chr(0xae) } = '-';
|
||||
$translate_encoding_table{ chr(0xad) } = '.';
|
||||
}
|
||||
|
||||
sub to_3rd_encoding {
|
||||
@ -791,12 +818,12 @@ sub enable_eon_ticket {
|
||||
sub match_again_rival_firered_cerulean {
|
||||
my $save = shift;
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
my $version = $section0->{version};
|
||||
die "This is not Pokemon Leafgreen or Firered"
|
||||
if !_is_leafgreen_or_firered($version);
|
||||
if !_is_leafgreen_or_firered($version);
|
||||
my $superdata = get_first_super_data($save);
|
||||
set_var( $save, $superdata, $VAR_MAP_SCENE_CERULEAN_CITY_RIVAL, 0 );
|
||||
set_first_super_data($save, $superdata);
|
||||
set_var( $save, $superdata, $VAR_MAP_SCENE_CERULEAN_CITY_RIVAL, 0 );
|
||||
set_first_super_data( $save, $superdata );
|
||||
}
|
||||
|
||||
sub enable_deoxys_firered {
|
||||
@ -805,10 +832,10 @@ sub enable_deoxys_firered {
|
||||
die "This is not Pokemon Leafgreen or Firered"
|
||||
if !_is_leafgreen_or_firered( $section0->{version} );
|
||||
my $superdata = get_first_super_data($save);
|
||||
set_flag_id( $save, $superdata, $FLAG_RECEIVED_AURORA_TICKET, 1 );
|
||||
set_flag_id( $save, $superdata, $FLAG_RECEIVED_AURORA_TICKET, 1 );
|
||||
set_flag_id( $save, $superdata, $FLAG_ENABLE_SHIP_BIRTH_ISLAND, 1 );
|
||||
set_flag_id( $save, $superdata, $FLAG_FOUGHT_DEOXYS, 0 );
|
||||
set_flag_id( $save, $superdata, $FLAG_DEOXYS_FLEW_AWAY, 0 );
|
||||
set_flag_id( $save, $superdata, $FLAG_FOUGHT_DEOXYS, 0 );
|
||||
set_flag_id( $save, $superdata, $FLAG_DEOXYS_FLEW_AWAY, 0 );
|
||||
add_key_item( $save, $superdata, $ITEM_AURORA_TICKET );
|
||||
set_first_super_data( $save, $superdata );
|
||||
}
|
||||
@ -857,14 +884,15 @@ sub enable_rematch_main_legendary {
|
||||
sub get_security_key {
|
||||
my $save = shift;
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
my $data = $section0->{data};
|
||||
my $version = $section0->{version};
|
||||
my $data = $section0->{data};
|
||||
open my $fh, '<', \$data;
|
||||
if (_is_leafgreen_or_firered($version)) {
|
||||
if ( _is_leafgreen_or_firered($version) ) {
|
||||
read $fh, my $read, 0xf20;
|
||||
read $fh, $read, 4;
|
||||
read $fh, $read, 4;
|
||||
return unpack 'V', $read;
|
||||
} elsif (_is_ruby_or_sapphire($version)) {
|
||||
}
|
||||
elsif ( _is_ruby_or_sapphire($version) ) {
|
||||
return 0;
|
||||
}
|
||||
close $fh;
|
||||
@ -876,13 +904,14 @@ sub add_key_item {
|
||||
my $superdata = shift;
|
||||
my $item_id = shift;
|
||||
my $result = '';
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
open my $fh, '<', $superdata;
|
||||
my $offset = $KEY_ITEMS_OFFSET_RUBY;
|
||||
my $offset = $KEY_ITEMS_OFFSET_RUBY;
|
||||
my $max_key_items = $MAX_KEY_ITEMS_RUBY;
|
||||
if (_is_leafgreen_or_firered($version)) {
|
||||
$offset = $KEY_ITEMS_OFFSET_FIRERED;
|
||||
|
||||
if ( _is_leafgreen_or_firered($version) ) {
|
||||
$offset = $KEY_ITEMS_OFFSET_FIRERED;
|
||||
$max_key_items = $MAX_KEY_ITEMS_FIRERED;
|
||||
}
|
||||
read $fh, my ($read), $offset;
|
||||
@ -899,7 +928,7 @@ sub add_key_item {
|
||||
}
|
||||
$result .= $read;
|
||||
read $fh, $read, 2;
|
||||
my $quantity = get_security_key($save) ^ (unpack 'v', $read);
|
||||
my $quantity = get_security_key($save) ^ ( unpack 'v', $read );
|
||||
$result .= $read;
|
||||
if ( $found_item == $item_id ) {
|
||||
warn "$item_id already present with $quantity.";
|
||||
@ -914,16 +943,20 @@ sub add_key_item {
|
||||
}
|
||||
|
||||
sub get_var {
|
||||
my $save = shift;
|
||||
my $superdata = shift;
|
||||
my $var = shift;
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $save = shift;
|
||||
my $superdata = shift;
|
||||
my $var = shift;
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
my $read_until = ( ( $var - $Rsaves::Constants::Ruby::Vars::VARS_START ) * 2 ) + $RUBY_VARS_START;
|
||||
if (_is_leafgreen_or_firered($version)) {
|
||||
$read_until = ( ( $var - $Rsaves::Constants::Firered::Vars::VARS_START ) * 2 ) + $FIRERED_VARS_START;
|
||||
my $read_until =
|
||||
( ( $var - $Rsaves::Constants::Ruby::Vars::VARS_START ) * 2 ) +
|
||||
$RUBY_VARS_START;
|
||||
if ( _is_leafgreen_or_firered($version) ) {
|
||||
$read_until =
|
||||
( ( $var - $Rsaves::Constants::Firered::Vars::VARS_START ) * 2 ) +
|
||||
$FIRERED_VARS_START;
|
||||
}
|
||||
if (_is_emerald($version)) {
|
||||
if ( _is_emerald($version) ) {
|
||||
die "Not implemented.";
|
||||
}
|
||||
open my $fh, '<', $superdata;
|
||||
@ -939,17 +972,22 @@ sub set_var {
|
||||
my $superdata = shift;
|
||||
my $var = shift;
|
||||
my $value = shift;
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
die "$value bigger than 0xffff" if $value > 0xffff;
|
||||
my $read_until = ( ( $var - $Rsaves::Constants::Ruby::Vars::VARS_START ) * 2 ) + $RUBY_VARS_START;
|
||||
if (_is_leafgreen_or_firered($version)) {
|
||||
$read_until = ( ( $var - $Rsaves::Constants::Firered::Vars::VARS_START ) * 2 ) + $FIRERED_VARS_START;
|
||||
my $read_until =
|
||||
( ( $var - $Rsaves::Constants::Ruby::Vars::VARS_START ) * 2 ) +
|
||||
$RUBY_VARS_START;
|
||||
|
||||
if ( _is_leafgreen_or_firered($version) ) {
|
||||
$read_until =
|
||||
( ( $var - $Rsaves::Constants::Firered::Vars::VARS_START ) * 2 ) +
|
||||
$FIRERED_VARS_START;
|
||||
}
|
||||
if (_is_emerald($version)) {
|
||||
if ( _is_emerald($version) ) {
|
||||
die "Not implemented.";
|
||||
}
|
||||
my $result = shift;
|
||||
my $result = shift;
|
||||
open my $fh, '<', $superdata;
|
||||
read $fh, ( my $read ), $read_until or die "Unable to read";
|
||||
$result .= $read;
|
||||
@ -969,7 +1007,7 @@ sub set_rematch {
|
||||
my $version = $section0->{version};
|
||||
my $offset = 0x9ca;
|
||||
|
||||
if (!_is_emerald($version)) {
|
||||
if ( !_is_emerald($version) ) {
|
||||
die 'Must be version emerald to do this.';
|
||||
}
|
||||
my $result = '';
|
||||
@ -999,10 +1037,10 @@ sub set_flag_id {
|
||||
my $version = $section0->{version};
|
||||
my $offset = int( $id / 8 ) + $FLAGS_OFFSET_RUBY;
|
||||
if ( _is_leafgreen_or_firered($version) ) {
|
||||
$offset = (int $id / 8 ) + $FLAGS_OFFSET_FIRERED;
|
||||
$offset = ( int $id / 8 ) + $FLAGS_OFFSET_FIRERED;
|
||||
}
|
||||
if ( _is_emerald($version) ) {
|
||||
$offset = (int $id / 8 ) + $FLAGS_OFFSET_EMERALD;
|
||||
$offset = ( int $id / 8 ) + $FLAGS_OFFSET_EMERALD;
|
||||
}
|
||||
my $result = '';
|
||||
open my $fh, '<', $superdata;
|
||||
@ -1029,12 +1067,12 @@ sub check_flag_id {
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
|
||||
my $offset = int( $id / 8 ) + $FLAGS_OFFSET_RUBY;
|
||||
my $offset = int( $id / 8 ) + $FLAGS_OFFSET_RUBY;
|
||||
if ( _is_leafgreen_or_firered($version) ) {
|
||||
$offset = int ($id / 8 ) + $FLAGS_OFFSET_FIRERED;
|
||||
$offset = int( $id / 8 ) + $FLAGS_OFFSET_FIRERED;
|
||||
}
|
||||
if (_is_emerald($version)) {
|
||||
$offset = (int $id / 8 ) + $FLAGS_OFFSET_EMERALD;
|
||||
if ( _is_emerald($version) ) {
|
||||
$offset = ( int $id / 8 ) + $FLAGS_OFFSET_EMERALD;
|
||||
}
|
||||
|
||||
my $flags_offset = unpack "x@{[$offset]} C", ${$superdata};
|
||||
@ -1048,11 +1086,11 @@ sub check_rematch {
|
||||
my $section0 = _find_section_save( $save, 0 );
|
||||
my $version = $section0->{version};
|
||||
|
||||
if (!_is_emerald($version)) {
|
||||
if ( !_is_emerald($version) ) {
|
||||
die 'Must be version emerald to do this.';
|
||||
}
|
||||
|
||||
my $offset = $id + 0x9ca - 1;
|
||||
my $offset = $id + 0x9ca - 1;
|
||||
|
||||
my $rematch_offset = unpack "x@{[$offset]} C", ${$superdata};
|
||||
return $rematch_offset;
|
||||
@ -1084,9 +1122,10 @@ sub _recalculate_checksum {
|
||||
my $readed = '';
|
||||
read $fh, $readed, 4;
|
||||
my $to_add = unpack 'V', $readed;
|
||||
$checksum = 0xffffffff & ($checksum + $to_add);
|
||||
$checksum = 0xffffffff & ( $checksum + $to_add );
|
||||
}
|
||||
my $final_checksum = (_hihalf_u32($checksum) + _lowhalf_u32($checksum)) & 0xffffffff;
|
||||
my $final_checksum =
|
||||
( _hihalf_u32($checksum) + _lowhalf_u32($checksum) ) & 0xffffffff;
|
||||
$section->{checksum} = $final_checksum;
|
||||
}
|
||||
|
||||
|
21
lib/Rsaves/Constants/Emerald/Natures.pm
Normal file
@ -0,0 +1,21 @@
|
||||
package Rsaves::Constants::Emerald::Natures;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @NATURES = (
|
||||
'HARDY', 'LONELY', 'BRAVE', 'ADAMANT', 'NAUGHTY', 'BOLD',
|
||||
'DOCILE', 'RELAXED', 'IMPISH', 'LAX', 'TIMID', 'HASTY',
|
||||
'SERIOUS', 'JOLLY', 'NAIVE', 'MODEST', 'MILD', 'QUIET',
|
||||
'BASHFUL', 'RASH', 'CALM', 'GENTLE', 'SASSY', 'CAREFUL',
|
||||
'QUIRKY',
|
||||
);
|
||||
|
||||
our %NATURE_TO_ID;
|
||||
for (my $i = 0; $i < scalar @NATURES; $i++) {
|
||||
my $nature = $NATURES[$i];
|
||||
$NATURE_TO_ID{$nature} = $i;
|
||||
}
|
||||
1;
|
532
lib/Rsaves/Constants/Emerald/Species.pm
Normal file
@ -0,0 +1,532 @@
|
||||
package Rsaves::Constants::Emerald::Species;
|
||||
|
||||
use v5.16.3;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $SPECIES_NONE = 0;
|
||||
our $SPECIES_BULBASAUR = 1;
|
||||
our $SPECIES_IVYSAUR = 2;
|
||||
our $SPECIES_VENUSAUR = 3;
|
||||
our $SPECIES_CHARMANDER = 4;
|
||||
our $SPECIES_CHARMELEON = 5;
|
||||
our $SPECIES_CHARIZARD = 6;
|
||||
our $SPECIES_SQUIRTLE = 7;
|
||||
our $SPECIES_WARTORTLE = 8;
|
||||
our $SPECIES_BLASTOISE = 9;
|
||||
our $SPECIES_CATERPIE = 10;
|
||||
our $SPECIES_METAPOD = 11;
|
||||
our $SPECIES_BUTTERFREE = 12;
|
||||
our $SPECIES_WEEDLE = 13;
|
||||
our $SPECIES_KAKUNA = 14;
|
||||
our $SPECIES_BEEDRILL = 15;
|
||||
our $SPECIES_PIDGEY = 16;
|
||||
our $SPECIES_PIDGEOTTO = 17;
|
||||
our $SPECIES_PIDGEOT = 18;
|
||||
our $SPECIES_RATTATA = 19;
|
||||
our $SPECIES_RATICATE = 20;
|
||||
our $SPECIES_SPEAROW = 21;
|
||||
our $SPECIES_FEAROW = 22;
|
||||
our $SPECIES_EKANS = 23;
|
||||
our $SPECIES_ARBOK = 24;
|
||||
our $SPECIES_PIKACHU = 25;
|
||||
our $SPECIES_RAICHU = 26;
|
||||
our $SPECIES_SANDSHREW = 27;
|
||||
our $SPECIES_SANDSLASH = 28;
|
||||
our $SPECIES_NIDORAN_F = 29;
|
||||
our $SPECIES_NIDORINA = 30;
|
||||
our $SPECIES_NIDOQUEEN = 31;
|
||||
our $SPECIES_NIDORAN_M = 32;
|
||||
our $SPECIES_NIDORINO = 33;
|
||||
our $SPECIES_NIDOKING = 34;
|
||||
our $SPECIES_CLEFAIRY = 35;
|
||||
our $SPECIES_CLEFABLE = 36;
|
||||
our $SPECIES_VULPIX = 37;
|
||||
our $SPECIES_NINETALES = 38;
|
||||
our $SPECIES_JIGGLYPUFF = 39;
|
||||
our $SPECIES_WIGGLYTUFF = 40;
|
||||
our $SPECIES_ZUBAT = 41;
|
||||
our $SPECIES_GOLBAT = 42;
|
||||
our $SPECIES_ODDISH = 43;
|
||||
our $SPECIES_GLOOM = 44;
|
||||
our $SPECIES_VILEPLUME = 45;
|
||||
our $SPECIES_PARAS = 46;
|
||||
our $SPECIES_PARASECT = 47;
|
||||
our $SPECIES_VENONAT = 48;
|
||||
our $SPECIES_VENOMOTH = 49;
|
||||
our $SPECIES_DIGLETT = 50;
|
||||
our $SPECIES_DUGTRIO = 51;
|
||||
our $SPECIES_MEOWTH = 52;
|
||||
our $SPECIES_PERSIAN = 53;
|
||||
our $SPECIES_PSYDUCK = 54;
|
||||
our $SPECIES_GOLDUCK = 55;
|
||||
our $SPECIES_MANKEY = 56;
|
||||
our $SPECIES_PRIMEAPE = 57;
|
||||
our $SPECIES_GROWLITHE = 58;
|
||||
our $SPECIES_ARCANINE = 59;
|
||||
our $SPECIES_POLIWAG = 60;
|
||||
our $SPECIES_POLIWHIRL = 61;
|
||||
our $SPECIES_POLIWRATH = 62;
|
||||
our $SPECIES_ABRA = 63;
|
||||
our $SPECIES_KADABRA = 64;
|
||||
our $SPECIES_ALAKAZAM = 65;
|
||||
our $SPECIES_MACHOP = 66;
|
||||
our $SPECIES_MACHOKE = 67;
|
||||
our $SPECIES_MACHAMP = 68;
|
||||
our $SPECIES_BELLSPROUT = 69;
|
||||
our $SPECIES_WEEPINBELL = 70;
|
||||
our $SPECIES_VICTREEBEL = 71;
|
||||
our $SPECIES_TENTACOOL = 72;
|
||||
our $SPECIES_TENTACRUEL = 73;
|
||||
our $SPECIES_GEODUDE = 74;
|
||||
our $SPECIES_GRAVELER = 75;
|
||||
our $SPECIES_GOLEM = 76;
|
||||
our $SPECIES_PONYTA = 77;
|
||||
our $SPECIES_RAPIDASH = 78;
|
||||
our $SPECIES_SLOWPOKE = 79;
|
||||
our $SPECIES_SLOWBRO = 80;
|
||||
our $SPECIES_MAGNEMITE = 81;
|
||||
our $SPECIES_MAGNETON = 82;
|
||||
our $SPECIES_FARFETCHD = 83;
|
||||
our $SPECIES_DODUO = 84;
|
||||
our $SPECIES_DODRIO = 85;
|
||||
our $SPECIES_SEEL = 86;
|
||||
our $SPECIES_DEWGONG = 87;
|
||||
our $SPECIES_GRIMER = 88;
|
||||
our $SPECIES_MUK = 89;
|
||||
our $SPECIES_SHELLDER = 90;
|
||||
our $SPECIES_CLOYSTER = 91;
|
||||
our $SPECIES_GASTLY = 92;
|
||||
our $SPECIES_HAUNTER = 93;
|
||||
our $SPECIES_GENGAR = 94;
|
||||
our $SPECIES_ONIX = 95;
|
||||
our $SPECIES_DROWZEE = 96;
|
||||
our $SPECIES_HYPNO = 97;
|
||||
our $SPECIES_KRABBY = 98;
|
||||
our $SPECIES_KINGLER = 99;
|
||||
our $SPECIES_VOLTORB = 100;
|
||||
our $SPECIES_ELECTRODE = 101;
|
||||
our $SPECIES_EXEGGCUTE = 102;
|
||||
our $SPECIES_EXEGGUTOR = 103;
|
||||
our $SPECIES_CUBONE = 104;
|
||||
our $SPECIES_MAROWAK = 105;
|
||||
our $SPECIES_HITMONLEE = 106;
|
||||
our $SPECIES_HITMONCHAN = 107;
|
||||
our $SPECIES_LICKITUNG = 108;
|
||||
our $SPECIES_KOFFING = 109;
|
||||
our $SPECIES_WEEZING = 110;
|
||||
our $SPECIES_RHYHORN = 111;
|
||||
our $SPECIES_RHYDON = 112;
|
||||
our $SPECIES_CHANSEY = 113;
|
||||
our $SPECIES_TANGELA = 114;
|
||||
our $SPECIES_KANGASKHAN = 115;
|
||||
our $SPECIES_HORSEA = 116;
|
||||
our $SPECIES_SEADRA = 117;
|
||||
our $SPECIES_GOLDEEN = 118;
|
||||
our $SPECIES_SEAKING = 119;
|
||||
our $SPECIES_STARYU = 120;
|
||||
our $SPECIES_STARMIE = 121;
|
||||
our $SPECIES_MR_MIME = 122;
|
||||
our $SPECIES_SCYTHER = 123;
|
||||
our $SPECIES_JYNX = 124;
|
||||
our $SPECIES_ELECTABUZZ = 125;
|
||||
our $SPECIES_MAGMAR = 126;
|
||||
our $SPECIES_PINSIR = 127;
|
||||
our $SPECIES_TAUROS = 128;
|
||||
our $SPECIES_MAGIKARP = 129;
|
||||
our $SPECIES_GYARADOS = 130;
|
||||
our $SPECIES_LAPRAS = 131;
|
||||
our $SPECIES_DITTO = 132;
|
||||
our $SPECIES_EEVEE = 133;
|
||||
our $SPECIES_VAPOREON = 134;
|
||||
our $SPECIES_JOLTEON = 135;
|
||||
our $SPECIES_FLAREON = 136;
|
||||
our $SPECIES_PORYGON = 137;
|
||||
our $SPECIES_OMANYTE = 138;
|
||||
our $SPECIES_OMASTAR = 139;
|
||||
our $SPECIES_KABUTO = 140;
|
||||
our $SPECIES_KABUTOPS = 141;
|
||||
our $SPECIES_AERODACTYL = 142;
|
||||
our $SPECIES_SNORLAX = 143;
|
||||
our $SPECIES_ARTICUNO = 144;
|
||||
our $SPECIES_ZAPDOS = 145;
|
||||
our $SPECIES_MOLTRES = 146;
|
||||
our $SPECIES_DRATINI = 147;
|
||||
our $SPECIES_DRAGONAIR = 148;
|
||||
our $SPECIES_DRAGONITE = 149;
|
||||
our $SPECIES_MEWTWO = 150;
|
||||
our $SPECIES_MEW = 151;
|
||||
our $SPECIES_CHIKORITA = 152;
|
||||
our $SPECIES_BAYLEEF = 153;
|
||||
our $SPECIES_MEGANIUM = 154;
|
||||
our $SPECIES_CYNDAQUIL = 155;
|
||||
our $SPECIES_QUILAVA = 156;
|
||||
our $SPECIES_TYPHLOSION = 157;
|
||||
our $SPECIES_TOTODILE = 158;
|
||||
our $SPECIES_CROCONAW = 159;
|
||||
our $SPECIES_FERALIGATR = 160;
|
||||
our $SPECIES_SENTRET = 161;
|
||||
our $SPECIES_FURRET = 162;
|
||||
our $SPECIES_HOOTHOOT = 163;
|
||||
our $SPECIES_NOCTOWL = 164;
|
||||
our $SPECIES_LEDYBA = 165;
|
||||
our $SPECIES_LEDIAN = 166;
|
||||
our $SPECIES_SPINARAK = 167;
|
||||
our $SPECIES_ARIADOS = 168;
|
||||
our $SPECIES_CROBAT = 169;
|
||||
our $SPECIES_CHINCHOU = 170;
|
||||
our $SPECIES_LANTURN = 171;
|
||||
our $SPECIES_PICHU = 172;
|
||||
our $SPECIES_CLEFFA = 173;
|
||||
our $SPECIES_IGGLYBUFF = 174;
|
||||
our $SPECIES_TOGEPI = 175;
|
||||
our $SPECIES_TOGETIC = 176;
|
||||
our $SPECIES_NATU = 177;
|
||||
our $SPECIES_XATU = 178;
|
||||
our $SPECIES_MAREEP = 179;
|
||||
our $SPECIES_FLAAFFY = 180;
|
||||
our $SPECIES_AMPHAROS = 181;
|
||||
our $SPECIES_BELLOSSOM = 182;
|
||||
our $SPECIES_MARILL = 183;
|
||||
our $SPECIES_AZUMARILL = 184;
|
||||
our $SPECIES_SUDOWOODO = 185;
|
||||
our $SPECIES_POLITOED = 186;
|
||||
our $SPECIES_HOPPIP = 187;
|
||||
our $SPECIES_SKIPLOOM = 188;
|
||||
our $SPECIES_JUMPLUFF = 189;
|
||||
our $SPECIES_AIPOM = 190;
|
||||
our $SPECIES_SUNKERN = 191;
|
||||
our $SPECIES_SUNFLORA = 192;
|
||||
our $SPECIES_YANMA = 193;
|
||||
our $SPECIES_WOOPER = 194;
|
||||
our $SPECIES_QUAGSIRE = 195;
|
||||
our $SPECIES_ESPEON = 196;
|
||||
our $SPECIES_UMBREON = 197;
|
||||
our $SPECIES_MURKROW = 198;
|
||||
our $SPECIES_SLOWKING = 199;
|
||||
our $SPECIES_MISDREAVUS = 200;
|
||||
our $SPECIES_UNOWN = 201;
|
||||
our $SPECIES_WOBBUFFET = 202;
|
||||
our $SPECIES_GIRAFARIG = 203;
|
||||
our $SPECIES_PINECO = 204;
|
||||
our $SPECIES_FORRETRESS = 205;
|
||||
our $SPECIES_DUNSPARCE = 206;
|
||||
our $SPECIES_GLIGAR = 207;
|
||||
our $SPECIES_STEELIX = 208;
|
||||
our $SPECIES_SNUBBULL = 209;
|
||||
our $SPECIES_GRANBULL = 210;
|
||||
our $SPECIES_QWILFISH = 211;
|
||||
our $SPECIES_SCIZOR = 212;
|
||||
our $SPECIES_SHUCKLE = 213;
|
||||
our $SPECIES_HERACROSS = 214;
|
||||
our $SPECIES_SNEASEL = 215;
|
||||
our $SPECIES_TEDDIURSA = 216;
|
||||
our $SPECIES_URSARING = 217;
|
||||
our $SPECIES_SLUGMA = 218;
|
||||
our $SPECIES_MAGCARGO = 219;
|
||||
our $SPECIES_SWINUB = 220;
|
||||
our $SPECIES_PILOSWINE = 221;
|
||||
our $SPECIES_CORSOLA = 222;
|
||||
our $SPECIES_REMORAID = 223;
|
||||
our $SPECIES_OCTILLERY = 224;
|
||||
our $SPECIES_DELIBIRD = 225;
|
||||
our $SPECIES_MANTINE = 226;
|
||||
our $SPECIES_SKARMORY = 227;
|
||||
our $SPECIES_HOUNDOUR = 228;
|
||||
our $SPECIES_HOUNDOOM = 229;
|
||||
our $SPECIES_KINGDRA = 230;
|
||||
our $SPECIES_PHANPY = 231;
|
||||
our $SPECIES_DONPHAN = 232;
|
||||
our $SPECIES_PORYGON2 = 233;
|
||||
our $SPECIES_STANTLER = 234;
|
||||
our $SPECIES_SMEARGLE = 235;
|
||||
our $SPECIES_TYROGUE = 236;
|
||||
our $SPECIES_HITMONTOP = 237;
|
||||
our $SPECIES_SMOOCHUM = 238;
|
||||
our $SPECIES_ELEKID = 239;
|
||||
our $SPECIES_MAGBY = 240;
|
||||
our $SPECIES_MILTANK = 241;
|
||||
our $SPECIES_BLISSEY = 242;
|
||||
our $SPECIES_RAIKOU = 243;
|
||||
our $SPECIES_ENTEI = 244;
|
||||
our $SPECIES_SUICUNE = 245;
|
||||
our $SPECIES_LARVITAR = 246;
|
||||
our $SPECIES_PUPITAR = 247;
|
||||
our $SPECIES_TYRANITAR = 248;
|
||||
our $SPECIES_LUGIA = 249;
|
||||
our $SPECIES_HO_OH = 250;
|
||||
our $SPECIES_CELEBI = 251;
|
||||
our $SPECIES_OLD_UNOWN_B = 252;
|
||||
our $SPECIES_OLD_UNOWN_C = 253;
|
||||
our $SPECIES_OLD_UNOWN_D = 254;
|
||||
our $SPECIES_OLD_UNOWN_E = 255;
|
||||
our $SPECIES_OLD_UNOWN_F = 256;
|
||||
our $SPECIES_OLD_UNOWN_G = 257;
|
||||
our $SPECIES_OLD_UNOWN_H = 258;
|
||||
our $SPECIES_OLD_UNOWN_I = 259;
|
||||
our $SPECIES_OLD_UNOWN_J = 260;
|
||||
our $SPECIES_OLD_UNOWN_K = 261;
|
||||
our $SPECIES_OLD_UNOWN_L = 262;
|
||||
our $SPECIES_OLD_UNOWN_M = 263;
|
||||
our $SPECIES_OLD_UNOWN_N = 264;
|
||||
our $SPECIES_OLD_UNOWN_O = 265;
|
||||
our $SPECIES_OLD_UNOWN_P = 266;
|
||||
our $SPECIES_OLD_UNOWN_Q = 267;
|
||||
our $SPECIES_OLD_UNOWN_R = 268;
|
||||
our $SPECIES_OLD_UNOWN_S = 269;
|
||||
our $SPECIES_OLD_UNOWN_T = 270;
|
||||
our $SPECIES_OLD_UNOWN_U = 271;
|
||||
our $SPECIES_OLD_UNOWN_V = 272;
|
||||
our $SPECIES_OLD_UNOWN_W = 273;
|
||||
our $SPECIES_OLD_UNOWN_X = 274;
|
||||
our $SPECIES_OLD_UNOWN_Y = 275;
|
||||
our $SPECIES_OLD_UNOWN_Z = 276;
|
||||
our $SPECIES_TREECKO = 277;
|
||||
our $SPECIES_GROVYLE = 278;
|
||||
our $SPECIES_SCEPTILE = 279;
|
||||
our $SPECIES_TORCHIC = 280;
|
||||
our $SPECIES_COMBUSKEN = 281;
|
||||
our $SPECIES_BLAZIKEN = 282;
|
||||
our $SPECIES_MUDKIP = 283;
|
||||
our $SPECIES_MARSHTOMP = 284;
|
||||
our $SPECIES_SWAMPERT = 285;
|
||||
our $SPECIES_POOCHYENA = 286;
|
||||
our $SPECIES_MIGHTYENA = 287;
|
||||
our $SPECIES_ZIGZAGOON = 288;
|
||||
our $SPECIES_LINOONE = 289;
|
||||
our $SPECIES_WURMPLE = 290;
|
||||
our $SPECIES_SILCOON = 291;
|
||||
our $SPECIES_BEAUTIFLY = 292;
|
||||
our $SPECIES_CASCOON = 293;
|
||||
our $SPECIES_DUSTOX = 294;
|
||||
our $SPECIES_LOTAD = 295;
|
||||
our $SPECIES_LOMBRE = 296;
|
||||
our $SPECIES_LUDICOLO = 297;
|
||||
our $SPECIES_SEEDOT = 298;
|
||||
our $SPECIES_NUZLEAF = 299;
|
||||
our $SPECIES_SHIFTRY = 300;
|
||||
our $SPECIES_NINCADA = 301;
|
||||
our $SPECIES_NINJASK = 302;
|
||||
our $SPECIES_SHEDINJA = 303;
|
||||
our $SPECIES_TAILLOW = 304;
|
||||
our $SPECIES_SWELLOW = 305;
|
||||
our $SPECIES_SHROOMISH = 306;
|
||||
our $SPECIES_BRELOOM = 307;
|
||||
our $SPECIES_SPINDA = 308;
|
||||
our $SPECIES_WINGULL = 309;
|
||||
our $SPECIES_PELIPPER = 310;
|
||||
our $SPECIES_SURSKIT = 311;
|
||||
our $SPECIES_MASQUERAIN = 312;
|
||||
our $SPECIES_WAILMER = 313;
|
||||
our $SPECIES_WAILORD = 314;
|
||||
our $SPECIES_SKITTY = 315;
|
||||
our $SPECIES_DELCATTY = 316;
|
||||
our $SPECIES_KECLEON = 317;
|
||||
our $SPECIES_BALTOY = 318;
|
||||
our $SPECIES_CLAYDOL = 319;
|
||||
our $SPECIES_NOSEPASS = 320;
|
||||
our $SPECIES_TORKOAL = 321;
|
||||
our $SPECIES_SABLEYE = 322;
|
||||
our $SPECIES_BARBOACH = 323;
|
||||
our $SPECIES_WHISCASH = 324;
|
||||
our $SPECIES_LUVDISC = 325;
|
||||
our $SPECIES_CORPHISH = 326;
|
||||
our $SPECIES_CRAWDAUNT = 327;
|
||||
our $SPECIES_FEEBAS = 328;
|
||||
our $SPECIES_MILOTIC = 329;
|
||||
our $SPECIES_CARVANHA = 330;
|
||||
our $SPECIES_SHARPEDO = 331;
|
||||
our $SPECIES_TRAPINCH = 332;
|
||||
our $SPECIES_VIBRAVA = 333;
|
||||
our $SPECIES_FLYGON = 334;
|
||||
our $SPECIES_MAKUHITA = 335;
|
||||
our $SPECIES_HARIYAMA = 336;
|
||||
our $SPECIES_ELECTRIKE = 337;
|
||||
our $SPECIES_MANECTRIC = 338;
|
||||
our $SPECIES_NUMEL = 339;
|
||||
our $SPECIES_CAMERUPT = 340;
|
||||
our $SPECIES_SPHEAL = 341;
|
||||
our $SPECIES_SEALEO = 342;
|
||||
our $SPECIES_WALREIN = 343;
|
||||
our $SPECIES_CACNEA = 344;
|
||||
our $SPECIES_CACTURNE = 345;
|
||||
our $SPECIES_SNORUNT = 346;
|
||||
our $SPECIES_GLALIE = 347;
|
||||
our $SPECIES_LUNATONE = 348;
|
||||
our $SPECIES_SOLROCK = 349;
|
||||
our $SPECIES_AZURILL = 350;
|
||||
our $SPECIES_SPOINK = 351;
|
||||
our $SPECIES_GRUMPIG = 352;
|
||||
our $SPECIES_PLUSLE = 353;
|
||||
our $SPECIES_MINUN = 354;
|
||||
our $SPECIES_MAWILE = 355;
|
||||
our $SPECIES_MEDITITE = 356;
|
||||
our $SPECIES_MEDICHAM = 357;
|
||||
our $SPECIES_SWABLU = 358;
|
||||
our $SPECIES_ALTARIA = 359;
|
||||
our $SPECIES_WYNAUT = 360;
|
||||
our $SPECIES_DUSKULL = 361;
|
||||
our $SPECIES_DUSCLOPS = 362;
|
||||
our $SPECIES_ROSELIA = 363;
|
||||
our $SPECIES_SLAKOTH = 364;
|
||||
our $SPECIES_VIGOROTH = 365;
|
||||
our $SPECIES_SLAKING = 366;
|
||||
our $SPECIES_GULPIN = 367;
|
||||
our $SPECIES_SWALOT = 368;
|
||||
our $SPECIES_TROPIUS = 369;
|
||||
our $SPECIES_WHISMUR = 370;
|
||||
our $SPECIES_LOUDRED = 371;
|
||||
our $SPECIES_EXPLOUD = 372;
|
||||
our $SPECIES_CLAMPERL = 373;
|
||||
our $SPECIES_HUNTAIL = 374;
|
||||
our $SPECIES_GOREBYSS = 375;
|
||||
our $SPECIES_ABSOL = 376;
|
||||
our $SPECIES_SHUPPET = 377;
|
||||
our $SPECIES_BANETTE = 378;
|
||||
our $SPECIES_SEVIPER = 379;
|
||||
our $SPECIES_ZANGOOSE = 380;
|
||||
our $SPECIES_RELICANTH = 381;
|
||||
our $SPECIES_ARON = 382;
|
||||
our $SPECIES_LAIRON = 383;
|
||||
our $SPECIES_AGGRON = 384;
|
||||
our $SPECIES_CASTFORM = 385;
|
||||
our $SPECIES_VOLBEAT = 386;
|
||||
our $SPECIES_ILLUMISE = 387;
|
||||
our $SPECIES_LILEEP = 388;
|
||||
our $SPECIES_CRADILY = 389;
|
||||
our $SPECIES_ANORITH = 390;
|
||||
our $SPECIES_ARMALDO = 391;
|
||||
our $SPECIES_RALTS = 392;
|
||||
our $SPECIES_KIRLIA = 393;
|
||||
our $SPECIES_GARDEVOIR = 394;
|
||||
our $SPECIES_BAGON = 395;
|
||||
our $SPECIES_SHELGON = 396;
|
||||
our $SPECIES_SALAMENCE = 397;
|
||||
our $SPECIES_BELDUM = 398;
|
||||
our $SPECIES_METANG = 399;
|
||||
our $SPECIES_METAGROSS = 400;
|
||||
our $SPECIES_REGIROCK = 401;
|
||||
our $SPECIES_REGICE = 402;
|
||||
our $SPECIES_REGISTEEL = 403;
|
||||
our $SPECIES_KYOGRE = 404;
|
||||
our $SPECIES_GROUDON = 405;
|
||||
our $SPECIES_RAYQUAZA = 406;
|
||||
our $SPECIES_LATIAS = 407;
|
||||
our $SPECIES_LATIOS = 408;
|
||||
our $SPECIES_JIRACHI = 409;
|
||||
our $SPECIES_DEOXYS = 410;
|
||||
our $SPECIES_CHIMECHO = 411;
|
||||
|
||||
our @SPECIES = (
|
||||
'NONE', 'BULBASAUR', 'IVYSAUR', 'VENUSAUR',
|
||||
'CHARMANDER', 'CHARMELEON', 'CHARIZARD', 'SQUIRTLE',
|
||||
'WARTORTLE', 'BLASTOISE', 'CATERPIE', 'METAPOD',
|
||||
'BUTTERFREE', 'WEEDLE', 'KAKUNA', 'BEEDRILL',
|
||||
'PIDGEY', 'PIDGEOTTO', 'PIDGEOT', 'RATTATA',
|
||||
'RATICATE', 'SPEAROW', 'FEAROW', 'EKANS',
|
||||
'ARBOK', 'PIKACHU', 'RAICHU', 'SANDSHREW',
|
||||
'SANDSLASH', 'NIDORAN_F', 'NIDORINA', 'NIDOQUEEN',
|
||||
'NIDORAN_M', 'NIDORINO', 'NIDOKING', 'CLEFAIRY',
|
||||
'CLEFABLE', 'VULPIX', 'NINETALES', 'JIGGLYPUFF',
|
||||
'WIGGLYTUFF', 'ZUBAT', 'GOLBAT', 'ODDISH',
|
||||
'GLOOM', 'VILEPLUME', 'PARAS', 'PARASECT',
|
||||
'VENONAT', 'VENOMOTH', 'DIGLETT', 'DUGTRIO',
|
||||
'MEOWTH', 'PERSIAN', 'PSYDUCK', 'GOLDUCK',
|
||||
'MANKEY', 'PRIMEAPE', 'GROWLITHE', 'ARCANINE',
|
||||
'POLIWAG', 'POLIWHIRL', 'POLIWRATH', 'ABRA',
|
||||
'KADABRA', 'ALAKAZAM', 'MACHOP', 'MACHOKE',
|
||||
'MACHAMP', 'BELLSPROUT', 'WEEPINBELL', 'VICTREEBEL',
|
||||
'TENTACOOL', 'TENTACRUEL', 'GEODUDE', 'GRAVELER',
|
||||
'GOLEM', 'PONYTA', 'RAPIDASH', 'SLOWPOKE',
|
||||
'SLOWBRO', 'MAGNEMITE', 'MAGNETON', 'FARFETCHD',
|
||||
'DODUO', 'DODRIO', 'SEEL', 'DEWGONG',
|
||||
'GRIMER', 'MUK', 'SHELLDER', 'CLOYSTER',
|
||||
'GASTLY', 'HAUNTER', 'GENGAR', 'ONIX',
|
||||
'DROWZEE', 'HYPNO', 'KRABBY', 'KINGLER',
|
||||
'VOLTORB', 'ELECTRODE', 'EXEGGCUTE', 'EXEGGUTOR',
|
||||
'CUBONE', 'MAROWAK', 'HITMONLEE', 'HITMONCHAN',
|
||||
'LICKITUNG', 'KOFFING', 'WEEZING', 'RHYHORN',
|
||||
'RHYDON', 'CHANSEY', 'TANGELA', 'KANGASKHAN',
|
||||
'HORSEA', 'SEADRA', 'GOLDEEN', 'SEAKING',
|
||||
'STARYU', 'STARMIE', 'MR_MIME', 'SCYTHER',
|
||||
'JYNX', 'ELECTABUZZ', 'MAGMAR', 'PINSIR',
|
||||
'TAUROS', 'MAGIKARP', 'GYARADOS', 'LAPRAS',
|
||||
'DITTO', 'EEVEE', 'VAPOREON', 'JOLTEON',
|
||||
'FLAREON', 'PORYGON', 'OMANYTE', 'OMASTAR',
|
||||
'KABUTO', 'KABUTOPS', 'AERODACTYL', 'SNORLAX',
|
||||
'ARTICUNO', 'ZAPDOS', 'MOLTRES', 'DRATINI',
|
||||
'DRAGONAIR', 'DRAGONITE', 'MEWTWO', 'MEW',
|
||||
'CHIKORITA', 'BAYLEEF', 'MEGANIUM', 'CYNDAQUIL',
|
||||
'QUILAVA', 'TYPHLOSION', 'TOTODILE', 'CROCONAW',
|
||||
'FERALIGATR', 'SENTRET', 'FURRET', 'HOOTHOOT',
|
||||
'NOCTOWL', 'LEDYBA', 'LEDIAN', 'SPINARAK',
|
||||
'ARIADOS', 'CROBAT', 'CHINCHOU', 'LANTURN',
|
||||
'PICHU', 'CLEFFA', 'IGGLYBUFF', 'TOGEPI',
|
||||
'TOGETIC', 'NATU', 'XATU', 'MAREEP',
|
||||
'FLAAFFY', 'AMPHAROS', 'BELLOSSOM', 'MARILL',
|
||||
'AZUMARILL', 'SUDOWOODO', 'POLITOED', 'HOPPIP',
|
||||
'SKIPLOOM', 'JUMPLUFF', 'AIPOM', 'SUNKERN',
|
||||
'SUNFLORA', 'YANMA', 'WOOPER', 'QUAGSIRE',
|
||||
'ESPEON', 'UMBREON', 'MURKROW', 'SLOWKING',
|
||||
'MISDREAVUS', 'UNOWN', 'WOBBUFFET', 'GIRAFARIG',
|
||||
'PINECO', 'FORRETRESS', 'DUNSPARCE', 'GLIGAR',
|
||||
'STEELIX', 'SNUBBULL', 'GRANBULL', 'QWILFISH',
|
||||
'SCIZOR', 'SHUCKLE', 'HERACROSS', 'SNEASEL',
|
||||
'TEDDIURSA', 'URSARING', 'SLUGMA', 'MAGCARGO',
|
||||
'SWINUB', 'PILOSWINE', 'CORSOLA', 'REMORAID',
|
||||
'OCTILLERY', 'DELIBIRD', 'MANTINE', 'SKARMORY',
|
||||
'HOUNDOUR', 'HOUNDOOM', 'KINGDRA', 'PHANPY',
|
||||
'DONPHAN', 'PORYGON2', 'STANTLER', 'SMEARGLE',
|
||||
'TYROGUE', 'HITMONTOP', 'SMOOCHUM', 'ELEKID',
|
||||
'MAGBY', 'MILTANK', 'BLISSEY', 'RAIKOU',
|
||||
'ENTEI', 'SUICUNE', 'LARVITAR', 'PUPITAR',
|
||||
'TYRANITAR', 'LUGIA', 'HO_OH', 'CELEBI',
|
||||
'OLD_UNOWN_B', 'OLD_UNOWN_C', 'OLD_UNOWN_D', 'OLD_UNOWN_E',
|
||||
'OLD_UNOWN_F', 'OLD_UNOWN_G', 'OLD_UNOWN_H', 'OLD_UNOWN_I',
|
||||
'OLD_UNOWN_J', 'OLD_UNOWN_K', 'OLD_UNOWN_L', 'OLD_UNOWN_M',
|
||||
'OLD_UNOWN_N', 'OLD_UNOWN_O', 'OLD_UNOWN_P', 'OLD_UNOWN_Q',
|
||||
'OLD_UNOWN_R', 'OLD_UNOWN_S', 'OLD_UNOWN_T', 'OLD_UNOWN_U',
|
||||
'OLD_UNOWN_V', 'OLD_UNOWN_W', 'OLD_UNOWN_X', 'OLD_UNOWN_Y',
|
||||
'OLD_UNOWN_Z', 'TREECKO', 'GROVYLE', 'SCEPTILE',
|
||||
'TORCHIC', 'COMBUSKEN', 'BLAZIKEN', 'MUDKIP',
|
||||
'MARSHTOMP', 'SWAMPERT', 'POOCHYENA', 'MIGHTYENA',
|
||||
'ZIGZAGOON', 'LINOONE', 'WURMPLE', 'SILCOON',
|
||||
'BEAUTIFLY', 'CASCOON', 'DUSTOX', 'LOTAD',
|
||||
'LOMBRE', 'LUDICOLO', 'SEEDOT', 'NUZLEAF',
|
||||
'SHIFTRY', 'NINCADA', 'NINJASK', 'SHEDINJA',
|
||||
'TAILLOW', 'SWELLOW', 'SHROOMISH', 'BRELOOM',
|
||||
'SPINDA', 'WINGULL', 'PELIPPER', 'SURSKIT',
|
||||
'MASQUERAIN', 'WAILMER', 'WAILORD', 'SKITTY',
|
||||
'DELCATTY', 'KECLEON', 'BALTOY', 'CLAYDOL',
|
||||
'NOSEPASS', 'TORKOAL', 'SABLEYE', 'BARBOACH',
|
||||
'WHISCASH', 'LUVDISC', 'CORPHISH', 'CRAWDAUNT',
|
||||
'FEEBAS', 'MILOTIC', 'CARVANHA', 'SHARPEDO',
|
||||
'TRAPINCH', 'VIBRAVA', 'FLYGON', 'MAKUHITA',
|
||||
'HARIYAMA', 'ELECTRIKE', 'MANECTRIC', 'NUMEL',
|
||||
'CAMERUPT', 'SPHEAL', 'SEALEO', 'WALREIN',
|
||||
'CACNEA', 'CACTURNE', 'SNORUNT', 'GLALIE',
|
||||
'LUNATONE', 'SOLROCK', 'AZURILL', 'SPOINK',
|
||||
'GRUMPIG', 'PLUSLE', 'MINUN', 'MAWILE',
|
||||
'MEDITITE', 'MEDICHAM', 'SWABLU', 'ALTARIA',
|
||||
'WYNAUT', 'DUSKULL', 'DUSCLOPS', 'ROSELIA',
|
||||
'SLAKOTH', 'VIGOROTH', 'SLAKING', 'GULPIN',
|
||||
'SWALOT', 'TROPIUS', 'WHISMUR', 'LOUDRED',
|
||||
'EXPLOUD', 'CLAMPERL', 'HUNTAIL', 'GOREBYSS',
|
||||
'ABSOL', 'SHUPPET', 'BANETTE', 'SEVIPER',
|
||||
'ZANGOOSE', 'RELICANTH', 'ARON', 'LAIRON',
|
||||
'AGGRON', 'CASTFORM', 'VOLBEAT', 'ILLUMISE',
|
||||
'LILEEP', 'CRADILY', 'ANORITH', 'ARMALDO',
|
||||
'RALTS', 'KIRLIA', 'GARDEVOIR', 'BAGON',
|
||||
'SHELGON', 'SALAMENCE', 'BELDUM', 'METANG',
|
||||
'METAGROSS', 'REGIROCK', 'REGICE', 'REGISTEEL',
|
||||
'KYOGRE', 'GROUDON', 'RAYQUAZA', 'LATIAS',
|
||||
'LATIOS', 'JIRACHI', 'DEOXYS', 'CHIMECHO',
|
||||
);
|
||||
|
||||
our %SPECIES_NAME_TO_ID;
|
||||
|
||||
for (my $i = 0; $i < scalar @SPECIES; $i++) {
|
||||
$SPECIES_NAME_TO_ID{$SPECIES[$i]} = $i;
|
||||
}
|
||||
1;
|
1652
lib/Rsaves/Constants/Emerald/SpeciesData.pm
Normal file
1
pokeemerald
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 954ba0a15590d1eaf4929238cec4e0ea3d2e8dd4
|
BIN
resources/forest.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/hand_cursor.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
resources/pc_background.png
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
resources/right_arrow_pc.png
Normal file
After Width: | Height: | Size: 200 B |
BIN
resources/shiny/abra.png
Normal file
After Width: | Height: | Size: 585 B |
BIN
resources/shiny/absol.png
Normal file
After Width: | Height: | Size: 890 B |
BIN
resources/shiny/aerodactyl.png
Normal file
After Width: | Height: | Size: 923 B |
BIN
resources/shiny/aggron.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shiny/aipom.png
Normal file
After Width: | Height: | Size: 639 B |
BIN
resources/shiny/alakazam.png
Normal file
After Width: | Height: | Size: 839 B |
BIN
resources/shiny/altaria.png
Normal file
After Width: | Height: | Size: 825 B |
BIN
resources/shiny/ampharos.png
Normal file
After Width: | Height: | Size: 721 B |
BIN
resources/shiny/anorith.png
Normal file
After Width: | Height: | Size: 691 B |
BIN
resources/shiny/arbok.png
Normal file
After Width: | Height: | Size: 880 B |
BIN
resources/shiny/arcanine.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shiny/ariados.png
Normal file
After Width: | Height: | Size: 850 B |
BIN
resources/shiny/armaldo.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shiny/aron.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
resources/shiny/articuno.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
resources/shiny/azumarill.png
Normal file
After Width: | Height: | Size: 631 B |
BIN
resources/shiny/azurill.png
Normal file
After Width: | Height: | Size: 589 B |
BIN
resources/shiny/bagon.png
Normal file
After Width: | Height: | Size: 512 B |
BIN
resources/shiny/baltoy.png
Normal file
After Width: | Height: | Size: 416 B |
BIN
resources/shiny/banette.png
Normal file
After Width: | Height: | Size: 546 B |
BIN
resources/shiny/barboach.png
Normal file
After Width: | Height: | Size: 565 B |
BIN
resources/shiny/bayleef.png
Normal file
After Width: | Height: | Size: 815 B |
BIN
resources/shiny/beautifly.png
Normal file
After Width: | Height: | Size: 699 B |
BIN
resources/shiny/beedrill.png
Normal file
After Width: | Height: | Size: 891 B |
BIN
resources/shiny/beldum.png
Normal file
After Width: | Height: | Size: 465 B |
BIN
resources/shiny/bellossom.png
Normal file
After Width: | Height: | Size: 520 B |
BIN
resources/shiny/bellsprout.png
Normal file
After Width: | Height: | Size: 528 B |
BIN
resources/shiny/blastoise.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
resources/shiny/blaziken.png
Normal file
After Width: | Height: | Size: 1010 B |
BIN
resources/shiny/blissey.png
Normal file
After Width: | Height: | Size: 827 B |
BIN
resources/shiny/breloom.png
Normal file
After Width: | Height: | Size: 849 B |
BIN
resources/shiny/bulbasaur.png
Normal file
After Width: | Height: | Size: 525 B |
BIN
resources/shiny/butterfree.png
Normal file
After Width: | Height: | Size: 739 B |
BIN
resources/shiny/cacnea.png
Normal file
After Width: | Height: | Size: 662 B |
BIN
resources/shiny/cacturne.png
Normal file
After Width: | Height: | Size: 917 B |
BIN
resources/shiny/camerupt.png
Normal file
After Width: | Height: | Size: 839 B |
BIN
resources/shiny/carvanha.png
Normal file
After Width: | Height: | Size: 692 B |
BIN
resources/shiny/cascoon.png
Normal file
After Width: | Height: | Size: 493 B |
BIN
resources/shiny/castform.png
Normal file
After Width: | Height: | Size: 382 B |
BIN
resources/shiny/caterpie.png
Normal file
After Width: | Height: | Size: 484 B |
BIN
resources/shiny/celebi.png
Normal file
After Width: | Height: | Size: 514 B |
BIN
resources/shiny/chansey.png
Normal file
After Width: | Height: | Size: 674 B |
BIN
resources/shiny/charizard.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shiny/charmander.png
Normal file
After Width: | Height: | Size: 561 B |
BIN
resources/shiny/charmeleon.png
Normal file
After Width: | Height: | Size: 775 B |
BIN
resources/shiny/chikorita.png
Normal file
After Width: | Height: | Size: 507 B |
BIN
resources/shiny/chimecho.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
resources/shiny/chinchou.png
Normal file
After Width: | Height: | Size: 607 B |
BIN
resources/shiny/clamperl.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
resources/shiny/claydol.png
Normal file
After Width: | Height: | Size: 771 B |
BIN
resources/shiny/clefable.png
Normal file
After Width: | Height: | Size: 650 B |
BIN
resources/shiny/clefairy.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
resources/shiny/cleffa.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
resources/shiny/cloyster.png
Normal file
After Width: | Height: | Size: 861 B |
BIN
resources/shiny/combusken.png
Normal file
After Width: | Height: | Size: 838 B |
BIN
resources/shiny/corphish.png
Normal file
After Width: | Height: | Size: 704 B |
BIN
resources/shiny/corsola.png
Normal file
After Width: | Height: | Size: 601 B |
BIN
resources/shiny/cradily.png
Normal file
After Width: | Height: | Size: 887 B |
BIN
resources/shiny/crawdaunt.png
Normal file
After Width: | Height: | Size: 1006 B |
BIN
resources/shiny/crobat.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
resources/shiny/croconaw.png
Normal file
After Width: | Height: | Size: 730 B |
BIN
resources/shiny/cubone.png
Normal file
After Width: | Height: | Size: 604 B |
BIN
resources/shiny/cyndaquil.png
Normal file
After Width: | Height: | Size: 546 B |
BIN
resources/shiny/delcatty.png
Normal file
After Width: | Height: | Size: 765 B |
BIN
resources/shiny/delibird.png
Normal file
After Width: | Height: | Size: 733 B |
BIN
resources/shiny/deoxys.png
Normal file
After Width: | Height: | Size: 838 B |
BIN
resources/shiny/dewgong.png
Normal file
After Width: | Height: | Size: 747 B |
BIN
resources/shiny/diglett.png
Normal file
After Width: | Height: | Size: 422 B |
BIN
resources/shiny/ditto.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
resources/shiny/dodrio.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shiny/doduo.png
Normal file
After Width: | Height: | Size: 705 B |
BIN
resources/shiny/donphan.png
Normal file
After Width: | Height: | Size: 923 B |
BIN
resources/shiny/dragonair.png
Normal file
After Width: | Height: | Size: 733 B |
BIN
resources/shiny/dragonite.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shiny/dratini.png
Normal file
After Width: | Height: | Size: 549 B |
BIN
resources/shiny/drowzee.png
Normal file
After Width: | Height: | Size: 703 B |
BIN
resources/shiny/dugtrio.png
Normal file
After Width: | Height: | Size: 635 B |
BIN
resources/shiny/dunsparce.png
Normal file
After Width: | Height: | Size: 645 B |
BIN
resources/shiny/dusclops.png
Normal file
After Width: | Height: | Size: 741 B |