package GEmeTool::Save; use v5.16.3; use strict; use warnings; use Rsaves; use Rsaves::Constants::Global qw/$SAPPHIRE_VERSION $RUBY_VERSION $EMERALD_VERSION $FIRERED_VERSION $LEAFGREEN_VERSION $COLOSSEUM_VERSION/; use Rsaves::Constants::Emerald::Flags; use Rsaves::Constants::Emerald::Rematches; use Moo; use GEmeTool::Log qw/logger/; use namespace::clean; use GEmeTool::Save::PokemonPC; has __saves => ( is => 'rw' ); has __extra => ( is => 'rw' ); has input_file => ( is => 'rw', required => 1 ); has _initial_rematches => ( is => 'rw' ); has _initial_flags => ( is => 'rw' ); has _pc => ( is => 'rw' ); sub instance { my $class = shift; my $input_file = shift; my $save = $class->new( input_file => $input_file ); return $save; } sub BUILD { my $self = shift; logger()->msg( 'Opening save...', $self->input_file ); } sub get_flags_save { my $self = shift; my %flags_by_id = $self->_get_flags_hash_by_id; my @return; for my $i ( sort { $a <=> $b } keys %flags_by_id ) { push @return, { value => $self->has_flag($i), name => $flags_by_id{$i}, id => $i }; } return \@return; } sub get_rematches_save { my $self = shift; my %rematch_by_id = $self->_get_rematches_hash_by_id; my @return; for my $i ( sort { $a <=> $b } keys %rematch_by_id ) { push @return, { value => $self->has_rematch($i), name => $rematch_by_id{$i}, id => $i }; } return \@return; } sub save { my $self = shift; my $file = shift; my $extra = $self->__extra; my $saves = $self->__saves; my $ini_flags = $self->_initial_flags; my $end_flags = $self->get_flags_save; my $ini_rematches = $self->_initial_rematches; my $end_rematches = $self->get_rematches_save; logger()->msg( "Saving, edited data:\n" . $self->diff_boolean_flag_like( $ini_flags, $end_flags ) . $self->diff_boolean_flag_like( $ini_rematches, $end_rematches ), $self->input_file, $file, ); Rsaves::save_changes( @$saves, $extra, $file ); } sub diff_boolean_flag_like { my $self = shift; my $initial = shift; my $final = shift; my $result_string = ''; for ( my $i = 0 ; $i < scalar @$initial ; $i++ ) { my $flag_ini = $initial->[$i]; my $flag_end = $final->[$i]; if ( ( !!$flag_ini->{value} ) == ( !!$flag_end->{value} ) ) { next; } $result_string .= "@{[$flag_end->{name}]} => @{[$flag_end->{value} ? 'ON' : 'OFF']}\n"; } return $result_string; } sub has_rematch { my $self = shift; my $flag_id = shift; my $superdata = $self->_get_superdata; my $save = $self->_get_current_save; return Rsaves::check_rematch( $save, $superdata, $flag_id ); } sub has_flag { my $self = shift; my $flag_id = shift; my $superdata = $self->_get_superdata; my $save = $self->_get_current_save; return Rsaves::check_flag_id( $save, $superdata, $flag_id ); } sub set_rematch { my $self = shift; my $flag_id = shift; my $value = shift; my $superdata = $self->_get_superdata; my $save = $self->_get_current_save; Rsaves::set_rematch( $save, $superdata, $flag_id, $value ); $self->_set_superdata($superdata); } sub set_flag { my $self = shift; my $flag_id = shift; my $value = shift; my $superdata = $self->_get_superdata; my $save = $self->_get_current_save; Rsaves::set_flag_id( $save, $superdata, $flag_id, $value ); $self->_set_superdata($superdata); } sub _set_superdata { my $self = shift; my $superdata = shift; my $save = $self->_get_current_save; Rsaves::set_first_super_data( $save, $superdata ); } sub _saves { my $self = shift; my $saves = $self->__saves; if ( !defined $saves ) { $self->_build_saves_and_extra; } return $self->__saves; } sub _extra { my $self = shift; my $extra = $self->__extra; if ( !defined $extra ) { $self->_build_saves_and_extra; } return $self->__extra; } sub _get_superdata { my $self = shift; return Rsaves::get_first_super_data( $self->_get_current_save ); } sub _get_rematches_hash_by_id { my $self = shift; my @rematches = $self->_get_rematches_constant_list; my $rematches = {@rematches}; my @final_hash = ( map { $_ => $rematches->{$_} } grep { $_ =~ /^\d+$/ } keys %$rematches ); return @final_hash; } sub _build_saves_and_extra { my $self = shift; my ( @saves_raw, $extra ); ( @saves_raw[ 0, 1 ], $extra ) = Rsaves::read_save( $self->input_file ); my @saves = Rsaves::get_saves( @saves_raw, $EMERALD_VERSION ); $self->__saves( \@saves ); $self->__extra($extra); $self->store_initial_flags_and_rematch; } sub store_initial_flags_and_rematch { my $self = shift; $self->_initial_flags( [@{$self->get_flags_save}] ); $self->_initial_rematches( [@{$self->get_rematches_save}] ); } sub _get_rematches_constant_list { return @Rsaves::Constants::Emerald::Rematches::REMATCHES; } sub _get_flags_constant_list { return @Rsaves::Constants::Emerald::Flags::FLAGS; } sub _get_current_save { my $self = shift; return $self->_saves->[ Rsaves::find_current_save_index( @{ $self->_saves } ) ]; } sub _get_flags_hash_by_id { my $self = shift; my @flags = $self->_get_flags_constant_list; my $flags = {@flags}; my @final_hash = ( map { $_ => $flags->{$_} } grep { $_ =~ /^\d+$/ } keys %$flags ); 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;