Compare commits

...

24 Commits

Author SHA1 Message Date
sergiotarxz 082b1d173d Merge branch 'pc_editing' of git.owlcode.tech:sergiotarxz/GEmeTool 2024-03-11 16:10:29 +01:00
sergiotarxz e2743b9dc6 Adding ev and iv support. 2024-03-11 02:50:43 +01:00
Sergiotarxz d7da1100fe Adding missing natures. 2024-03-10 21:47:50 +01:00
Sergiotarxz 27bddb53f8 Improving style pokemon edition. 2024-03-10 20:57:39 +01:00
Sergiotarxz 71e5f82d6a Adding nature selection screen, very ugly. 2024-03-09 23:01:54 +01:00
Sergiotarxz 899f783cbb Initial personality tuning support. 2024-03-09 21:03:09 +01:00
sergiotarxz 34a41d74c2 Adding nickname editing. 2024-03-09 17:29:35 +01:00
sergiotarxz 4e15773d3d Change species + dropdown + functional search. 2024-03-09 17:05:35 +01:00
Sergiotarxz e40869769c Improving the titlebar of PcWindow. 2024-03-08 23:47:28 +01:00
Sergiotarxz 7987b5c828 Enabling the close box button. 2024-03-08 23:42:14 +01:00
Sergiotarxz 77cc606473 Adding genders. 2024-03-08 22:38:50 +01:00
Sergiotarxz 6371fd1195 Fixing decimal bug with levels. 2024-03-08 21:19:43 +01:00
Sergiotarxz 780477c52d Adding logic to get the level of every pokemon. 2024-03-08 21:09:22 +01:00
sergiotarxz fe98d9a8d9 Fixing pokemon with alternative forms. 2024-03-08 03:54:27 +01:00
Sergiotarxz dfc2abf809 Adding missing files. 2024-03-08 03:30:14 +01:00
Sergiotarxz 90a36b9547 Adding logic to change box. 2024-03-08 02:56:51 +01:00
Sergiotarxz 3a9326d909 Adding shiny fronts. 2024-03-08 01:44:57 +01:00
Sergiotarxz acfdd06660 Adding hand, adding complete pc interface, adding selected pokemon logic. 2024-03-08 00:14:50 +01:00
Sergiotarxz a43b07c5fc Missing files. 2024-03-07 09:38:16 +01:00
Sergiotarxz dbacdcdf79 Adding logic to print the box name. 2024-03-07 00:08:01 +01:00
Sergiotarxz e274f22aba Able to read the pokemon boxes and put them in a canvas!! 2024-03-06 21:00:52 +01:00
Sergiotarxz 129e20ffd6 Adding inital support to printing pokemon icons. 2024-03-06 13:22:16 +01:00
Sergiotarxz 3ace9d4438 Adding initial cairo printing of forest box to the pokemon editor. 2024-03-06 01:51:55 +01:00
sergiotarxz 3ab70cefe5 Adding initial support for cairo. 2024-03-05 21:10:24 +01:00
407 changed files with 3975 additions and 148 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "pokeemerald"]
path = pokeemerald
url = https://github.com/pret/pokeemerald

View File

@ -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
View 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
View 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
View 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;

View File

@ -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;

View 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;

View 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;

View 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;

View File

@ -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;

View 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;

View 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;

View File

@ -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;
}

View 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;

View 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;

File diff suppressed because it is too large Load Diff

1
pokeemerald Submodule

@ -0,0 +1 @@
Subproject commit 954ba0a15590d1eaf4929238cec4e0ea3d2e8dd4

BIN
resources/forest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
resources/hand_cursor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
resources/pc_background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

BIN
resources/shiny/abra.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

BIN
resources/shiny/absol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

BIN
resources/shiny/aggron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/shiny/aipom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
resources/shiny/altaria.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

BIN
resources/shiny/anorith.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

BIN
resources/shiny/arbok.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/shiny/ariados.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

BIN
resources/shiny/armaldo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/shiny/aron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

BIN
resources/shiny/azurill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
resources/shiny/bagon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

BIN
resources/shiny/baltoy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

BIN
resources/shiny/banette.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

BIN
resources/shiny/bayleef.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

BIN
resources/shiny/beldum.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

BIN
resources/shiny/blissey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

BIN
resources/shiny/breloom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

BIN
resources/shiny/cacnea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

BIN
resources/shiny/cascoon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

BIN
resources/shiny/celebi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

BIN
resources/shiny/chansey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

BIN
resources/shiny/claydol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

BIN
resources/shiny/cleffa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
resources/shiny/corsola.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
resources/shiny/cradily.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

BIN
resources/shiny/crobat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

BIN
resources/shiny/cubone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
resources/shiny/deoxys.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

BIN
resources/shiny/dewgong.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

BIN
resources/shiny/diglett.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

BIN
resources/shiny/ditto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

BIN
resources/shiny/dodrio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/shiny/doduo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

BIN
resources/shiny/donphan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/shiny/dratini.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

BIN
resources/shiny/drowzee.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

BIN
resources/shiny/dugtrio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Some files were not shown because too many files have changed in this diff Show More