From aa53eab253b8818cf61fa517e311af5dabb0e33c Mon Sep 17 00:00:00 2001 From: Andrew Livy Date: Fri, 20 Dec 2002 19:05:54 +0000 Subject: [PATCH] Added Elements to Ez2MusicSelect so that it looks similar to pump, added the "Guide" Graphic to Pump's Select Mode, Returning from Gameplay now goes to the correct SongSelect Screen based upon theme metrics. --- stepmania/Themes/default/metrics.ini | 37 ++-- stepmania/src/MusicBannerWheel.cpp | 27 ++- stepmania/src/MusicBannerWheel.h | 5 + stepmania/src/ScreenEvaluation.cpp | 4 +- stepmania/src/ScreenEz2SelectMusic.cpp | 226 +++++++++++++++++++------ stepmania/src/ScreenEz2SelectMusic.h | 26 ++- stepmania/src/ScreenGameplay.cpp | 5 +- stepmania/src/ScreenMusicScroll.cpp | 1 - stepmania/src/ScreenSelectMode.cpp | 6 + stepmania/src/ScreenSelectMode.h | 1 + stepmania/src/plib-1.6.0/sg_d.lib | Bin 253428 -> 253428 bytes stepmania/src/plib-1.6.0/ul_d.lib | Bin 100098 -> 100098 bytes 12 files changed, 255 insertions(+), 83 deletions(-) diff --git a/stepmania/Themes/default/metrics.ini b/stepmania/Themes/default/metrics.ini index b9d0594067..82a5e5a6fb 100644 --- a/stepmania/Themes/default/metrics.ini +++ b/stepmania/Themes/default/metrics.ini @@ -92,6 +92,8 @@ JoinMessageP1X=120 JoinMessageP1Y=336 JoinMessageP2X=520 JoinMessageP2Y=336 +GuideX=320 +GuideY=374 HelpText=Press $ on the pad to join. Press ! " to change styles, then press START TimerSeconds=40 NextScreen=ScreenSelectGroup @@ -228,31 +230,14 @@ ScoreConnectedToMusicWheel=1 SampleMusicDelay=0.25 [ScreenEz2SelectMusic] -BannerX=320 // central banner -BannerY=240 // central banner -BannerWidth=200 -BannerHeight=200 -ScoreFrameP1X=80 -ScoreFrameP1Y=60 -ScoreFrameP2X=560 -ScoreFrameP2Y=60 -ScoreP1X=80 -ScoreP1Y=60 -ScoreP2X=560 -ScoreP2Y=60 -MeterFrameP1X=82 -MeterFrameP1Y=432 -MeterFrameP2X=238 -MeterFrameP2Y=432 -MeterP1X=88 -MeterP1Y=432 -MeterP2X=228 -MeterP2Y=432 -WheelX=999 // hide -WheelY=999 // hide -HelpText=! or " change music Hold ! and " then press START to change sort::## easier difficulty $$ harder difficulty::#$#$ to change sort -TimerSeconds=60 -ScoreConnectedToMusicWheel=1 +PumpDifficultyX=320 +PumpDifficultyY=280 +ScrollingListX=320 +ScrollingListY=240 +MeterP1X=999 // by default hide these elements +MeterP1Y=999 +MeterP2X=999 +MeterP2Y=999 [ScreenSelectCourse] ExplanationX=132 @@ -283,6 +268,7 @@ TimerSeconds=60 StageType=0 // 0 for MAX, 1 for Pump, 2 for EZ2 [ScreenGameplay] +SongSelectScreen=ScreenSelectMusic BPMX=999 // don't show by default BPMY=999 BPMZoom=0.0 @@ -352,6 +338,7 @@ DemonstrationSeconds=30 TickEarlySeconds=0.058 [ScreenEvaluation] +SongSelectScreen=ScreenSelectMusic BannerX=320 BannerY=100 StageX=320 diff --git a/stepmania/src/MusicBannerWheel.cpp b/stepmania/src/MusicBannerWheel.cpp index 240cbeefbc..6ea0264fb9 100644 --- a/stepmania/src/MusicBannerWheel.cpp +++ b/stepmania/src/MusicBannerWheel.cpp @@ -17,6 +17,7 @@ #include "SongManager.h" #include "ThemeManager.h" #include "RageMusic.h" +#include "StyleDef.h" #define BANNERSPACING 200 #define MAXSONGSINBUFFER 5 @@ -34,6 +35,24 @@ MusicBannerWheel::MusicBannerWheel() arraySongs = SONGMAN->m_pSongs; + // If there is no currently selected song, select one. + if( GAMESTATE->m_pCurSong == NULL ) + { + currentPos=0; + } + else // theres a song already selected (i.e. they came back from gameplay)... + { + // find our song and change the currentPos to wherever it may be. + for(int i=0; im_pCurSong == arraySongs[i]) + { + currentPos=i; + i=(arraySongs.size()-1); // get us out of the loop by moving i ahead to the end + } + } + } + LoadSongData(); m_debugtext.LoadFromFont( THEME->GetPathTo("Fonts","small titles") ); @@ -123,7 +142,6 @@ void MusicBannerWheel::BannersLeft() else currentPos--; - if(scrlistPos==0) scrlistPos = MAXSONGSINBUFFER-1; else @@ -133,6 +151,7 @@ void MusicBannerWheel::BannersLeft() LoadSongData(); m_debugtext.SetText(ssprintf("currentPos: %d scrlistPos: %d",currentPos,scrlistPos)); m_ScrollingList.Left(); + ChangeNotes(); } void MusicBannerWheel::BannersRight() @@ -151,8 +170,14 @@ void MusicBannerWheel::BannersRight() LoadSongData(); m_debugtext.SetText(ssprintf("currentPos: %d scrlistPos: %d",currentPos,scrlistPos)); m_ScrollingList.Right(); + ChangeNotes(); } +void MusicBannerWheel::ChangeNotes() +{ +} + + MusicBannerWheel::~MusicBannerWheel() { } diff --git a/stepmania/src/MusicBannerWheel.h b/stepmania/src/MusicBannerWheel.h index b9f41525fa..b952bd919e 100644 --- a/stepmania/src/MusicBannerWheel.h +++ b/stepmania/src/MusicBannerWheel.h @@ -17,6 +17,10 @@ #include "ScrollingList.h" #include "SongManager.h" #include "BitmapText.h" +#include "SongManager.h" +#include "PlayerOptions.h" +#include "SongOptions.h" + class MusicBannerWheel : public ActorFrame { @@ -30,6 +34,7 @@ private: void SetNewPos(int NewPos); void PlayMusicSample(); void LoadSongData(); + void ChangeNotes(); BitmapText m_debugtext; diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index 879ef1c779..084e0d6f7c 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -25,6 +25,7 @@ #include "ThemeManager.h" +#define SONGSEL_SCREEN THEME->GetMetric("ScreenEvaluation","SongSelectScreen") #define BANNER_X THEME->GetMetricF("ScreenEvaluation","BannerX") #define BANNER_Y THEME->GetMetricF("ScreenEvaluation","BannerY") #define STAGE_X THEME->GetMetricF("ScreenEvaluation","StageX") @@ -818,7 +819,8 @@ void ScreenEvaluation::HandleScreenMessage( const ScreenMessage SM ) MenuStart( PLAYER_INVALID ); break; case SM_GoToSelectMusic: - SCREENMAN->SetNewScreen( "ScreenSelectMusic" ); + // SCREENMAN->SetNewScreen( "ScreenSelectMusic" ); + SCREENMAN->SetNewScreen( SONGSEL_SCREEN ); break; case SM_GoToSelectCourse: SCREENMAN->SetNewScreen( "ScreenSelectCourse" ); diff --git a/stepmania/src/ScreenEz2SelectMusic.cpp b/stepmania/src/ScreenEz2SelectMusic.cpp index 661b210cc0..d94ba9234a 100644 --- a/stepmania/src/ScreenEz2SelectMusic.cpp +++ b/stepmania/src/ScreenEz2SelectMusic.cpp @@ -1,14 +1,13 @@ #include "stdafx.h" /* ----------------------------------------------------------------------------- - File: ScreenSandbox.h + File: ScreenEz2SelectMusic.cpp - Desc: Area for testing. + Desc: See Header Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. - Chris Danford - Glenn Maynard (OpenGL Code) - Lance Gilbert (OpenGL/Usability Modifications) + + Andrew Livy ----------------------------------------------------------------------------- */ @@ -27,12 +26,27 @@ #include "GameConstantsAndTypes.h" #include "PrefsManager.h" #include "ThemeManager.h" +#include "GameState.h" +#include "StyleDef.h" +#include "InputMapper.h" +#include "CodeDetector.h" +#define SCROLLING_LIST_X THEME->GetMetricF("ScreenEz2SelectMusic","ScrollingListX") +#define SCROLLING_LIST_Y THEME->GetMetricF("ScreenEz2SelectMusic","ScrollingListY") +#define PUMP_DIFF_X THEME->GetMetricI("ScreenEz2SelectMusic","PumpDifficultyX") +#define PUMP_DIFF_Y THEME->GetMetricI("ScreenEz2SelectMusic","PumpDifficultyY") #define HELP_TEXT THEME->GetMetric("ScreenSelectMusic","HelpText") #define TIMER_SECONDS THEME->GetMetricI("ScreenSelectMusic","TimerSeconds") +#define METER_X( p ) THEME->GetMetricF("ScreenEz2SelectMusic",ssprintf("MeterP%dX",p+1)) +#define METER_Y( p ) THEME->GetMetricF("ScreenEz2SelectMusic",ssprintf("MeterP%dY",p+1)) +#define GUIDE_X THEME->GetMetricF("ScreenSelectMode","GuideX") +#define GUIDE_Y THEME->GetMetricF("ScreenSelectMode","GuideY") + +const ScreenMessage SM_GoToPrevScreen = ScreenMessage(SM_User+1); ScreenEz2SelectMusic::ScreenEz2SelectMusic() { + CodeDetector::RefreshCacheItems(); m_Menu.Load( THEME->GetPathTo("BGAnimations","select music"), THEME->GetPathTo("Graphics","select music top edge"), @@ -40,52 +54,102 @@ ScreenEz2SelectMusic::ScreenEz2SelectMusic() ); this->AddChild( &m_Menu ); - m_MusicBannerWheel.SetX(CENTER_X); - m_MusicBannerWheel.SetY(CENTER_Y); + + m_ChoiceListFrame.Load( THEME->GetPathTo("Graphics","select mode list frame")); + m_ChoiceListFrame.SetXY( SCROLLING_LIST_X, SCROLLING_LIST_Y); + this->AddChild( &m_ChoiceListFrame ); + + m_Guide.Load( THEME->GetPathTo("Graphics","select mode guide")); + m_Guide.SetXY( GUIDE_X, GUIDE_Y ); + this->AddChild( &m_Guide ); + + m_MusicBannerWheel.SetX(SCROLLING_LIST_X); + m_MusicBannerWheel.SetY(SCROLLING_LIST_Y); this->AddChild( &m_MusicBannerWheel ); + m_ChoiceListHighlight.Load( THEME->GetPathTo("Graphics","select mode list highlight")); + m_ChoiceListHighlight.SetXY( SCROLLING_LIST_X, SCROLLING_LIST_Y); + this->AddChild( &m_ChoiceListHighlight ); + + for(int p=0; pAddChild( &m_FootMeter[p] ); + + m_iSelection[p] = 0; + } + + m_PumpDifficultyRating.LoadFromFont( THEME->GetPathTo("Fonts","pump songselect difficulty") ); + m_PumpDifficultyRating.SetXY( PUMP_DIFF_X, PUMP_DIFF_Y ); + this->AddChild(&m_PumpDifficultyRating); + + MusicChanged(); + m_Menu.TweenOnScreenFromMenu( SM_None ); } void ScreenEz2SelectMusic::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ) { - if( type != IET_FIRST_PRESS ) - return; // ignore +// if( type != IET_FIRST_PRESS ) +// return; // ignore - switch( DeviceI.device) + PlayerNumber pn = GAMESTATE->GetCurrentStyleDef()->ControllerToPlayerNumber( GameI.controller ); + + if( CodeDetector::EnteredEasierDifficulty(GameI.controller) ) { - case DEVICE_KEYBOARD: - switch( DeviceI.button ) - { - case SDLK_LEFT: - m_MusicBannerWheel.BannersLeft(); - break; - case SDLK_RIGHT: - m_MusicBannerWheel.BannersRight(); - break; - case SDLK_UP: - - break; - case SDLK_DOWN: - - break; - case SDLK_t: - { - SDL_Event *event; - event = (SDL_Event *) malloc(sizeof(event)); - event->type = SDL_QUIT; - SDL_PushEvent(event); - } - case SDLK_ESCAPE: - { - SCREENMAN->SetNewScreen( "ScreenTitleMenu" ); - } - } - + EasierDifficulty( pn ); + return; + } + if( CodeDetector::EnteredHarderDifficulty(GameI.controller) ) + { + HarderDifficulty( pn ); + return; } + Screen::Input( DeviceI, type, GameI, MenuI, StyleI ); } +void ScreenEz2SelectMusic::HandleScreenMessage( const ScreenMessage SM ) +{ + Screen::HandleScreenMessage( SM ); + + switch( SM ) + { + case SM_GoToPrevScreen: + SCREENMAN->SetNewScreen( "ScreenTitleMenu" ); + break; + } +} + + +void ScreenEz2SelectMusic::MenuRight( PlayerNumber pn, const InputEventType type ) +{ + m_MusicBannerWheel.BannersRight(); + MusicChanged(); +} + +void ScreenEz2SelectMusic::MenuBack( PlayerNumber pn ) +{ + MUSIC->Stop(); + + m_Menu.TweenOffScreenToBlack( SM_GoToPrevScreen, true ); +} + + +void ScreenEz2SelectMusic::MenuLeft( PlayerNumber pn, const InputEventType type ) +{ + m_MusicBannerWheel.BannersLeft(); + MusicChanged(); +} + +void ScreenEz2SelectMusic::MenuStart( PlayerNumber pn ) +{ + MUSIC->Stop(); + SCREENMAN->SetNewScreen( "ScreenStage" ); +} + + void ScreenEz2SelectMusic::Update( float fDeltaTime ) { Screen::Update( fDeltaTime ); @@ -98,19 +162,81 @@ void ScreenEz2SelectMusic::DrawPrimitives() m_Menu.DrawTopLayer(); } - -void ScreenEz2SelectMusic::HandleScreenMessage( const ScreenMessage SM ) +void ScreenEz2SelectMusic::EasierDifficulty( PlayerNumber pn ) { - Screen::HandleScreenMessage( SM ); - switch( SM ) + if( !GAMESTATE->IsPlayerEnabled(pn) ) + return; + if( m_arrayNotes[pn].empty() ) + return; + if( m_iSelection[pn] == 0 ) + return; + + m_iSelection[pn]--; + // the user explicity switched difficulties. Update the preferred difficulty + GAMESTATE->m_PreferredDifficulty[pn] = m_arrayNotes[pn][ m_iSelection[pn] ]->m_Difficulty; + +// m_soundChangeNotes.Play(); + + AfterNotesChange( pn ); +} + + + +void ScreenEz2SelectMusic::HarderDifficulty( PlayerNumber pn ) +{ + if( !GAMESTATE->IsPlayerEnabled(pn) ) + return; + if( m_arrayNotes[pn].empty() ) + return; + if( m_iSelection[pn] == int(m_arrayNotes[pn].size()-1) ) + return; + + m_iSelection[pn]++; + // the user explicity switched difficulties. Update the preferred difficulty + GAMESTATE->m_PreferredDifficulty[pn] = m_arrayNotes[pn][ m_iSelection[pn] ]->m_Difficulty; + +// m_soundChangeNotes.Play(); + + AfterNotesChange( pn ); +} + + + +void ScreenEz2SelectMusic::MusicChanged() +{ + Song* pSong = m_MusicBannerWheel.GetSelectedSong(); + GAMESTATE->m_pCurSong = pSong; + + int pn; + for( pn = 0; pn < NUM_PLAYERS; ++pn) + m_arrayNotes[pn].clear(); + + + for( pn = 0; pn < NUM_PLAYERS; ++pn) { - case SM_DoneClosingWipingLeft: - break; - case SM_DoneClosingWipingRight: - break; - case SM_DoneOpeningWipingLeft: - break; - case SM_DoneOpeningWipingRight: - break; + pSong->GetNotesThatMatch( GAMESTATE->GetCurrentStyleDef()->m_NotesType, m_arrayNotes[pn] ); + SortNotesArrayByDifficulty( m_arrayNotes[pn] ); + } + + for( int p=0; pIsPlayerEnabled(pn) ) + return; + Notes* pNotes = m_arrayNotes[pn].empty()? NULL: m_arrayNotes[pn][m_iSelection[pn]]; + + if( pNotes != NULL ) + m_PumpDifficultyRating.SetText(ssprintf("Lv.%d",pNotes->m_iMeter)); + + GAMESTATE->m_pCurNotes[pn] = pNotes; + +// Notes* m_pNotes = GAMESTATE->m_pCurNotes[pn]; + + m_FootMeter[pn].SetFromNotes( pNotes ); +} + diff --git a/stepmania/src/ScreenEz2SelectMusic.h b/stepmania/src/ScreenEz2SelectMusic.h index cbdb049f0c..21979ba15a 100644 --- a/stepmania/src/ScreenEz2SelectMusic.h +++ b/stepmania/src/ScreenEz2SelectMusic.h @@ -2,12 +2,12 @@ #define SCREENEZ2SELECTMUSIC_H /* ----------------------------------------------------------------------------- - Class: ScreenSandbox + Class: ScreenEz2SelectMusic - Desc: Area for testing. + Desc: A Scrolling List Of Song Banners used to select the song the player wants. Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. - Chris Danford + Andrew Livy ----------------------------------------------------------------------------- */ @@ -20,6 +20,7 @@ #include "RageSoundStream.h" #include "MusicBannerWheel.h" #include "MenuElements.h" +#include "FootMeter.h" class ScreenEz2SelectMusic : public Screen { @@ -30,10 +31,27 @@ public: virtual void Update( float fDeltaTime ); virtual void Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); virtual void HandleScreenMessage( const ScreenMessage SM ); + virtual void MenuStart( PlayerNumber pn ); + virtual void MenuLeft( PlayerNumber pn, const InputEventType type ); + virtual void MenuRight( PlayerNumber pn, const InputEventType type ); + virtual void MenuBack( PlayerNumber pn ); + protected: + void AfterNotesChange( PlayerNumber pn ); + void MusicChanged(); + + void EasierDifficulty( PlayerNumber pn ); + void HarderDifficulty( PlayerNumber pn ); + + Sprite m_ChoiceListFrame; + Sprite m_ChoiceListHighlight; + Sprite m_Guide; + BitmapText m_PumpDifficultyRating; MusicBannerWheel m_MusicBannerWheel; MenuElements m_Menu; - + FootMeter m_FootMeter[NUM_PLAYERS]; + CArray m_arrayNotes[NUM_PLAYERS]; + int m_iSelection[NUM_PLAYERS]; }; diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index b9ea640d6c..7af4d4ba15 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -33,6 +33,8 @@ // Defines // +#define SONGSEL_SCREEN THEME->GetMetric("ScreenGameplay","SongSelectScreen") + #define MAXCOMBO_X THEME->GetMetricF("ScreenGameplay","MAXCOMBOX") #define MAXCOMBO_Y THEME->GetMetricF("ScreenGameplay","MAXCOMBOY") #define MAXCOMBO_ZOOM THEME->GetMetricF("ScreenGameplay","MAXCOMBOZoom") @@ -1389,7 +1391,8 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) switch( GAMESTATE->m_PlayMode ) { case PLAY_MODE_ARCADE: - SCREENMAN->SetNewScreen( "ScreenSelectMusic" ); + // SCREENMAN->SetNewScreen( "ScreenSelectMusic" ); + SCREENMAN->SetNewScreen( SONGSEL_SCREEN ); break; case PLAY_MODE_ONI: case PLAY_MODE_ENDLESS: diff --git a/stepmania/src/ScreenMusicScroll.cpp b/stepmania/src/ScreenMusicScroll.cpp index 73d11b5b47..00ecf845b0 100644 --- a/stepmania/src/ScreenMusicScroll.cpp +++ b/stepmania/src/ScreenMusicScroll.cpp @@ -115,7 +115,6 @@ const CString CREDIT_LINES[] = "Garett Sakamoto", "SailorBob", "AngelTK (Kenny Lai)", - "spds (James Sanders)", "Illusionz - Issaquah, WA", "Quarters - Kirkland, WA", "Segapark - Bournemouth, UK", diff --git a/stepmania/src/ScreenSelectMode.cpp b/stepmania/src/ScreenSelectMode.cpp index e99964d2b6..3a2ab1e73b 100644 --- a/stepmania/src/ScreenSelectMode.cpp +++ b/stepmania/src/ScreenSelectMode.cpp @@ -34,6 +34,8 @@ const ScreenMessage SM_GoToNextScreen = ScreenMessage(SM_User + 2); #define JOIN_FRAME_Y( i ) THEME->GetMetricF("ScreenSelectMode",ssprintf("JoinFrameP%dY",i+1)) #define JOIN_MESSAGE_X( p ) THEME->GetMetricF("ScreenSelectMode",ssprintf("JoinMessageP%dX",p+1)) #define JOIN_MESSAGE_Y( i ) THEME->GetMetricF("ScreenSelectMode",ssprintf("JoinMessageP%dY",i+1)) +#define GUIDE_X THEME->GetMetricF("ScreenSelectMode","GuideX") +#define GUIDE_Y THEME->GetMetricF("ScreenSelectMode","GuideY") #define HELP_TEXT THEME->GetMetric("ScreenSelectMode","HelpText") #define TIMER_SECONDS THEME->GetMetricI("ScreenSelectMode","TimerSeconds") #define NEXT_SCREEN THEME->GetMetric("ScreenSelectMode","NextScreen") @@ -76,6 +78,10 @@ ScreenSelectMode::ScreenSelectMode() m_ChoiceListHighlight.SetXY( CENTER_X, SCROLLING_LIST_Y); this->AddChild( &m_ChoiceListHighlight ); + m_Guide.Load( THEME->GetPathTo("Graphics","select mode guide")); + m_Guide.SetXY( GUIDE_X, GUIDE_Y ); + this->AddChild( &m_Guide ); + for( int p=0; pGetPathTo("Graphics","select player join frame 1x2") ); diff --git a/stepmania/src/ScreenSelectMode.h b/stepmania/src/ScreenSelectMode.h index 6420306895..13ceac2f62 100644 --- a/stepmania/src/ScreenSelectMode.h +++ b/stepmania/src/ScreenSelectMode.h @@ -54,6 +54,7 @@ protected: Sprite m_sprJoinFrame[NUM_PLAYERS]; Sprite m_ChoiceListFrame; Sprite m_ChoiceListHighlight; + Sprite m_Guide; CArray m_apPossibleModeChoices; diff --git a/stepmania/src/plib-1.6.0/sg_d.lib b/stepmania/src/plib-1.6.0/sg_d.lib index 30e5be7122827a010d6c236a926a6e028c031164..798a196a4cb4a63a284822980288c34d9888ebb1 100644 GIT binary patch delta 3174 zcmaJ@Yitx%6uysT``T_xDI4q-TDPR6T55N@ot?pmHO01R7h0eqi3r6OF~WCKz2& z0l*Y;(+QoyA!E)(SzaAAWuiR(kXvpjOpr(Ti?JjK!TJ8R#j%GKHUt2?I71%ao=qOt zLWey`xqk950Plq3vgGA~3}nq9b#vip`BvcT$O3s`5R4D@v>k;JNZ~r=8(S^%Rni#& z8Bad7!Tw`NNY{|Zc79TYXukW$g{&WcST%*Ow0siRKOpO7+rffV8yruq=ufLx~@0G&_ z82sware~hwQ+lLIay=P3+j?Pi*dme%;WBMm^@#RD$eE;uq>;LMm_#38m}=M?tr!4z z4A2A^S&V}QKdH+G7jdDCc01lgJ8y>w8`M&h;GGCWl?qpCLR1ktXVrO2&N`vpqP7;j z=7bp$Pu;|u0mrMx(v}Q3Lho#8M#9X9tF^qVS5p7q(DHhnp*hV?ox z9VtS-Pmt2pPgSfRmIBq*OGg11gykoNDYU2s{u&pq(@iD?px>$(oRd3>4Bd{L^ke}3 zKGe{{^smeCF}A&&rZ%wpEli{Le}PA8pW?HFJSsx5;RIRa<4P10TTnf3Zhg+In*Jdt zD~ge!gH_kxfo4W2}13$cQK2*G)phCL__1j&6Jd)o2xk?qSZGX1U&}Cb=`yOft$u(;wmfwTuPw#g6e=PyB()K150RQioNXyDS$L5I8u2Pkn|1w!4>12Y zQKI8%>2hqE!-Gv&n?tJ5OoyanCBDiH22*sggS@hK!)FPo@55iK0lGKEp1qp)Tw(ZR~Uhug5Cs{K8ZT zt@;vAX6Nbm`>^p`JhdO!X-Vj`1Nb-2OeLqCE)L>_9LCDd{065Yi;$}vwnfw^N-7TV zb+Ld^-{B7KtWD@LZiZTq;1!Ygp)A(j;ZP8aRimlKulFj>A&` delta 2973 zcmZ`*du&rx7(b7)bzApfj0V>-Mh7(r%(m;}76X~gj0Fl*oJbl=o<4I1Ip4 z^1BV%qWxYtpA1V##~e6J&I(P#Zod>=5L!1THJ{-i0N}Yw#W^}Hn>|1I2Y@$Cadd5@ z0Noux=FNqpS{F0D-VTvomUR!ndPQq zcJlR5_?etv?xi0`VaOqSZ=cC*GXr2@C8vQOl_&YedqZf~M7R`2zq+&eDM6i(n)rpyCgmAg)RFt8e5Ngs824@0R!)*E(L%X3e8tw(R_fn5?pp*s;3Q~s!F47Kh z$nA6iaxnuUY+$ix!#i;UWf`qf2`D2tpJdRIoU_3UlhQEsx(ycSH6-2w_@W{rtuKI2 z|CfrSYXUrzc}kP5`3L}gu>7PXmzLJUU(@2bvB@)&$q^VzVu}{JMv(s7kd2;*z(4x;=+82zWqY2| zm&$ur9=-nyJUmBGb2NEeic;0WKPpElsl}D^=T;Zatcp)8Svdw78dK3WgO-({9h#i% zTsqAki;N>j>c=6i4LM|C2od<59!I@~QmJ|nnFdHQy1LpKxF^5I-QGbLbzne5I5D0fI z6v5$l(77CSWPNPCTZyy=Wtj#mBO6+S#`TUz;|+FUD;mc~Hg_AUa87U)^#&=3wUP2l z9u)HWi(KBGCSOmJzo#icem;uw2swdz(?`cpYp))C8*xS; zDo;WA`00ZESnTJ8Y+Qkp$)@|rq6)?h9ikztTR?=nkz_d1-i`7NhO7rDM>M3-$_Hq8 zeUCZ1z6@(~#1cp$_8Oen?o~B-m}z(8%)d#b2Cr5*c^^-DA1C%aJDE<$)?#6j4%T6H zk|=`+i_E$TU(?#0Gd%O5z(6c4=@6+0lLoRR7!p0y+HtKje z#MywIIUcW>wFhR`g2AAd#&~@JPZ6nTz@>dX?xXClfx+WiPi8dWzNDi8Z_jc2<_Lbb zm)32@7C7JKvKU?dpaeuq-~tb-1@;GhM@5Twy=d{&i57QA9@yBIWJU1vR=*T17W|TA zQT((fg1^%wn%;!9jl{K>Oa!@#x8TGAi8q#l1 z!k`4A=o35(=6GD?#*2~Mep>e_c4+N#X|GVk>6Qc&kKX#Z5S>=MAyMbv6orM%8iH#6Oq~@n5QU;f$u4%Cg`5ys_g$<6IUfUy)2&ce0QQSe*&@T{35D)s@lp zL4*fyF|syEv%W8>5kAbe;0Yu2_FNCBVT{j<%ynQsHeW7Pfp0N3E&y`@2*+~Bav%CFW zxNu`$!~5$_-sAV;$|0SfA2fHe@(5GQ z4l`N~k#a~eFMRT1u?b&WBGgJ(Mw8*ZP^-h{4%1ido$!@0_k?p3%lSWJg$bMb{givM zgX8C2e|c_VvLIWU502OHLzCaRklaKKe`o3dw#B+NwH6B<`Ln5PoKV?O(w-njb$f-J zlyWxxjq9$RO@83bmVQ{*N>qkY;$}pA0ptur)ls|@(PXr#h}adh2DDKiu9}*{M<0G( zsQLPrM}Bm7cloDg##FSgn8uzvqo~z`5Y+5J6uxwZGDTqmM@z*gx^ylxbf|dLX2o>0 zUmz}4EW=OE3}J=JX62(^mys?$SyxS?RDMntm@?KJ-mqDoo#TuGY*&P;bs*3 z^TrSQzyA|9N~LSz@{ci!A#b3wugbEz%4x@GY0q{_WSK7WBE)*%2NA%sqFcRwn8pRq z866cc--UIe0{$y)BV>FVfp)tW3!=~go)^KIc?EW?U!3UIv_Q1U@~d#)S1kKDlP^1$ zfrH+%!;R4Dlzr9+>nh4LTvHo;SJ=qjw+QMATYq)Kc&wDiE*41PGX9&x)=VCGO86i33mV!SvMw5!4T8cW|3M<#9k9yQ=$`lb4n1U!GmZSW4I62 r#)+nw_&$xd{V*YdI zoNxYf&SZLmnVw+oy^y4T%z>5;Rmrr{__i7G_lvQ-vClH z*8U;gKNg}-D%N76YD}E-SAaI;s(aJ$D}B-?v&cMuT{II!s1hL*LD?Xi*VG-Dewyb1 zt~Bl7DL$wFd^+7uHX~g{lc|tz;(g;PhGq0x!*}WESA)@B&KtFO z`-1HB*IPWitu||}z1HDm&)ZK-bD?@OHq?#G4qRl@=Ij@iO&79ps1y@I426BXPT`tX z-y%z*s?bN@9$O-6dRa(Q%O!>Wbd;?jWf6%;-op|R%Oz4S3GC3>1HxtMgJX`>LyFvs&TrQ9i+|xCG+#?uG{BqpR$AV>9#x0 zQ!;-L7hJiVuf^Oj`Z%ACi>hu}R%j7M^&7Zv36W|;zZYd7cbyEghL<;snu==p=?K4r z$Z}d!P~4;FXsN3dvT7P?;7U;)U7-EL$0zHs-S=?uCtUhtp++RM(apg-%56u@9)+N! zM-k}k5m_UO%5^lG-~6+zmsPaQJ<5?JqM%J&agijFpod3#_*m&|=Kap1&G=>19>Qy* z-45seu}#(h-Wj`zJ$q{P_{X`?Fa6H4?(|=J3Jt!}_S(a5^kHzO|JY(dmZ~jki+ueG zSrTM%j#nY(K0ibN3yNZP24DzJEsW6?hDliSP#9jhv?1e61X>HoCPbkPyqj!}yaTHi z{y*UvsRcj~>?VM}qnTq87F^&U4uUD)H%vw%6?3~#EVSNIMThADz> zgw1DrU@%t7u-1pIpQF*(0W+PSg!z33>;)eo#>+!c=Oco#pc5v1qGW~+!*#%-tQfby zfgVkel00|7@~^(&rX&!}s|Z4=BI*ev*9En4QCDibA=wz{f|G?!GWHw+zDlZW{%{1U Td~r!tHk6*0c