From acfdd06660e899e015910a29206f2ac60bcf3f43 Mon Sep 17 00:00:00 2001 From: Sergiotarxz Date: Fri, 8 Mar 2024 00:14:50 +0100 Subject: [PATCH] Adding hand, adding complete pc interface, adding selected pokemon logic. --- Build.PL | 1 + lib/GEmeTool/Save.pm | 9 +- lib/GEmeTool/Save/PokemonBox.pm | 16 +- lib/GEmeTool/Save/PokemonPC.pm | 14 ++ lib/GEmeTool/View/MainWindow.pm | 92 ++--------- lib/GEmeTool/View/PokemonPCWindow.pm | 234 +++++++++++++++++++++++++++ resources/hand_cursor.png | Bin 0 -> 24025 bytes resources/pc_background.png | Bin 0 -> 170849 bytes 8 files changed, 281 insertions(+), 85 deletions(-) create mode 100644 lib/GEmeTool/View/PokemonPCWindow.pm create mode 100644 resources/hand_cursor.png create mode 100644 resources/pc_background.png diff --git a/Build.PL b/Build.PL index c856bc3..c9026cd 100755 --- a/Build.PL +++ b/Build.PL @@ -18,6 +18,7 @@ my $build = Module::Build->new( 'namespace::clean' => 0, 'Cairo::GObject' => 0, 'UUID::URandom' => 0, + 'Glib' => 0, }, ); $build->create_build_script; diff --git a/lib/GEmeTool/Save.pm b/lib/GEmeTool/Save.pm index fde6fe0..bce7869 100644 --- a/lib/GEmeTool/Save.pm +++ b/lib/GEmeTool/Save.pm @@ -27,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; @@ -221,10 +223,15 @@ sub _get_flags_hash_by_id { sub get_pc_system { my $self = shift; + if (defined $self->_pc) { + return $self->_pc; + } my $pc = Rsaves::read_pc_storage($self->_get_current_save); - return GEmeTool::Save::PokemonPC->new(_pc => $pc, _save => sub { + 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; diff --git a/lib/GEmeTool/Save/PokemonBox.pm b/lib/GEmeTool/Save/PokemonBox.pm index 1e27714..57d7170 100644 --- a/lib/GEmeTool/Save/PokemonBox.pm +++ b/lib/GEmeTool/Save/PokemonBox.pm @@ -24,6 +24,10 @@ has _box => ( required => 1, ); +has _pokemons => ( + is => 'rw', +); + sub wallpaper { my $self = shift; my $arg = shift; @@ -45,9 +49,19 @@ sub 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."; } - return GEmeTool::Save::Pokemon->new( _pokemon => $self->_box->[$number] ); + if (defined $pokemons->[$number]) { + return $pokemons->[$number]; + } + my $return = GEmeTool::Save::Pokemon->new( _pokemon => $self->_box->[$number] ); + $pokemons->[$number] = $return; + return $return; } 1; diff --git a/lib/GEmeTool/Save/PokemonPC.pm b/lib/GEmeTool/Save/PokemonPC.pm index 4836c5e..2191189 100644 --- a/lib/GEmeTool/Save/PokemonPC.pm +++ b/lib/GEmeTool/Save/PokemonPC.pm @@ -20,6 +20,10 @@ has _save => ( required => 1, ); +has _boxes => ( + is => 'rw', +); + sub boxes { my $self = shift; my $pc = $self->_pc; @@ -30,12 +34,21 @@ sub boxes { 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]; @@ -45,6 +58,7 @@ sub get_box { _name => $name, _box => $box ); + $boxes->[$number] = $return; return $return; } diff --git a/lib/GEmeTool/View/MainWindow.pm b/lib/GEmeTool/View/MainWindow.pm index eab1133..3032148 100644 --- a/lib/GEmeTool/View/MainWindow.pm +++ b/lib/GEmeTool/View/MainWindow.pm @@ -11,10 +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 Cairo::GObject; +use GEmeTool::View::PokemonPCWindow; use Moo; @@ -219,11 +220,11 @@ sub open_file { } sub start_editing_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 ); + 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; @@ -324,82 +325,7 @@ sub activate_about { my $root = path(__FILE__)->parent->parent->parent->parent; sub activate_view_pc { - my $self = shift; - my $gtk_window = Gtk4::Window->new; - my $canvas = Gtk4::DrawingArea->new; - $gtk_window->set_default_size( 312, 340 ); - $gtk_window->set_resizable(0); - $canvas->set_draw_func( - sub { - my $canvas = shift; - my $cairo = shift; - my $width = shift; - my $height = shift; - - $self->draw_box($cairo); - $self->draw_pokemon($cairo); - $self->draw_box_name($cairo); - } - ); - $gtk_window->set_child($canvas); - $gtk_window->present; -} - -sub draw_box_name { - my $self = shift; - my $cairo = shift; - my $save = $self->_save; - my $pc = $save->get_pc_system; - my $box = $pc->get_box(0); - my $name = Rsaves::translate_3rd_encoding($box->name); - $cairo->scale( 1, 1 ); - $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); -} - -sub draw_pokemon { - my $self = shift; - my $cairo = shift; - my $save = $self->_save; - my $pc = $save->get_pc_system; - my $box = $pc->get_box(0); - $cairo->scale(0.95, 0.95); - 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 $pokemon_image = - $root->child($pokemon->get_image); - 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; - my $p = 25; - $cairo->set_source_surface( $output_image, $j * ($p + 1), - 20 + ( ( $p - 3 ) * $i ) ); - $cairo->get_source()->set_filter('nearest'); - $cairo->paint; - } - } -} - -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; - + my $self = shift; + GEmeTool::View::PokemonPCWindow->new( _save => $self->_save )->start; } 1; diff --git a/lib/GEmeTool/View/PokemonPCWindow.pm b/lib/GEmeTool/View/PokemonPCWindow.pm new file mode 100644 index 0000000..1fac2ef --- /dev/null +++ b/lib/GEmeTool/View/PokemonPCWindow.pm @@ -0,0 +1,234 @@ +package GEmeTool::View::PokemonPCWindow; + +use v5.16.3; + +use strict; +use warnings; + +use Cairo::GObject; +use Glib; +use Glib::IO; +use Path::Tiny; +use Math::Trig; + +use Moo; + +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, +); + + +my $BOX_X = 275; +my $BOX_Y = 50; +my $BOX_WIDTH = 312; +my $BOX_HEIGHT = 340; + +has _cursor_position => ( is => 'rw' ); + +my $root = path(__FILE__)->parent->parent->parent->parent; + +sub start { + my $self = shift; + my $gtk_window = Gtk4::Window->new; + my $controller_motion = Gtk4::EventControllerMotion->new; + $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); + 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; + + $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); + my $selected_pokemon = $self->get_selected_pokemon; + $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_cursor($cairo); + } + ); + $gtk_window->set_child($canvas); + $gtk_window->present; + Glib::Timeout->add( + 1000 / 15, + sub { + $canvas->queue_draw; + return 1; + } + ); +} + +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 = $pc->get_box(0); + 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 = $pc->get_box(0); + 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_image ); + 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 = $pc->get_box(0); + 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; + $cairo->scale( 1 / 2, 1 / 2 ); + +} +1; diff --git a/resources/hand_cursor.png b/resources/hand_cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..1a87e68b9b69f61dd609319509ffde4ca0b98d18 GIT binary patch literal 24025 zcmeHP30PA{+r5z;Mci-&K~TYJAS8j1$i4|yL>7grXhTRKKnReqD#c3Cii&liRG}iE zh$6TEqT((~sS8!y01=h4SVY_a5h4Gbz-UAy3F_bH>6htqGjnI&dCz&z%$?jBVmB;W zI8RA&vLb>YO7?cv&Sff?58(+>3QE5{8-JD{nT zJMS*<0Wxa7t-UP@1O!4qc-4p%A}=c|Co3Z_Cnu+%Ag?%LoYIKl!$(XSGgf(=+GO>q zYLit}HKyxoYiQ2VQdQL<&6+qiIXPJ zn5nHZ>l>nhA<2kLv9h+Yoo8o1-^F$D5;ynnmeRcF3~wK%FNYfv8WtWA8S_)@y7fPA zh}*V(N5Zd(zwO+WmcDmi#{SF$2ao0ElfE(G_GON(o)iLATG?XFcA1?X_;yI zvSTcqc2tL#8I|vuWS#yt*^!sX~W2?XuFj zFzsx=rWNuP+=%Sf40YdIX*EgZJ4s%nJET<9XO%wOonQWXvcavlE(dFCl?@v%m30xi zYm%`xZ{ZVos*60FOPgw)2yW{PPvbMGo3TFi??T=$`EzWVt zF7*$1NVS%WgZA`TmC&vCEToqlIfTo(d&g*!_Ssc8cQ|>JW+bdV;9GIoFT;U|J#JGS zvnKlIk!_(_E32YT{rPQF7pbnHBxtSjtG&f@Ulfk}LACmV-$QoG$=Z&N+U8oh-{YH3 zkEBFmmd`m=+;XeC_*VAeD*yWGzk8m$1jtUwENi@TBaeEkt$gI;*$@9d@{$&_cXzOE zm|@Rvrf2i7hr3uMT2&bD+*_j+GR3^~O6gJ4{L6{~4)! zUbz1D=JKbVr#Q{c9$~RWGS`Gqw#(rL$tiEd>MN_pHZQxmFzH*|(tg_?4D;6Un zVDF85_p{{(Ew*CPVo+5tiH=4 zbzbcV4frYc!Gq*qBHi}f`{#K39Y3iQkCyVXl6e7~yf0(odq-_%d@4KIl4<4X_uW? zFWNM7pI_a+RLf)acGagVf2-R~9v+{N_2A4mi#N2*eH|30YZh^Wv-$F0s@ziF`#l#b zq8qDuh$iXv?age(&o@aB85&E`>X6Cr>Tj|kD zFCMvANL&8EYjvy=JB#ZSjM*+?nsq^)^>9s2IHQ^uuLEOw)JdF@LUJJF|n0mnWs zc9!kjT;DjI3|v~=$3wh5bgb_;PmYE~vuL?3W1iIher^`Iw4&KvYsIa$=)7f3OC77U zW7x^HOzRf~!KaNd$1sm?WUcUVkU4Vu^vbYfay(>ZMnuH5k;UClyiGz2q^fTh)+#NH zT7Rkicx`1$WfF;pq($_EB_?XOc3k7MB)b_mN6#uYwoa& zt6to14cj`i`$V}k&1`ACsn-4F%pP^pl4B7Z?HYfnO{b(T)TJI$O}cl!70xZU+eXoE5PrSaWA+v+Bkre0g+=H^amjGYrwmcEPqtIajX zE1dIcKfgL~V8RS9hw%A+meC`li>eo&d~TZBRc&;fhcK3R-=i-Gew!|rDb=7pKlPFF z_;TGntd==vZ$IN9hc;dv-AP8`?K*SI+KXvb&6GRqUKODY?d+;)1?A<9X#w}D-+aII za^y|iYi-vf$JRd~nJ#ZFY*E)te(?6pGBt(A%MT`}SZ%O%^m48^J@3(6mhJ4z5k0j& zC#yo|jqj0vipNDKMC$JSb+_5G)mc>CsSEt0_SYB17^|JUc4;xUR@wb=74@ilhi&cZ z`gN_pZLN*Zzp6f>xyt{r?ABHFm7DyhI;(R!;v=^&oxjoE{iIW}Gov)dU}cMmN;Idw zGoois^Izjz}g(N zeeJ5ce2&`>v;DFyUTq$)p7)Q^7M*~~LaCsxOH%daF19JYX9?$yr#N>KBS=xZY7bXE zlaJmRSeCzIYGnJPGg1x}EMk=D?BVjOlYDZIlE# z;roloJ-1T2wEo~BZZB+t8lE?ljj>+|V z?_Y6L4@*6~=&;5~$CmO5#k3TyCzCpRI(D8leuYk*GxSOJWfS-7`ek2hPz>9ezxdDO_MD3)b64i(otg1cE9yjJhHRwgiAMYVsf`PhVvbf> z9WFb>Y@Xw08j^QLIkCXV%seu#;WQ;XGyHhR;{2)fjZdoe7Cgf5k12PGPe@cM$$fY? zasIb@2H!XJ`09qOt|7Oz#GMCr52HvAblhTD;O_pQeh% z+@Fo44=fCI8eO_HR?}5J-!g0D%)}oowy&FBTxtiZKoaSGo9U3{IA3lZwSpxHS`P>5NI7Z9CSs zzCJZ?&EYWp-SyE=%dhWmz{*NnKQbaLND7Y$XH*y(wT_+VZogzh`3CI;r!<~x-BH<6 zYc#=Qd^n@%%HGBeT1B2mV-iL(X1HkWo*92|*TPQA+q8t2apj$u;f-+DRVb+!TZ5{c2}0t_wCzXMK0So71LdPzBpu=OZ%G3 zYTq}N{o+uWu$CBWi3vALXa9+bDKKx{b!VBM`hI2eb*JXnAad)^hi^T0C+dDpMP>Cl z@1@<{NanTR(;2VBmm$c=WlUFhuDinm3XRRurFyYF>AK;pK>pjgu~~Q^mF7q1YIxGU znE@u6t%c__HJDx|nr;RTIEO$hx)0MXGMMfXxzLps=|>}bX_}cT8i!L*2P`_5su9le z58zP3O*Hv_DQFo~>uGB6O}Kt0n(pXM(uy5S*C6T=b#YjmaAqi8(^OHzIM|CpakjSY zbAjHOX!>xuffPNxu&^-QFoG^S*jrDZOeX8$@OpSW7PY`~A_BP7aBKia3%Ka@VNK`I zf|-F_CObd__@sKWL%1fInrOQQd&rU>e;flpes<5_I83d)GfOB-o!Hju%aj?oVf-rW_Pi{{u*{ z=YH1%NZ`$61@e2LVt-)CWisB2^#M1~!VgD~2-^Lf-w&)|?0jR?%E5tR&8CF_diK^P zngE~T#ilX6DEuOsgu^k=O){3`;sMr8E5@}f~}*}*I-I-E=v)tjyt z7~svv0D@C27TKF<;&pNFYZm!axeT;}iRJ=kKuGxe23IDF?!u)4HT6k2vJru#j|N~! zAmfbQ8!e#+bI_RxeDY6E_$^>qC}=RKuv9QlQ3w2bG!}|gFrCU}2fMP_{wA95&RyO$ zJD`t~7nMu3rgG`1(|0E^uJ9ygHcp>{>!lCeIk3H$j0j=Y;Nj6QM(xodw_|cp{0M$k z?-S)h59+<^z4d4EA0-V9{zE~b(t1PSP($fne4ePU-X@w4HNcyWt{#2U71lEcm!BRv3p(F;TO zgVyRB z!3P2sBmv4`7%VNF5n*#dM4(3i_20kSHKgK%#&|f&ZQY;Okp(tru1n z`gJVK0c?lBk^>6x`Xd3>DL+Do0Lm}8Lx$imhtB)o!}`H;ksm|B9WrnTwrOCa8p{39y|~*qp$dHH{^Ps; zfN=LL>V{Qh1t2t#8AcCINB|(nhnmDDAP5A&L4r9bi@SLp5&Y5P-?U!vjf3$QDXMWC9Qv0Dy>L zq!6%w4qj-9_z6OPRUr}q2o9wd2Hu~{VD~}^0Pvv#i*jf&=(iyR2N8n{$l5ov2MbE9 zwoeie1P2}gIEbjf{Gc9OLrnt`5CyzH@K8wzoddve|HuWwKpRZp-~t|M^ycr|piTe$ zBL(_L-@gL{2f*MGJSPD6upRURM?7Ex1E2l^^!7hvMXO`bY>! z6p$z&Q9z=AM1lXF0)p=jqI^q!@{LH8&Vn`&xNjTxKm5-WMW3{bc@Vp9q|S zg9&j+h)e*0i?U4zukbUcPZN4DA(jFVy#LM^I{BPj=sGYIaIlXM*gp))Z%_h);9y+8 zMjDg=1O(t>fCT#smPIDe9~ABv1%Kut=vdV9phE!mfxSE7 z5C3%q00##X;DSUTpg0o{^cj=@Fn}Zkfk4#YS^pAAq#@|r5%ag{f=4p&R}|tLNc1Ny z5&_T&lIVZ<0NVQ3_1S_Zp-E%{z!M|^y$S%mJA@LbgJy%~lJfzfPr;!2eSt;^f&XO% oZZz$gjZUJC;QtHIJDL7RRJA)n}yanmfx@aKX0H!f&c&j literal 0 HcmV?d00001 diff --git a/resources/pc_background.png b/resources/pc_background.png new file mode 100644 index 0000000000000000000000000000000000000000..e47e082452eed14cb55682cb0fefc1ad8b8fb69e GIT binary patch literal 170849 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