From 1220dbe085f686fee331d225e778e3522e9285bc Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 4 Jun 2013 23:47:22 -0400 Subject: [PATCH] Revert "Round 2-2 of this." This reverts commit 0ae4183f7ba16647230d4680efea90f729fd8614. --- Docs/Luadoc/LuaDocumentation.xml | 2 +- Docs/Userdocs/sm5_beginner.txt | 1 + Themes/HelloWorld/screens.txt | 1 + Themes/_fallback/Languages/en.ini | 16 + Themes/_fallback/Languages/es.ini | 16 + Themes/_fallback/Languages/ja.ini | 16 + Themes/_fallback/Languages/nl.ini | 16 + Themes/_fallback/Languages/pl.ini | 16 + Themes/_fallback/base._ini | 21 ++ Themes/_portKit-sm4/metrics.ini | 21 ++ .../project.pbxproj | 20 ++ src/Bookkeeper.cpp | 261 +++++++++++++++ src/Bookkeeper.h | 93 ++++++ src/Game.cpp | 1 + src/GameCommand.cpp | 79 ++++- src/GameCommand.h | 6 + src/GameInput.h | 1 + src/GameState.cpp | 31 ++ src/GameState.h | 3 + src/InputMapper.cpp | 9 +- src/LightsManager.cpp | 12 + src/Makefile.am | 2 + src/MessageManager.cpp | 1 + src/MessageManager.h | 1 + src/PrefsManager.cpp | 2 + src/PrefsManager.h | 2 + src/Profile.cpp | 30 ++ src/Profile.h | 4 +- src/Screen.cpp | 1 + src/ScreenAttract.cpp | 5 + src/ScreenBookkeeping.cpp | 315 ++++++++++++++++++ src/ScreenBookkeeping.h | 73 ++++ src/ScreenContinue.cpp | 3 + src/ScreenDebugOverlay.cpp | 3 +- src/ScreenSelect.cpp | 5 +- src/ScreenServiceAction.cpp | 12 +- src/StepMania-net2008.vcproj | 16 + src/StepMania-net2010.vcxproj | 4 + src/StepMania-net2010.vcxproj.filters | 12 + src/StepMania-net2011.vcxproj | 4 + src/StepMania-net2011.vcxproj.filters | 14 +- src/StepMania.cpp | 71 +++- src/StepMania.h | 4 + 43 files changed, 1214 insertions(+), 12 deletions(-) create mode 100644 src/Bookkeeper.cpp create mode 100644 src/Bookkeeper.h create mode 100644 src/ScreenBookkeeping.cpp create mode 100644 src/ScreenBookkeeping.h diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index f2504a4f5f..fab6b8e330 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -2339,7 +2339,7 @@ save yourself some time, copy this for undocumented things: Resets the specific Player's mods to the default settings. - Saves the machine profile data. + Saves the bookkeeping and machine profile data. Sets the current for the specified . diff --git a/Docs/Userdocs/sm5_beginner.txt b/Docs/Userdocs/sm5_beginner.txt index 966c10994f..24c31d8535 100644 --- a/Docs/Userdocs/sm5_beginner.txt +++ b/Docs/Userdocs/sm5_beginner.txt @@ -156,6 +156,7 @@ menus were re-shuffled around for the StepMania 4 alphas. The typical StepMania 3.9 Options Menu: * Appearance Options * Background Options +* Bookkeeping * Center Image * Coin Options * Config Key/Joy Mappings diff --git a/Themes/HelloWorld/screens.txt b/Themes/HelloWorld/screens.txt index ee3ca9203b..a046631d70 100644 --- a/Themes/HelloWorld/screens.txt +++ b/Themes/HelloWorld/screens.txt @@ -78,6 +78,7 @@ ScreenUnlockCelebrate * ScreenAttract +ScreenBookkeeping ScreenEdit ScreenEditMenu ScreenEvaluation diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 6784dc74d5..100dcd63ea 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -5,6 +5,7 @@ StepMania=StepMania [LoadingWindow] Couldn't open any loading windows.=Couldn't open any loading windows. Starting sound subsystem...=Starting sound subsystem... +Initializing bookkeeper...=Initializing bookkeeper... Starting lights subsystem...=Starting lights subsystem... Loading game type...=Loading game type... Building song cache index...=Building song cache index... @@ -349,10 +350,12 @@ BGBrightness=Controls how bright the background will appear. Turn this setting d Background=Change options that control the backgrounds that play during gameplay. BarDrain=BarDrain BatLives=BatLives +Bookkeeping=Check coin drop statistics. Calibrate Machine Sync=Calibrate the audio synchronization. CelShadeModels=Choose if dancing characters are drawn with cel shading. Center Image=Center the image on your monitor. Characters=Characters +Clear Bookkeeping Data=Clear all coin drop data. Clear Machine Edits=Save all step edits saved to this machine. Clear USB edits=Clear USB edits Clear Machine Stats=Clear all scores saved to this machine. @@ -847,6 +850,7 @@ BarDrain=Bar Drain BatLives=Bat Lives Base Difficulty=Base Difficulty Beat 0 Offset=Beat 0 Offset +Bookkeeping=Bookkeeping Calibrate Machine Sync=Calibrate Audio Sync CPUSkill=CPU Skill CelShadeModels=Cel-shaded Models @@ -856,6 +860,7 @@ Characters=Characters Chart Name=Chart Name Chart Style=Chart Style Choose=Choose +Clear Bookkeeping Data=Clear Bookkeeping Data Clear Machine Edits=Clear Machine Edits Clear Machine Stats=Clear Machine Scores Clear USB edits=Clear USB edits @@ -1274,6 +1279,15 @@ HeaderSubText=Get the best performance HeaderText=Advanced Options HeaderSubText=These settings are for advanced users +[ScreenBookkeeping] +All-time Coin Total:=All-time Coin Total: +Total Song Plays: %d=Total Song Plays: %d +Coin Data by Day of Week, All-Time=Coin Data by Day of Week, All-Time +Coin Data by Hour of Day, All-Time=Coin Data by Hour of Day, All-Time +Coin Data of Last %d Days=Coin Data of Last %d Days +Coin Data of Last %d Weeks=Coin Data of Last %d Weeks +HeaderText=Bookkeeping + [ScreenCaution] Caution=CAUTION! CautionText=Keep the dance platform a safe distance from your monitor and furniture.\n\nBe careful that you do not injure pets, children, or spectators while dancing. @@ -1635,6 +1649,7 @@ HelpTextTextEntry=Type a value using the keyboard. Press Enter to finish. HelpTextMapControllers=Use arrow keys to move, ENTER to assign, SPACE to clear::Press ESCAPE when done HelpTextOnline=smonline.us to connect to official Stepmania Online Server::Check out Stepmaniaonline.com for more information HelpTextNetSelectMusic=Ctrl + Enter to enter room/select song::&UP; for Player Options +HelpTextBookkeeping=Press &MENULEFT;&MENURIGHT; to cycle data. Press ESCAPE when done. [ScreenSelectGame] HeaderText=Select Game @@ -1674,6 +1689,7 @@ HeaderSubText=Let's get started. I know you can! %d edits cleared, %d errors.=%d edits cleared, %d errors. %d failed=%d failed %d ignored=%d ignored +Bookkeeping data cleared.=Bookkeeping data cleared. Copied from P%d card:=Copied from P%d card: Copied to P%d card:=Copied to P%d card: Edits not cleared - No memory cards ready.=Edits not cleared - No memory cards ready. diff --git a/Themes/_fallback/Languages/es.ini b/Themes/_fallback/Languages/es.ini index 37191689fc..3131aa7906 100644 --- a/Themes/_fallback/Languages/es.ini +++ b/Themes/_fallback/Languages/es.ini @@ -5,6 +5,7 @@ StepMania=StepMania [LoadingWindow] Couldn't open any loading windows.=Couldn't open any loading windows. Starting sound subsystem...=Starting sound subsystem... +Initializing bookkeeper...=Initializing bookkeeper... Starting lights subsystem...=Starting lights subsystem... Loading game type...=Loading game type... Building song cache index...=Building song cache index... @@ -332,10 +333,12 @@ BGBrightness=Controls how bright the background will appear. Turn this setting d Background=Change options that control the backgrounds that play during gameplay. BarDrain=BarDrain BatLives=BatLives +Bookkeeping=Check coin drop statistics. Calibrate Machine Sync=Calibrate the audio synchronization. CelShadeModels=Choose if dancing characters are drawn with cel shading. Center Image=Center the image on your monitor. Characters=Characters +Clear Bookkeeping Data=Clear all coin drop data. Clear Machine Edits=Save all step edits saved to this machine. Clear USB edits=Clear USB edits Clear Machine Stats=Clear all scores saved to this machine. @@ -820,6 +823,7 @@ BarDrain=Bar Drain BatLives=Bat Lives Base Difficulty=Base Difficulty Beat 0 Offset=Beat 0 Offset +Bookkeeping=Bookkeeping Calibrate Machine Sync=Calibrate Audio Sync CPUSkill=CPU Skill CelShadeModels=Cel-shaded Models @@ -829,6 +833,7 @@ Characters=Characters Chart Name=Chart Name Chart Style=Chart Style Choose=Choose +Clear Bookkeeping Data=Clear Bookkeeping Data Clear Machine Edits=Clear Machine Edits Clear Machine Stats=Clear Machine Scores Clear USB edits=Clear USB edits @@ -1218,6 +1223,15 @@ HeaderSubText=Get the best performance HeaderText=Advanced Options HeaderSubText=These settings are for advanced users +[ScreenBookkeeping] +All-time Coin Total:=All-time Coin Total: +Total Song Plays: %d=Total Song Plays: %d +Coin Data by Day of Week, All-Time=Coin Data by Day of Week, All-Time +Coin Data by Hour of Day, All-Time=Coin Data by Hour of Day, All-Time +Coin Data of Last %d Days=Coin Data of Last %d Days +Coin Data of Last %d Weeks=Coin Data of Last %d Weeks +HeaderText=Bookkeeping + [ScreenCaution] Caution=¡ADVERTENCIA! CautionText=Mantén la plataforma de baile a una distancia segura del monitor y muebles.\n\nTen cuidado para no hacer daño a mascotas, niños o espectadores mientras bailas. @@ -1567,6 +1581,7 @@ HelpTextTextEntry=Type a value using the keyboard. Press Enter to finish. HelpTextMapControllers=Use arrow keys to move, ENTER to assign, SPACE to clear::Press ESCAPE when done HelpTextOnline=smonline.us to connect to official Stepmania Online Server::Check out Stepmaniaonline.com for more information HelpTextNetSelectMusic=Ctrl + Enter to enter room/select song::&UP; for Player Options +HelpTextBookkeeping=Press &MENULEFT;&MENURIGHT; to cycle data. Press ESCAPE when done. [ScreenSelectGame] HeaderText=Seleccionar Juego @@ -1606,6 +1621,7 @@ HeaderSubText=Let's get started. I know you can! %d edits cleared, %d errors.=%d edits cleared, %d errors. %d failed=%d failed %d ignored=%d ignored +Bookkeeping data cleared.=Bookkeeping data cleared. Copied from P%d card:=Copied from P%d card: Copied to P%d card:=Copied to P%d card: Edits not cleared - No memory cards ready.=Edits not cleared - No memory cards ready. diff --git a/Themes/_fallback/Languages/ja.ini b/Themes/_fallback/Languages/ja.ini index 17c2b91874..3b93495ed3 100644 --- a/Themes/_fallback/Languages/ja.ini +++ b/Themes/_fallback/Languages/ja.ini @@ -14,6 +14,7 @@ StepMania=StepMania [LoadingWindow] Couldn't open any loading windows.=読み込みウインドウが開けませんでした。 Starting sound subsystem...=音声システム開始 +Initializing bookkeeper...=クレジット記録初期化中 Starting lights subsystem...=サイドライト初期化中 Loading game type...=ゲーム読み込み中 Building song cache index...=譜面データベース生成中 @@ -333,10 +334,12 @@ BGBrightness=背景の明度を調整します。 Background=プレイ中の背景を設定します。「Static」で背景を固定します。\n「Random Background」はRandomMoviesフォルダの背景を再生します。 BarDrain=ライフバーの減り方を設定します。 BatLives=ライフバッテリーの個数を設定します。 +Bookkeeping=クレジットの投入履歴を閲覧できます。 Calibrate Machine Sync=グローバルオフセットを設定します。 CelShadeModels=3Dキャラクターをセルシェードで表示します。 Center Image=モニタと画像の位置を調整します。 Characters=キャラクターの使用設定をします。 +Clear Bookkeeping Data=クレジットデータを削除します。 Clear Machine Edits=Songs以外のローカルに保存されているエディットデータを削除します。 Clear USB edits=メモリーカードに保存されているエディットデータを削除します。 Clear Machine Stats=スコアデータを削除します。 @@ -818,6 +821,7 @@ BarDrain=バーの減り方 BatLives=バッテリーの個数 Base Difficulty=基本難易度 Beat 0 Offset=0小節のオフセット +Bookkeeping=クレジット履歴 Calibrate Machine Sync=音の同期 CPUSkill=CPUのうまさ CelShadeModels=セルシェード\nモデル @@ -827,6 +831,7 @@ Characters=キャラクター Chart Name=譜面の名前 Chart Style=譜面の推奨プレイスタイル Choose=選択 +Clear Bookkeeping Data=クレジット\n履歴の消去 Clear Machine Edits=筐体エディットの消去 Clear Machine Stats=筐体スコアの消去 Clear USB edits=メモリーカード\nエディットの消去 @@ -1222,6 +1227,15 @@ HeaderSubText=画像と音声に関するオプションです。 HeaderText=ゲームオプション HeaderSubText=プレイ中のスコア形式など、ゲーム難易度に関わる設定です。 +[ScreenBookkeeping] +All-time Coin Total:=今まで投入されたコインの枚数: +Total Song Plays: %d=プレイされた曲: %d +Coin Data by Day of Week, All-Time=週間のコイン枚数 +Coin Data by Hour of Day, All-Time=時間のコイン枚数 +Coin Data of Last %d Days=%d日前からのコイン枚数 +Coin Data of Last %d Weeks=%d週前からのコイン枚数 +HeaderText=コイン枚数を確認できます。 + [ScreenCaution] Caution=CAUTION! CautionText=プレイする周りには物を置かないようにしてください。また、近隣の迷惑にならないようにしてください。 @@ -1576,6 +1590,7 @@ HelpTextTextEntry=キーボードのタイプ(例:106、109)を入力します HelpTextMapControllers=矢印キーを設定します。ENTERキーで設定、SPACEキーで削除します。Escキーで終了します。 HelpTextOnline=日本サーバはsmojp.ath.cxです。一度接続そのもののテストを行うことを推奨します。\n詳しくはstepmaniaonline.com(英語)を参照してください。 HelpTextNetSelectMusic=Ctrl+Enter 決定&UP; プレイヤーオプション +HelpTextBookkeeping=&MENULEFT;&MENURIGHT; 周回データ Escキーで戻ります。 [ScreenSelectGame] HeaderText=シミュレートするゲームの選択 @@ -1615,6 +1630,7 @@ HeaderSubText=モードを選択してください。 %d edits cleared, %d errors.=%dシーケンス削除、%dエラー %d failed=%d失敗 %d ignored=%d無視 +Bookkeeping data cleared.=クレジット履歴を削除しました。 Copied from P%d card:=P%dのメモリーカードからコピーしました。 Copied to P%d card:=P%dのメモリーカードへコピーしました。 Edits not cleared - No memory cards ready.=メモリーカードがありません。削除は失敗しました。 diff --git a/Themes/_fallback/Languages/nl.ini b/Themes/_fallback/Languages/nl.ini index 4c6efaf854..09b10a0bc3 100644 --- a/Themes/_fallback/Languages/nl.ini +++ b/Themes/_fallback/Languages/nl.ini @@ -5,6 +5,7 @@ StepMania=StepMania [LoadingWindow] Couldn't open any loading windows.=Kon geen laad scherm openen. Starting sound subsystem...=Start geluid subsysteem... +Initializing bookkeeper...=Initialiseren van de boekhouder... Starting lights subsystem...=Start licht subsysteem... Loading game type...=Laad spel type... Building song cache index...=Bouw nummer cache index... @@ -330,10 +331,12 @@ BGBrightness=Beheerst hoe fel de achtergrond er uit ziet. Zet dit lager als je d Background=Verander de opties voor welke achtergrond tijdens het spelen zichtbaar is. BarDrain=BalkDrain BatLives=BatLevens +Bookkeeping=Bekijk de ingeworpen munt statistieken. Calibrate Machine Sync=Stel de geluid synchronisatie af. CelShadeModels=Kies of de dansende karakters getekend worden met cel shading. Center Image=Centreer het beeld op je monitor. Characters=Karakters +Clear Bookkeeping Data=Verwijder alle munt invoer data. Clear Machine Edits=Sla alle stap wijzigingen op voor dit apparaat. Clear USB edits=Verwijder alle USB wijzigingen. Clear Machine Stats=Verwijder alle ranglijsten van deze machine. @@ -817,6 +820,7 @@ BarDrain=Balk Leeglopen BatLives=Bat Levens Base Difficulty=Basis Niveau Beat 0 Offset=Ritme 0 Offset +Bookkeeping=Boekhouding Calibrate Machine Sync=Kalibreer Geluid Synchronisatie CPUSkill=CPU Bekwaamheid CelShadeModels=Cel-shaded Modelen @@ -826,6 +830,7 @@ Characters=Karakters Chart Name=Stappen Kaart Naam Chart Style=Stappen Kaart Stijl Choose=Kies +Clear Bookkeeping Data=Wis Boekhoud Data Clear Machine Edits=Wis Machine Wijzigingen Clear Machine Stats=Wis Machine Scores Clear USB edits=Wis USB Wijzigingen @@ -1217,6 +1222,15 @@ HeaderSubText=Haal de beste prestatie HeaderText=Geavanceerde Opties HeaderSubText=Deze settings zijn voor geavanceerde gebruikers +[ScreenBookkeeping] +All-time Coin Total:=Totaal Van Alle Munten: +Total Song Plays: %d=Totaal Nummers Ooit Gespeeld: %d +Coin Data by Day of Week, All-Time=Munt Data Per Dag Van De Week +Coin Data by Hour of Day, All-Time=Munt Data Per Uur Van De Week +Coin Data of Last %d Days=Munt Data Van De Laatste %d Dagen +Coin Data of Last %d Weeks=Munt Data Van De Laatste %d Weken +HeaderText=Boekhouding + [ScreenCaution] Caution=KIJK UIT! CautionText=Zet het dansplatform op een veilige afstand van je scherm en meubels.\n\nWees voorzichtig dat je geen dieren, kinderen of omstanders bezeert. @@ -1569,6 +1583,7 @@ HelpTextTextEntry=Type een waarden met het toetsenbord. Druk op Enter als je kl HelpTextMapControllers=Gebruik de pijlen om te bewegen, ENTER om toe te wijzen, SPATIE om leeg te maken::Druk ESCAPE als je klaar bent HelpTextOnline=smonline.us om te verbinden met de officiële StepMania Online Server::Bekijk Stepmaniaonline.com voor meer informatie. HelpTextNetSelectMusic=Ctrl + Enter ga een kamer in/selecteer nummer:: &UP; voor Speler Opties +HelpTextBookkeeping=Druk &MENULEFT;&MENURIGHT; om data te doorlopen. Druk op ESCAPE als je klaar bent. [ScreenSelectGame] HeaderText=Selecteer Spel @@ -1608,6 +1623,7 @@ HeaderSubText=Laten we beginnen. Ik weet dat je het kan! %d edits cleared, %d errors.=%d bewerkingen geklaard, %d problemen. %d failed=%d gefaald %d ignored=%d genegeerd +Bookkeeping data cleared.=Boekhouding data opgeschoond Copied from P%d card:=Gekopieerd van P%d kaart: Copied to P%d card:=Gekopieerd naar P%d kaart: Edits not cleared - No memory cards ready.=Bewerkingen niet geklaard - Geen geheugenkaart klaar. diff --git a/Themes/_fallback/Languages/pl.ini b/Themes/_fallback/Languages/pl.ini index d8c5b1cf1d..6947726a43 100755 --- a/Themes/_fallback/Languages/pl.ini +++ b/Themes/_fallback/Languages/pl.ini @@ -5,6 +5,7 @@ StepMania=StepMania PL [LoadingWindow] Couldn't open any loading windows.=Nie udało się otowrzyć żadnego okna ładowania. Starting sound subsystem...=Uruchamianie podsystemu dźwięku... +Initializing bookkeeper...=Inicjalizacja modułu statystyk... Starting lights subsystem...=Uruchamianie podsystemu świateł... Loading game type...=Ładowanie modelu gry... Building song cache index...=Tworzenie indeksu bufora piosenek... @@ -327,10 +328,12 @@ BGBrightness=Ustala poziom jasność filmów odtwarzanych w tle piosenki. Zmniej Background=Zmienia opcje kontrolujące tła odtwarzanych w trakcie gry. BarDrain=Zużycie Energii BatLives=Ilość pasków baterii +Bookkeeping=Statystyka rzuconych żetonów/monet/kredytów. Calibrate Machine Sync=Kalibracja synchronizacji dźwięku. CelShadeModels=Decyduje czy Postacie Tańczące w tle są generowane z użyciem algorytmu Cel Shading. Center Image=Centrowanie obrazu monitora. Characters=Tańczące Postacie +Clear Bookkeeping Data=Zerowanie statystyk wrzuconych żetonów/monet/kredytów. Clear Machine Edits=Usunięcie wszystkich edycji kroków wgranych na maszynę. Clear USB edits=Zerowanie plików programu na pamięci USB Clear Machine Stats=Usunięcie wszystkich statystyk zapisanych na maszynie. @@ -819,6 +822,7 @@ BarDrain=Zużycie Energii BatLives=Ilość pasków Baterii Base Difficulty=Podstawowy Poziom Beat 0 Offset=Beat 0 Offset +Bookkeeping=Statystyka Calibrate Machine Sync=Kalibracja Synchronizacji Dźwięku CPUSkill=Poziom CPU CelShadeModels=Cel-shadedowane Modele @@ -828,6 +832,7 @@ Characters=Tancerze Chart Name=Nazwa Chart`a Chart Style=Styl Chart`a Choose=Wybierz +Clear Bookkeeping Data=Czyść dane wyrzutnika monet Clear Machine Edits=Czyść Zmodyfikowane Układy Clear Machine Stats=Czyść dane statystyczne Clear USB edits=Czyść Zmodyfikowane Układy na USB @@ -1221,6 +1226,15 @@ HeaderSubText=Ustaw najlepszą wydajność HeaderText=Opcje Zaawansowane HeaderSubText=Ustawienia przeznaczone dla zaawansowanych użytkowników +[ScreenBookkeeping] +All-time Coin Total:=Suma Wszystkich Monet: +Total Song Plays: %d=Liczba Odegranych piosenek: %d +Coin Data by Day of Week, All-Time=Wszystkie Monety z podz. na dni tygodnia +Coin Data by Hour of Day, All-Time=Wszystkie Monety z podz. na godziny +Coin Data of Last %d Days=Monety z Ostatnich %d Dni +Coin Data of Last %d Weeks=Monety z Ostatnich %d Tygodni +HeaderText=Statystyki + [ScreenCaution] Caution=UWAGA! CautionText=Zadbaj by mata taneczna znajdowała się w bezpiecznej odległości od monitora i mebli.\n\nZwraóć uwagę by podczas tańca nie skrzywdzić zwierząt, dzieci i obserwatorów @@ -1581,6 +1595,7 @@ HelpTextTextEntry=Wpisz wartość przy użyciu klawiatury. Naciśnij Enter by za HelpTextMapControllers=Użyj klawiszy strzałek do nawigacji, ENTER by przydzielić, SPACJĘ by wyczyścić pole::Naciśnij ESCAPE by zakończyć. HelpTextOnline=setepmaniaonline.eu by połączyć sięz oficjalnym Europejskim Serwerem Stepmania Online.:: Sprawdź www.stepmaniaonline.eu w celu rejestracji konta. HelpTextNetSelectMusic=Ctrl + Enter by wybrać pokój/piosenkę::&UP; Opcje Gracza +HelpTextBookkeeping=Naciśnij &MENULEFT;&MENURIGHT; by przeglądać dane. Naciśnij ESCAPE by zakończyć. [ScreenSelectGame] HeaderText=Wybierz Grę @@ -1621,6 +1636,7 @@ HeaderSubText=Zaczynajmy. Na pewno dasz radę. %d edits cleared, %d errors.=%d edycji wyczyszczono, %d błędów. %d failed=%d niewczytano %d ignored=%d zignowowano +Bookkeeping data cleared.=Statystyki wyczyszczone. Copied from P%d card:=Skopiowane z karty P%d: Copied to P%d card:=Skopiowane na kartę P%d: Edits not cleared - No memory cards ready.=Edycje nieusunięte - Brak karty. diff --git a/Themes/_fallback/base._ini b/Themes/_fallback/base._ini index 07f7273042..07f875edf4 100644 --- a/Themes/_fallback/base._ini +++ b/Themes/_fallback/base._ini @@ -2217,6 +2217,27 @@ Fallback="ScreenOptionsServiceChild" NextScreen=NextNetworkScreen() PrevScreen=NextNetworkScreen() +[ScreenBookkeeping] +Class="ScreenBookkeeping" +Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsService" +PrevScreen="ScreenOptionsService" +HelpText=ScreenString("HelpTextBookkeeping") +ShowSongPlays=true +ShowLastDays=true +ShowLastWeeks=true +ShowDayOfWeek=true +ShowHourOfDay=true +AllTimeX=SCREEN_CENTER_X +AllTimeY=110 +AllTimeOnCommand=zoom,0.7;diffuseshift;effectcolor1,0.5,0.5,0.5,1 +TitleX=SCREEN_CENTER_X +TitleY=140 +TitleOnCommand=zoom,0.8 +DataX=0 +DataY=SCREEN_CENTER_Y+16 +DataOnCommand= + [ScreenPackages] Class="ScreenPackages" PackagesBGY=SCREEN_CENTER_Y diff --git a/Themes/_portKit-sm4/metrics.ini b/Themes/_portKit-sm4/metrics.ini index 9faae82c0d..9bd0f54a35 100644 --- a/Themes/_portKit-sm4/metrics.ini +++ b/Themes/_portKit-sm4/metrics.ini @@ -2250,6 +2250,27 @@ Fallback="ScreenOptionsServiceChild" NextScreen=NextNetworkScreen() PrevScreen=NextNetworkScreen() +[ScreenBookkeeping] +Class="ScreenBookkeeping" +Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsService" +PrevScreen="ScreenOptionsService" +HelpText=ScreenString("HelpTextBookkeeping") +ShowSongPlays=true +ShowLastDays=true +ShowLastWeeks=true +ShowDayOfWeek=true +ShowHourOfDay=true +AllTimeX=SCREEN_CENTER_X +AllTimeY=110 +AllTimeOnCommand=zoom,0.7;diffuseshift;effectcolor1,color("0.5,0.5,0.5,1") +TitleX=SCREEN_CENTER_X +TitleY=140 +TitleOnCommand=zoom,0.8 +DataX=0 +DataY=SCREEN_CENTER_Y+16 +DataOnCommand= + [ScreenPackages] Class="ScreenPackages" PackagesBGY=SCREEN_CENTER_Y diff --git a/Xcode/stepmania_xcode4.3.xcodeproj/project.pbxproj b/Xcode/stepmania_xcode4.3.xcodeproj/project.pbxproj index cfa3e28389..7fa3ac33e4 100644 --- a/Xcode/stepmania_xcode4.3.xcodeproj/project.pbxproj +++ b/Xcode/stepmania_xcode4.3.xcodeproj/project.pbxproj @@ -401,7 +401,9 @@ AA29CE310558741A00961A51 /* PercentageDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAD620A5052EC78B00D02EE9 /* PercentageDisplay.cpp */; }; AA29CE320558741A00961A51 /* ScoreDisplayPercentage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6DAF0805300B3D00D02EE9 /* ScoreDisplayPercentage.cpp */; }; AA29CE340558741A00961A51 /* ScreenTestInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAC622FA05389A0500D02EE9 /* ScreenTestInput.cpp */; }; + AA29CE350558741A00961A51 /* ScreenBookkeeping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AADBE360053D5F8A00D02EE9 /* ScreenBookkeeping.cpp */; }; AA29CE360558741A00961A51 /* ScreenNameEntryTraditional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AADBE362053D5F8A00D02EE9 /* ScreenNameEntryTraditional.cpp */; }; + AA29CE370558741A00961A51 /* Bookkeeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AADBE368053DA38C00D02EE9 /* Bookkeeper.cpp */; }; AA29CE380558741A00961A51 /* GraphDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF551D0549F39700D02EE9 /* GraphDisplay.cpp */; }; AA29CE390558741A00961A51 /* ComboGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF55210549F43A00D02EE9 /* ComboGraph.cpp */; }; AA29CE3A0558741A00961A51 /* Attack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF5541054E736D00D02EE9 /* Attack.cpp */; }; @@ -616,7 +618,9 @@ AA40D28E09A08D650068C0D5 /* PercentageDisplay.h in Headers */ = {isa = PBXBuildFile; fileRef = AAD620A6052EC78B00D02EE9 /* PercentageDisplay.h */; }; AA40D28F09A08D650068C0D5 /* ScoreDisplayPercentage.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6DAF0905300B3D00D02EE9 /* ScoreDisplayPercentage.h */; }; AA40D29109A08D650068C0D5 /* ScreenTestInput.h in Headers */ = {isa = PBXBuildFile; fileRef = AAC622FB05389A0500D02EE9 /* ScreenTestInput.h */; }; + AA40D29209A08D650068C0D5 /* ScreenBookkeeping.h in Headers */ = {isa = PBXBuildFile; fileRef = AADBE361053D5F8A00D02EE9 /* ScreenBookkeeping.h */; }; AA40D29309A08D650068C0D5 /* ScreenNameEntryTraditional.h in Headers */ = {isa = PBXBuildFile; fileRef = AADBE363053D5F8A00D02EE9 /* ScreenNameEntryTraditional.h */; }; + AA40D29409A08D650068C0D5 /* Bookkeeper.h in Headers */ = {isa = PBXBuildFile; fileRef = AADBE369053DA38C00D02EE9 /* Bookkeeper.h */; }; AA40D29509A08D650068C0D5 /* GraphDisplay.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF551E0549F39700D02EE9 /* GraphDisplay.h */; }; AA40D29609A08D650068C0D5 /* ComboGraph.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF55220549F43A00D02EE9 /* ComboGraph.h */; }; AA40D29709A08D650068C0D5 /* Attack.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF5542054E736D00D02EE9 /* Attack.h */; }; @@ -932,7 +936,9 @@ AA40D44409A08D650068C0D5 /* PercentageDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAD620A5052EC78B00D02EE9 /* PercentageDisplay.cpp */; }; AA40D44509A08D650068C0D5 /* ScoreDisplayPercentage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6DAF0805300B3D00D02EE9 /* ScoreDisplayPercentage.cpp */; }; AA40D44709A08D650068C0D5 /* ScreenTestInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAC622FA05389A0500D02EE9 /* ScreenTestInput.cpp */; }; + AA40D44809A08D650068C0D5 /* ScreenBookkeeping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AADBE360053D5F8A00D02EE9 /* ScreenBookkeeping.cpp */; }; AA40D44909A08D650068C0D5 /* ScreenNameEntryTraditional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AADBE362053D5F8A00D02EE9 /* ScreenNameEntryTraditional.cpp */; }; + AA40D44A09A08D650068C0D5 /* Bookkeeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AADBE368053DA38C00D02EE9 /* Bookkeeper.cpp */; }; AA40D44B09A08D650068C0D5 /* GraphDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF551D0549F39700D02EE9 /* GraphDisplay.cpp */; }; AA40D44C09A08D650068C0D5 /* ComboGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF55210549F43A00D02EE9 /* ComboGraph.cpp */; }; AA40D44D09A08D650068C0D5 /* Attack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF5541054E736D00D02EE9 /* Attack.cpp */; }; @@ -3057,8 +3063,12 @@ AADB4E8C04D50FB900D02EE9 /* SignalHandler.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = SignalHandler.h; sourceTree = ""; }; AADB4E8F04D5263200D02EE9 /* arch_setup.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = arch_setup.h; sourceTree = ""; }; AADB4F5904D9220700D02EE9 /* Crash.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = Crash.h; sourceTree = ""; }; + AADBE360053D5F8A00D02EE9 /* ScreenBookkeeping.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenBookkeeping.cpp; path = ../src/ScreenBookkeeping.cpp; sourceTree = ""; }; + AADBE361053D5F8A00D02EE9 /* ScreenBookkeeping.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenBookkeeping.h; path = ../src/ScreenBookkeeping.h; sourceTree = ""; }; AADBE362053D5F8A00D02EE9 /* ScreenNameEntryTraditional.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenNameEntryTraditional.cpp; path = ../src/ScreenNameEntryTraditional.cpp; sourceTree = ""; }; AADBE363053D5F8A00D02EE9 /* ScreenNameEntryTraditional.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenNameEntryTraditional.h; path = ../src/ScreenNameEntryTraditional.h; sourceTree = ""; }; + AADBE368053DA38C00D02EE9 /* Bookkeeper.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Bookkeeper.cpp; path = ../src/Bookkeeper.cpp; sourceTree = ""; }; + AADBE369053DA38C00D02EE9 /* Bookkeeper.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Bookkeeper.h; path = ../src/Bookkeeper.h; sourceTree = ""; }; AADD1CC2095C233E0088C9DF /* LocalizedString.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = LocalizedString.cpp; path = ../src/LocalizedString.cpp; sourceTree = ""; }; AADD1CC3095C233F0088C9DF /* LocalizedString.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = LocalizedString.h; path = ../src/LocalizedString.h; sourceTree = ""; }; AAE2D6D30A67481E00071546 /* ScoreKeeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScoreKeeper.cpp; path = ../src/ScoreKeeper.cpp; sourceTree = ""; }; @@ -3631,6 +3641,8 @@ AA6E000B047711F3005F316C /* Screen.h */, AA6E0010047711F3005F316C /* ScreenAttract.cpp */, AA6E0011047711F3005F316C /* ScreenAttract.h */, + AADBE360053D5F8A00D02EE9 /* ScreenBookkeeping.cpp */, + AADBE361053D5F8A00D02EE9 /* ScreenBookkeeping.h */, AA2CA89D0BB745BD002441E9 /* ScreenContinue.cpp */, AA2CA89E0BB745BD002441E9 /* ScreenContinue.h */, AA07A5550843E72B00E33D21 /* ScreenDebugOverlay.cpp */, @@ -3788,6 +3800,8 @@ children = ( AA6E00FF0477128A005F316C /* AnnouncerManager.cpp */, AA6E01000477128A005F316C /* AnnouncerManager.h */, + AADBE368053DA38C00D02EE9 /* Bookkeeper.cpp */, + AADBE369053DA38C00D02EE9 /* Bookkeeper.h */, AA77E74508B64B1400FA24CA /* CharacterManager.cpp */, AA77E74608B64B1400FA24CA /* CharacterManager.h */, AAC0BFDF0E2951EC00F56EEB /* CryptHelpers.cpp */, @@ -5628,7 +5642,9 @@ AA40D28E09A08D650068C0D5 /* PercentageDisplay.h in Headers */, AA40D28F09A08D650068C0D5 /* ScoreDisplayPercentage.h in Headers */, AA40D29109A08D650068C0D5 /* ScreenTestInput.h in Headers */, + AA40D29209A08D650068C0D5 /* ScreenBookkeeping.h in Headers */, AA40D29309A08D650068C0D5 /* ScreenNameEntryTraditional.h in Headers */, + AA40D29409A08D650068C0D5 /* Bookkeeper.h in Headers */, AA40D29509A08D650068C0D5 /* GraphDisplay.h in Headers */, AA40D29609A08D650068C0D5 /* ComboGraph.h in Headers */, AA40D29709A08D650068C0D5 /* Attack.h in Headers */, @@ -6614,7 +6630,9 @@ AA29CE310558741A00961A51 /* PercentageDisplay.cpp in Sources */, AA29CE320558741A00961A51 /* ScoreDisplayPercentage.cpp in Sources */, AA29CE340558741A00961A51 /* ScreenTestInput.cpp in Sources */, + AA29CE350558741A00961A51 /* ScreenBookkeeping.cpp in Sources */, AA29CE360558741A00961A51 /* ScreenNameEntryTraditional.cpp in Sources */, + AA29CE370558741A00961A51 /* Bookkeeper.cpp in Sources */, AA29CE380558741A00961A51 /* GraphDisplay.cpp in Sources */, AA29CE390558741A00961A51 /* ComboGraph.cpp in Sources */, AA29CE3A0558741A00961A51 /* Attack.cpp in Sources */, @@ -7015,7 +7033,9 @@ AA40D44409A08D650068C0D5 /* PercentageDisplay.cpp in Sources */, AA40D44509A08D650068C0D5 /* ScoreDisplayPercentage.cpp in Sources */, AA40D44709A08D650068C0D5 /* ScreenTestInput.cpp in Sources */, + AA40D44809A08D650068C0D5 /* ScreenBookkeeping.cpp in Sources */, AA40D44909A08D650068C0D5 /* ScreenNameEntryTraditional.cpp in Sources */, + AA40D44A09A08D650068C0D5 /* Bookkeeper.cpp in Sources */, AA40D44B09A08D650068C0D5 /* GraphDisplay.cpp in Sources */, AA40D44C09A08D650068C0D5 /* ComboGraph.cpp in Sources */, AA40D44D09A08D650068C0D5 /* Attack.cpp in Sources */, diff --git a/src/Bookkeeper.cpp b/src/Bookkeeper.cpp new file mode 100644 index 0000000000..e1137f52f5 --- /dev/null +++ b/src/Bookkeeper.cpp @@ -0,0 +1,261 @@ +#include "global.h" +#include "Bookkeeper.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "IniFile.h" +#include "GameConstantsAndTypes.h" +#include "SongManager.h" +#include "RageFile.h" +#include "XmlFile.h" +#include "XmlFileUtil.h" +#include + +Bookkeeper* BOOKKEEPER = NULL; // global and accessable from anywhere in our program + +static const RString COINS_DAT = "Save/Coins.xml"; + +Bookkeeper::Bookkeeper() +{ + ClearAll(); + ReadFromDisk(); +} + +Bookkeeper::~Bookkeeper() +{ + WriteToDisk(); +} + +#define WARN_AND_RETURN { LOG->Warn("Error parsing at %s:%d",__FILE__,__LINE__); return; } + +void Bookkeeper::ClearAll() +{ + m_mapCoinsForHour.clear(); +} + +bool Bookkeeper::Date::operator<( const Date &rhs ) const +{ + if( m_iYear != rhs.m_iYear ) + return m_iYear < rhs.m_iYear; + if( m_iDayOfYear != rhs.m_iDayOfYear ) + return m_iDayOfYear < rhs.m_iDayOfYear; + return m_iHour < rhs.m_iHour; +} + +void Bookkeeper::Date::Set( time_t t ) +{ + tm ltime; + localtime_r( &t, <ime ); + + Set( ltime ); +} + +void Bookkeeper::Date::Set( tm pTime ) +{ + m_iHour = pTime.tm_hour; + m_iDayOfYear = pTime.tm_yday; + m_iYear = pTime.tm_year + 1900; +} + +void Bookkeeper::LoadFromNode( const XNode *pNode ) +{ + if( pNode->GetName() != "Bookkeeping" ) + { + LOG->Warn( "Error loading bookkeeping: unexpected \"%s\"", pNode->GetName().c_str() ); + return; + } + + const XNode *pData = pNode->GetChild( "Data" ); + if( pData == NULL ) + { + LOG->Warn( "Error loading bookkeeping: Data node missing" ); + return; + } + + FOREACH_CONST_Child( pData, day ) + { + Date d; + if( !day->GetAttrValue( "Hour", d.m_iHour ) || + !day->GetAttrValue( "Day", d.m_iDayOfYear ) || + !day->GetAttrValue( "Year", d.m_iYear ) ) + { + LOG->Warn( "Incomplete date field" ); + continue; + } + + int iCoins; + day->GetTextValue( iCoins ); + + m_mapCoinsForHour[d] = iCoins; + } +} + +XNode* Bookkeeper::CreateNode() const +{ + XNode *xml = new XNode( "Bookkeeping" ); + + { + XNode* pData = xml->AppendChild("Data"); + + for( map::const_iterator it = m_mapCoinsForHour.begin(); it != m_mapCoinsForHour.end(); ++it ) + { + int iCoins = it->second; + XNode *pDay = pData->AppendChild( "Coins", iCoins ); + + const Date &d = it->first; + pDay->AppendAttr( "Hour", d.m_iHour ); + pDay->AppendAttr( "Day", d.m_iDayOfYear ); + pDay->AppendAttr( "Year", d.m_iYear ); + } + } + + return xml; +} + +void Bookkeeper::ReadFromDisk() +{ + if( !IsAFile(COINS_DAT) ) + return; + + XNode xml; + if( !XmlFileUtil::LoadFromFileShowErrors(xml, COINS_DAT) ) + return; + + LoadFromNode( &xml ); +} + +void Bookkeeper::WriteToDisk() +{ + // Write data. Use SLOW_FLUSH, to help ensure that we don't lose coin data. + RageFile f; + if( !f.Open(COINS_DAT, RageFile::WRITE|RageFile::SLOW_FLUSH) ) + { + LOG->Warn( "Couldn't open file \"%s\" for writing: %s", COINS_DAT.c_str(), f.GetError().c_str() ); + return; + } + + auto_ptr xml( CreateNode() ); + XmlFileUtil::SaveToFile( xml.get(), f ); +} + +void Bookkeeper::CoinInserted() +{ + Date d; + d.Set( time(NULL) ); + + ++m_mapCoinsForHour[d]; +} + +// Return the number of coins between [beginning,ending). +int Bookkeeper::GetNumCoinsInRange( map::const_iterator begin, map::const_iterator end ) const +{ + int iCoins = 0; + + while( begin != end ) + { + iCoins += begin->second; + ++begin; + } + + return iCoins; +} + +int Bookkeeper::GetNumCoins( Date beginning, Date ending ) const +{ + return GetNumCoinsInRange( m_mapCoinsForHour.lower_bound( beginning ), + m_mapCoinsForHour.lower_bound( ending ) ); +} + +int Bookkeeper::GetCoinsTotal() const +{ + return GetNumCoinsInRange( m_mapCoinsForHour.begin(), m_mapCoinsForHour.end() ); +} + +void Bookkeeper::GetCoinsLastDays( int coins[NUM_LAST_DAYS] ) const +{ + time_t lOldTime = time(NULL); + tm time; + localtime_r( &lOldTime, &time ); + + time.tm_hour = 0; + + for( int i=0; i::const_iterator it = m_mapCoinsForHour.begin(); it != m_mapCoinsForHour.end(); ++it ) + { + const Date &d = it->first; + int iDayOfWeek = GetDayInYearAndYear( d.m_iDayOfYear, d.m_iYear ).tm_wday; + coins[iDayOfWeek] += it->second; + } +} + +void Bookkeeper::GetCoinsByHour( int coins[HOURS_IN_DAY] ) const +{ + memset( coins, 0, sizeof(int) * HOURS_IN_DAY ); + for( map::const_iterator it = m_mapCoinsForHour.begin(); it != m_mapCoinsForHour.end(); ++it ) + { + const Date &d = it->first; + + if( d.m_iHour >= HOURS_IN_DAY ) + { + LOG->Warn( "Hour %i >= %i", d.m_iHour, HOURS_IN_DAY ); + continue; + } + + coins[d.m_iHour] += it->second; + } +} + +/* + * (c) 2003-2005 Chris Danford, Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/Bookkeeper.h b/src/Bookkeeper.h new file mode 100644 index 0000000000..cddef0b9f6 --- /dev/null +++ b/src/Bookkeeper.h @@ -0,0 +1,93 @@ +#ifndef Bookkeeper_H +#define Bookkeeper_H + +#include "DateTime.h" +#include +class XNode; + +/** @brief Track when coins were put into the machine. */ +class Bookkeeper +{ +public: + Bookkeeper(); + ~Bookkeeper(); + + void ClearAll(); + + void CoinInserted(); + + int GetCoinsTotal() const; + void GetCoinsLastDays( int coins[NUM_LAST_DAYS] ) const; + void GetCoinsLastWeeks( int coins[NUM_LAST_WEEKS] ) const; + void GetCoinsByDayOfWeek( int coins[DAYS_IN_WEEK] ) const; + void GetCoinsByHour( int coins[HOURS_IN_DAY] ) const; + + void LoadFromNode( const XNode *pNode ); + XNode* CreateNode() const; + + void ReadFromDisk(); + void WriteToDisk(); + +private: + /** @brief A simple way of handling the date. */ + struct Date + { + /** + * @brief The hour of the date. + * + * The value 0 is defined to be midnight. */ + int m_iHour; + /** + * @brief The day of the year of the date. + * + * The value 0 is defined to be January 1st. */ + int m_iDayOfYear; + /** @brief The year of the date (e.g., 2005). */ + int m_iYear; + /** @brief Set up a date with initial values. */ + Date() { m_iHour = m_iDayOfYear = m_iYear = 0; } + /** + * @brief Set up a date based on the given time. + * @param time the time to turn into a Date. */ + Date( tm time ) { Set(time); } + void Set( time_t t ); + void Set( tm pTime ); + bool operator<( const Date &rhs ) const; + }; + int GetNumCoins( Date beginning, Date ending ) const; + int GetNumCoinsInRange( map::const_iterator begin, map::const_iterator end ) const; + + int m_iLastSeenTime; + map m_mapCoinsForHour; +}; + +extern Bookkeeper* BOOKKEEPER; // global and accessable from anywhere in our program + +#endif + +/** + * @file + * @author Chris Danford (c) 2003-2004 + * @section LICENSE + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/Game.cpp b/src/Game.cpp index 2442651aad..07aac354c4 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -24,6 +24,7 @@ static const Game::PerButtonInfo g_CommonButtonInfo[] = { GameButtonType_INVALID }, // GAME_BUTTON_START { GameButtonType_INVALID }, // GAME_BUTTON_SELECT { GameButtonType_INVALID }, // GAME_BUTTON_BACK + { GameButtonType_INVALID }, // GAME_BUTTON_COIN { GameButtonType_INVALID }, // GAME_BUTTON_OPERATOR { GameButtonType_INVALID }, // GAME_BUTTON_EFFECT_UP { GameButtonType_INVALID }, // GAME_BUTTON_EFFECT_DOWN diff --git a/src/GameCommand.cpp b/src/GameCommand.cpp index d8cf71b693..11353bd264 100644 --- a/src/GameCommand.cpp +++ b/src/GameCommand.cpp @@ -60,6 +60,8 @@ void GameCommand::Init() m_sUrl = ""; m_bUrlExits = true; + m_bInsertCredit = false; + m_bClearCredits = false; m_bStopMusic = false; m_bApplyDefaultOptions = false; m_bFadeMusic = false; @@ -367,6 +369,16 @@ void GameCommand::LoadOne( const Command& cmd ) m_vsScreensToPrepare.push_back( sValue ); } + else if( sName == "insertcredit" ) + { + m_bInsertCredit = true; + } + + else if( sName == "clearcredits" ) + { + m_bClearCredits = true; + } + else if( sName == "stopmusic" ) { m_bStopMusic = true; @@ -416,6 +428,36 @@ void GameCommand::LoadOne( const Command& cmd ) } } +int GetNumCreditsPaid() +{ + int iNumCreditsPaid = GAMESTATE->GetNumSidesJoined(); + + // players other than the first joined for free + if( GAMESTATE->GetPremium() == Premium_2PlayersFor1Credit ) + iNumCreditsPaid = min( iNumCreditsPaid, 1 ); + + return iNumCreditsPaid; +} + + +int GetCreditsRequiredToPlayStyle( const Style *style ) +{ + if( GAMESTATE->GetPremium() == Premium_2PlayersFor1Credit ) + return 1; + + switch( style->m_StyleType ) + { + case StyleType_OnePlayerOneSide: + return 1; + case StyleType_TwoPlayersSharedSides: + case StyleType_TwoPlayersTwoSides: + return 2; + case StyleType_OnePlayerTwoSides: + return (GAMESTATE->GetPremium() == Premium_DoubleFor1Credit) ? 1 : 2; + DEFAULT_FAIL( style->m_StyleType ); + } +} + static bool AreStyleAndPlayModeCompatible( const Style *style, PlayMode pm ) { if( style == NULL || pm == PlayMode_Invalid ) @@ -451,8 +493,33 @@ bool GameCommand::IsPlayable( RString *why ) const if ( m_pStyle ) { - int iCredits = NUM_PLAYERS; // not iNumCreditsPaid - + int iCredits = GAMESTATE->m_iCoins / PREFSMAN->m_iCoinsPerCredit; + const int iNumCreditsPaid = GetNumCreditsPaid(); + const int iNumCreditsRequired = GetCreditsRequiredToPlayStyle(m_pStyle); + + switch( GAMESTATE->GetCoinMode() ) + { + case CoinMode_Home: + case CoinMode_Free: + iCredits = NUM_PLAYERS; // not iNumCreditsPaid + default: break; + } + + /* With PREFSMAN->m_bDelayedCreditsReconcile disabled, enough credits must + * be paid. (This means that enough sides must be joined.) Enabled, simply + * having enough credits lying in the machine is sufficient; we'll deduct the + * extra in Apply(). */ + int iNumCreditsAvailable = iNumCreditsPaid; + if( PREFSMAN->m_bDelayedCreditsReconcile ) + iNumCreditsAvailable += iCredits; + + if( iNumCreditsAvailable < iNumCreditsRequired ) + { + if( why ) + *why = ssprintf( "need %i credits, have %i", iNumCreditsRequired, iNumCreditsAvailable ); + return false; + } + /* If both sides are joined, disallow singles modes, since easy to select * them accidentally, instead of versus mode. */ if( m_pStyle->m_StyleType == StyleType_OnePlayerOneSide && @@ -693,6 +760,14 @@ void GameCommand::ApplySelf( const vector &vpns ) const FOREACH_CONST( RString, m_vsScreensToPrepare, s ) SCREENMAN->PrepareScreen( *s ); + if( m_bInsertCredit ) + { + StepMania::InsertCredit(); + } + + if( m_bClearCredits ) + StepMania::ClearCredits(); + if( m_bApplyDefaultOptions ) { // applying options affects only the current stage diff --git a/src/GameCommand.h b/src/GameCommand.h index f9d503227a..50f9ae5050 100644 --- a/src/GameCommand.h +++ b/src/GameCommand.h @@ -19,6 +19,9 @@ class Style; class Game; struct lua_State; +int GetNumCreditsPaid(); +int GetCreditsRequiredToPlayStyle( const Style *style ); + class GameCommand { public: @@ -36,6 +39,7 @@ public: m_sSoundPath(""), m_vsScreensToPrepare(), m_iWeightPounds(-1), m_iGoalCalories(-1), m_GoalType(GoalType_Invalid), m_sProfileID(""), m_sUrl(""), m_bUrlExits(true), + m_bInsertCredit(false), m_bClearCredits(false), m_bStopMusic(false), m_bApplyDefaultOptions(false), m_bFadeMusic(false), m_fMusicFadeOutVolume(-1), m_fMusicFadeOutSeconds(-1), m_bApplyCommitsScreens(true) @@ -104,6 +108,8 @@ public: // sm-ssc adds: bool m_bUrlExits; // for making stepmania not exit on url + bool m_bInsertCredit; + bool m_bClearCredits; bool m_bStopMusic; bool m_bApplyDefaultOptions; // sm-ssc also adds: diff --git a/src/GameInput.h b/src/GameInput.h index 5228ca6569..5a474f0e71 100644 --- a/src/GameInput.h +++ b/src/GameInput.h @@ -26,6 +26,7 @@ enum GameButton GAME_BUTTON_START, GAME_BUTTON_SELECT, GAME_BUTTON_BACK, + GAME_BUTTON_COIN, /**< Insert a coin to play. */ GAME_BUTTON_OPERATOR, /**< Access the operator menu. */ GAME_BUTTON_EFFECT_UP, GAME_BUTTON_EFFECT_DOWN, diff --git a/src/GameState.cpp b/src/GameState.cpp index 02ba9cdb91..adffcf6119 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -3,6 +3,7 @@ #include "Actor.h" #include "AdjustSync.h" #include "AnnouncerManager.h" +#include "Bookkeeper.h" #include "Character.h" #include "CharacterManager.h" #include "CommonMetrics.h" @@ -110,6 +111,7 @@ GameState::GameState() : m_pCurGame( Message_CurrentGameChanged ), m_pCurStyle( Message_CurrentStyleChanged ), m_PlayMode( Message_PlayModeChanged ), + m_iCoins( Message_CoinsChanged ), m_sPreferredSongGroup( Message_PreferredSongGroupChanged ), m_sPreferredCourseGroup( Message_PreferredCourseGroupChanged ), m_PreferredStepsType( Message_PreferredStepsTypeChanged ), @@ -136,6 +138,7 @@ GameState::GameState() : SetCurrentStyle( NULL ); m_pCurGame.Set( NULL ); + m_iCoins.Set( 0 ); m_timeGameStarted.SetZero(); m_bDemonstrationOrJukebox = false; @@ -283,6 +286,7 @@ void GameState::Reset() m_MultiPlayerStatus[p] = MultiPlayerStatus_NotJoined; FOREACH_PlayerNumber( pn ) MEMCARDMAN->UnlockCard( pn ); + //m_iCoins = 0; // don't reset coin count! m_bMultiplayer = false; m_iNumMultiplayerNoteFields = 1; *m_Environment = LuaTable(); @@ -441,6 +445,14 @@ namespace if( GAMESTATE->m_bSideIsJoined[pn] ) return false; + // subtract coins + int iCoinsNeededToJoin = GAMESTATE->GetCoinsNeededToJoin(); + + if( GAMESTATE->m_iCoins < iCoinsNeededToJoin ) + return false; // not enough coins + + GAMESTATE->m_iCoins.Set( GAMESTATE->m_iCoins - iCoinsNeededToJoin ); + GAMESTATE->JoinPlayer( pn ); return true; @@ -469,6 +481,18 @@ bool GameState::JoinPlayers() return bJoined; } +int GameState::GetCoinsNeededToJoin() const +{ + int iCoinsToCharge = 0; + + // If joint premium, don't take away a credit for the second join. + if( GetPremium() == Premium_2PlayersFor1Credit && + GetNumSidesJoined() == 1 ) + iCoinsToCharge = 0; + + return iCoinsToCharge; +} + /* Game flow: * * BeginGame() - the first player has joined; the game is starting. @@ -585,6 +609,7 @@ bool GameState::HaveProfileToSave() void GameState::SaveLocalData() { + BOOKKEEPER->WriteToDisk(); PROFILEMAN->SaveMachineProfile(); } @@ -2272,7 +2297,10 @@ public: return 1; } DEFINE_METHOD( GetGameplayLeadIn, m_bGameplayLeadIn ) + DEFINE_METHOD( GetCoins, m_iCoins ) DEFINE_METHOD( IsSideJoined, m_bSideIsJoined[Enum::Check(L, 1)] ) + DEFINE_METHOD( GetCoinsNeededToJoin, GetCoinsNeededToJoin() ) + DEFINE_METHOD( EnoughCreditsToJoin, EnoughCreditsToJoin() ) DEFINE_METHOD( PlayersCanJoin, PlayersCanJoin() ) DEFINE_METHOD( GetNumSidesJoined, GetNumSidesJoined() ) DEFINE_METHOD( GetCoinMode, GetCoinMode() ) @@ -2525,7 +2553,10 @@ public: ADD_METHOD( GetSongDelay );*/ ADD_METHOD( GetSongPosition ); ADD_METHOD( GetGameplayLeadIn ); + ADD_METHOD( GetCoins ); ADD_METHOD( IsSideJoined ); + ADD_METHOD( GetCoinsNeededToJoin ); + ADD_METHOD( EnoughCreditsToJoin ); ADD_METHOD( PlayersCanJoin ); ADD_METHOD( GetNumSidesJoined ); ADD_METHOD( GetCoinMode ); diff --git a/src/GameState.h b/src/GameState.h index 8540c2fd2c..244d94ae3d 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -98,6 +98,7 @@ public: * Note that coins are not "credits". One may have to put in two coins * to get one credit, only to have to put in another four coins to get * the three credits needed to begin the game. */ + BroadcastOnChange m_iCoins; bool m_bMultiplayer; int m_iNumMultiplayerNoteFields; bool DifficultiesLocked() const; @@ -120,6 +121,8 @@ public: * @brief Determine if a second player can join in at this time. * @return true if a player can still enter the game, false otherwise. */ bool PlayersCanJoin() const; + int GetCoinsNeededToJoin() const; + bool EnoughCreditsToJoin() const { return m_iCoins >= GetCoinsNeededToJoin(); } int GetNumSidesJoined() const; const Game* GetCurrentGame(); diff --git a/src/InputMapper.cpp b/src/InputMapper.cpp index e8cc54d825..1d80e36669 100644 --- a/src/InputMapper.cpp +++ b/src/InputMapper.cpp @@ -65,6 +65,7 @@ static const AutoMappings g_DefaultKeyMappings = AutoMappings( AutoMappingEntry( 0, KEY_KP_ENTER, GAME_BUTTON_START, true ), AutoMappingEntry( 0, KEY_KP_C0, GAME_BUTTON_SELECT, true ), AutoMappingEntry( 0, KEY_HYPHEN, GAME_BUTTON_BACK, true ), // laptop keyboards. + AutoMappingEntry( 0, KEY_F1, GAME_BUTTON_COIN, false ), AutoMappingEntry( 0, KEY_SCRLLOCK, GAME_BUTTON_OPERATOR, false ) ); @@ -301,6 +302,7 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_SELECT, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_5, GAME_BUTTON_BACK, false ), + AutoMappingEntry( 0, JOY_BUTTON_6, GAME_BUTTON_COIN, false ), // Player 2. AutoMappingEntry( 0, JOY_BUTTON_32, DANCE_BUTTON_LEFT, true ), AutoMappingEntry( 0, JOY_BUTTON_30, DANCE_BUTTON_RIGHT, true ), @@ -314,7 +316,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_24, DANCE_BUTTON_UPLEFT, true ), AutoMappingEntry( 0, JOY_BUTTON_25, GAME_BUTTON_SELECT, true ), AutoMappingEntry( 0, JOY_BUTTON_26, GAME_BUTTON_START, true ), - AutoMappingEntry( 0, JOY_BUTTON_21, GAME_BUTTON_BACK, true ) + AutoMappingEntry( 0, JOY_BUTTON_21, GAME_BUTTON_BACK, true ), + AutoMappingEntry( 0, JOY_BUTTON_22, GAME_BUTTON_COIN, true ) ), AutoMappings( "dance", @@ -345,7 +348,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, /* R1 */ DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_10, /* Select */ GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_9, /* Start */ GAME_BUTTON_START, false ), - AutoMappingEntry( 0, JOY_BUTTON_5, /* R1 */ GAME_BUTTON_SELECT, false ) + AutoMappingEntry( 0, JOY_BUTTON_5, /* R1 */ GAME_BUTTON_SELECT, false ), + AutoMappingEntry( 0, JOY_BUTTON_6, /* R2 */ GAME_BUTTON_COIN, false ) ), AutoMappings( "dance", @@ -1010,6 +1014,7 @@ static const InputScheme::GameButtonInfo g_CommonGameButtonInfo[] = { "Start", GAME_BUTTON_START }, { "Select", GAME_BUTTON_SELECT }, { "Back", GAME_BUTTON_BACK }, + { "Coin", GAME_BUTTON_COIN }, { "Operator", GAME_BUTTON_OPERATOR }, { "EffectUp", GAME_BUTTON_EFFECT_UP }, { "EffectDown", GAME_BUTTON_EFFECT_DOWN }, diff --git a/src/LightsManager.cpp b/src/LightsManager.cpp index b8df2329bb..e2d2c4083a 100644 --- a/src/LightsManager.cpp +++ b/src/LightsManager.cpp @@ -420,6 +420,18 @@ void LightsManager::Update( float fDeltaTime ) } } + // If not joined, has enough credits, and not too late to join, then + // blink the menu buttons rapidly so they'll press Start + { + int iBeat = (int)(GAMESTATE->m_Position.m_fLightSongBeat*4); + bool bBlinkOn = (iBeat%2)==0; + FOREACH_PlayerNumber( pn ) + { + if( !GAMESTATE->m_bSideIsJoined[pn] && GAMESTATE->PlayersCanJoin() && GAMESTATE->EnoughCreditsToJoin() ) + m_LightsState.m_bGameButtonLights[pn][GAME_BUTTON_START] = bBlinkOn; + } + } + // apply new light values we set above FOREACH( LightsDriver*, m_vpDrivers, iter ) (*iter)->Set( &m_LightsState ); diff --git a/src/Makefile.am b/src/Makefile.am index a810e72f1f..11f52385fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,6 +57,7 @@ PNG = \ Screens = \ Screen.cpp Screen.h ScreenAttract.cpp ScreenAttract.h \ +ScreenBookkeeping.cpp ScreenBookkeeping.h \ ScreenContinue.cpp ScreenContinue.h \ ScreenDebugOverlay.cpp ScreenDebugOverlay.h \ ScreenDemonstration.cpp ScreenDemonstration.h ScreenDimensions.h \ @@ -471,6 +472,7 @@ RollingNumbers.cpp RollingNumbers.h Sprite.cpp Sprite.h GlobalSingletons = \ AnnouncerManager.cpp AnnouncerManager.h \ +Bookkeeper.cpp Bookkeeper.h \ CharacterManager.cpp CharacterManager.h \ CryptManager.cpp CryptManager.h \ FontManager.cpp FontManager.h GameSoundManager.cpp GameSoundManager.h \ diff --git a/src/MessageManager.cpp b/src/MessageManager.cpp index d1aac2c00f..1b08eabff0 100644 --- a/src/MessageManager.cpp +++ b/src/MessageManager.cpp @@ -16,6 +16,7 @@ static const char *MessageIDNames[] = { "CurrentGameChanged", "CurrentStyleChanged", "PlayModeChanged", + "CoinsChanged", "CurrentSongChanged", "CurrentStepsP1Changed", "CurrentStepsP2Changed", diff --git a/src/MessageManager.h b/src/MessageManager.h index 6291aec29d..020868fb4a 100644 --- a/src/MessageManager.h +++ b/src/MessageManager.h @@ -12,6 +12,7 @@ enum MessageID Message_CurrentGameChanged, Message_CurrentStyleChanged, Message_PlayModeChanged, + Message_CoinsChanged, Message_CurrentSongChanged, Message_CurrentStepsP1Changed, Message_CurrentStepsP2Changed, diff --git a/src/PrefsManager.cpp b/src/PrefsManager.cpp index 67045d80fb..6292d790c0 100644 --- a/src/PrefsManager.cpp +++ b/src/PrefsManager.cpp @@ -214,7 +214,9 @@ PrefsManager::PrefsManager() : m_iMusicWheelSwitchSpeed ( "MusicWheelSwitchSpeed", 15 ), m_AllowW1 ( "AllowW1", ALLOW_W1_EVERYWHERE ), m_bEventMode ( "EventMode", true ), + m_iCoinsPerCredit ( "CoinsPerCredit", 1 ), m_iSongsPerPlay ( "SongsPerPlay", 3, ValidateSongsPerPlay ), + m_bDelayedCreditsReconcile ( "DelayedCreditsReconcile", false ), m_ShowSongOptions ( "ShowSongOptions", Maybe_YES ), m_bDancePointsForOni ( "DancePointsForOni", true ), m_bPercentageScoring ( "PercentageScoring", false ), diff --git a/src/PrefsManager.h b/src/PrefsManager.h index e132295d13..f57dff5a0c 100644 --- a/src/PrefsManager.h +++ b/src/PrefsManager.h @@ -205,7 +205,9 @@ public: Preference m_iMusicWheelSwitchSpeed; Preference m_AllowW1; // this should almost always be on, given use cases. -aj Preference m_bEventMode; + Preference m_iCoinsPerCredit; Preference m_iSongsPerPlay; + Preference m_bDelayedCreditsReconcile; // zuh? Preference m_ShowSongOptions; Preference m_bDancePointsForOni; Preference m_bPercentageScoring; diff --git a/src/Profile.cpp b/src/Profile.cpp index ce200ed9e2..20d9236760 100644 --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -21,6 +21,7 @@ #include "XmlFile.h" #include "XmlFileUtil.h" #include "Foreach.h" +#include "Bookkeeper.h" #include "Game.h" #include "CharacterManager.h" #include "Character.h" @@ -1848,6 +1849,35 @@ XNode* Profile::SaveCoinDataCreateNode() const XNode* pNode = new XNode( "CoinData" ); + { + int coins[NUM_LAST_DAYS]; + BOOKKEEPER->GetCoinsLastDays( coins ); + XNode* p = pNode->AppendChild( "LastDays" ); + for( int i=0; iAppendChild( LastDayToString(i), coins[i] ); + } + { + int coins[NUM_LAST_WEEKS]; + BOOKKEEPER->GetCoinsLastWeeks( coins ); + XNode* p = pNode->AppendChild( "LastWeeks" ); + for( int i=0; iAppendChild( LastWeekToString(i), coins[i] ); + } + { + int coins[DAYS_IN_WEEK]; + BOOKKEEPER->GetCoinsByDayOfWeek( coins ); + XNode* p = pNode->AppendChild( "DayOfWeek" ); + for( int i=0; iAppendChild( DayOfWeekToString(i), coins[i] ); + } + { + int coins[HOURS_IN_DAY]; + BOOKKEEPER->GetCoinsByHour( coins ); + XNode* p = pNode->AppendChild( "Hour" ); + for( int i=0; iAppendChild( HourInDayToString(i), coins[i] ); + } + return pNode; } diff --git a/src/Profile.h b/src/Profile.h index 60a700c004..d86941b14c 100644 --- a/src/Profile.h +++ b/src/Profile.h @@ -281,8 +281,8 @@ public: /** * @brief The basics for Calorie Data. * - * Why track calories in a map, and not in a static sized array? - * The machine's clock is not guaranteed to be set correctly. + * Why track calories in a map, and not in a static sized array like + * Bookkeeping? The machine's clock is not guaranteed to be set correctly. * If calorie array is in a static sized array, playing on a machine with * a mis-set clock could wipe out all your past data. With this scheme, * the worst that could happen is that playing on a mis-set machine will diff --git a/src/Screen.cpp b/src/Screen.cpp index 03a860db8d..6e337f98cd 100644 --- a/src/Screen.cpp +++ b/src/Screen.cpp @@ -219,6 +219,7 @@ bool Screen::Input( const InputEventPlus &input ) return false; case GAME_BUTTON_START: return this->MenuStart ( input ); case GAME_BUTTON_SELECT: return this->MenuSelect( input ); + case GAME_BUTTON_COIN: return this->MenuCoin ( input ); default: return false; } } diff --git a/src/ScreenAttract.cpp b/src/ScreenAttract.cpp index cb3eee59a9..d52bd9da85 100644 --- a/src/ScreenAttract.cpp +++ b/src/ScreenAttract.cpp @@ -82,6 +82,7 @@ bool ScreenAttract::AttractInput( const InputEventPlus &input, ScreenWithMenuEle break; // fall through case GAME_BUTTON_START: + case GAME_BUTTON_COIN: switch( GAMESTATE->GetCoinMode() ) { case CoinMode_Home: @@ -89,6 +90,10 @@ bool ScreenAttract::AttractInput( const InputEventPlus &input, ScreenWithMenuEle if( pScreen->IsTransitioning() ) return false; + // HandleGlobalInputs() already played the coin sound. Don't play it again. + if( input.MenuI != GAME_BUTTON_COIN ) + SCREENMAN->PlayStartSound(); + pScreen->Cancel( SM_GoToStartScreen ); return true; default: FAIL_M("Invalid Coin Mode! Aborting..."); diff --git a/src/ScreenBookkeeping.cpp b/src/ScreenBookkeeping.cpp new file mode 100644 index 0000000000..d03857a19e --- /dev/null +++ b/src/ScreenBookkeeping.cpp @@ -0,0 +1,315 @@ +#include "global.h" +#include "ScreenBookkeeping.h" +#include "ScreenManager.h" +#include "RageLog.h" +#include "ThemeManager.h" +#include "Bookkeeper.h" +#include "ScreenDimensions.h" +#include "InputEventPlus.h" +#include "RageUtil.h" +#include "LocalizedString.h" +#include "Song.h" +#include "SongManager.h" +#include "UnlockManager.h" +#include "ProfileManager.h" +#include "Profile.h" + +static const char *BookkeepingViewNames[] = { + "SongPlays", + "LastDays", + "LastWeeks", + "DayOfWeek", + "HourOfDay", +}; +XToString( BookkeepingView ); + + +REGISTER_SCREEN_CLASS( ScreenBookkeeping ); + +void ScreenBookkeeping::Init() +{ + ScreenWithMenuElements::Init(); + + m_textAllTime.LoadFromFont( THEME->GetPathF(m_sName,"AllTime") ); + m_textAllTime.SetName( "AllTime" ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_textAllTime ); + this->AddChild( &m_textAllTime ); + + m_textTitle.LoadFromFont( THEME->GetPathF(m_sName,"title") ); + m_textTitle.SetName( "Title" ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_textTitle ); + this->AddChild( &m_textTitle ); + + for( int i=0; iGetPathF(m_sName,"data") ); + m_textData[i].SetName( "Data" ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_textData[i] ); + float fX = SCALE( i, 0.f, NUM_BOOKKEEPING_COLS-1, SCREEN_LEFT+50, SCREEN_RIGHT-160 ); + m_textData[i].SetX( fX ); + this->AddChild( &m_textData[i] ); + } + + FOREACH_ENUM( BookkeepingView, i ) + { + if( THEME->GetMetricB(m_sName,"Show"+BookkeepingViewToString(i)) ) + m_vBookkeepingViews.push_back( i ); + } + + m_iViewIndex = 0; + + UpdateView(); +} + +void ScreenBookkeeping::Update( float fDelta ) +{ + UpdateView(); // refresh so that counts change in real-time + + ScreenWithMenuElements::Update( fDelta ); +} + +bool ScreenBookkeeping::Input( const InputEventPlus &input ) +{ + if( input.type != IET_FIRST_PRESS && input.type != IET_REPEAT ) + return false; // ignore + + return Screen::Input( input ); // default handler +} + +bool ScreenBookkeeping::MenuLeft( const InputEventPlus &input ) +{ + m_iViewIndex--; + CLAMP( m_iViewIndex, 0, m_vBookkeepingViews.size()-1 ); + + UpdateView(); + return true; +} + +bool ScreenBookkeeping::MenuRight( const InputEventPlus &input ) +{ + m_iViewIndex++; + CLAMP( m_iViewIndex, 0, m_vBookkeepingViews.size()-1 ); + + UpdateView(); + return true; +} + +bool ScreenBookkeeping::MenuStart( const InputEventPlus &input ) +{ + if( IsTransitioning() ) + return false; + + SCREENMAN->PlayStartSound(); + StartTransitioningScreen( SM_GoToNextScreen ); + return true; +} + +bool ScreenBookkeeping::MenuBack( const InputEventPlus &input ) +{ + if( IsTransitioning() ) + return false; + + SCREENMAN->PlayStartSound(); + StartTransitioningScreen( SM_GoToPrevScreen ); + return true; +} + +bool ScreenBookkeeping::MenuCoin( const InputEventPlus &input ) +{ + UpdateView(); + + return Screen::MenuCoin( input ); +} + +static LocalizedString ALL_TIME ( "ScreenBookkeeping", "All-time Coin Total:" ); +static LocalizedString SONG_PLAYS ( "ScreenBookkeeping", "Total Song Plays: %d" ); +static LocalizedString LAST_DAYS ( "ScreenBookkeeping", "Coin Data of Last %d Days" ); +static LocalizedString LAST_WEEKS ( "ScreenBookkeeping", "Coin Data of Last %d Weeks" ); +static LocalizedString DAY_OF_WEEK ( "ScreenBookkeeping", "Coin Data by Day of Week, All-Time" ); +static LocalizedString HOUR_OF_DAY ( "ScreenBookkeeping", "Coin Data by Hour of Day, All-Time" ); +void ScreenBookkeeping::UpdateView() +{ + BookkeepingView view = m_vBookkeepingViews[m_iViewIndex]; + + + { + RString s; + s += ALL_TIME.GetValue(); + s += ssprintf( " %i\n", BOOKKEEPER->GetCoinsTotal() ); + m_textAllTime.SetText( s ); + } + + switch( view ) + { + case BookkeepingView_SongPlays: + { + Profile *pProfile = PROFILEMAN->GetMachineProfile(); + + vector vpSongs; + int iCount = 0; + FOREACH_CONST( Song *, SONGMAN->GetAllSongs(), s ) + { + Song *pSong = *s; + if( UNLOCKMAN->SongIsLocked(pSong) & ~LOCKED_DISABLED ) + continue; + iCount += pProfile->GetSongNumTimesPlayed( pSong ); + vpSongs.push_back( pSong ); + } + m_textTitle.SetText( ssprintf(SONG_PLAYS.GetValue(), iCount) ); + SongUtil::SortSongPointerArrayByNumPlays( vpSongs, pProfile, true ); + + const int iSongPerCol = 15; + + int iSongIndex = 0; + for( int i=0; iGetSongNumTimesPlayed( pSong ); + RString sTitle = ssprintf("%4d",iCount) + " " + pSong->GetDisplayFullTitle(); + if( sTitle.length() > 22 ) + sTitle = sTitle.Left(20) + "..."; + s += sTitle + "\n"; + iSongIndex++; + } + } + m_textData[i].SetText( s ); + m_textData[i].SetHorizAlign( align_left ); + } + } + break; + case BookkeepingView_LastDays: + { + m_textTitle.SetText( ssprintf(LAST_DAYS.GetValue(), NUM_LAST_DAYS) ); + + int coins[NUM_LAST_DAYS]; + BOOKKEEPER->GetCoinsLastDays( coins ); + int iTotalLast = 0; + + RString sTitle, sData; + for( int i=0; iGetCoinsLastWeeks( coins ); + + RString sTitle, sData; + for( int col=0; col<4; col++ ) + { + RString sTemp; + for( int row=0; row<52/4; row++ ) + { + int week = row*4+col; + sTemp += LastWeekToLocalizedString(week) + ssprintf(": %d",coins[week]) + "\n"; + } + + m_textData[col].SetHorizAlign( align_left ); + m_textData[col].SetText( sTemp ); + } + } + break; + case BookkeepingView_DayOfWeek: + { + m_textTitle.SetText( DAY_OF_WEEK ); + + int coins[DAYS_IN_WEEK]; + BOOKKEEPER->GetCoinsByDayOfWeek( coins ); + + RString sTitle, sData; + for( int i=0; iGetCoinsByHour( coins ); + + RString sTitle1, sData1; + for( int i=0; i m_vBookkeepingViews; + + BitmapText m_textAllTime; + BitmapText m_textTitle; + BitmapText m_textData[NUM_BOOKKEEPING_COLS]; +}; + +#endif + +/* + * (c) 2003-2004 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/ScreenContinue.cpp b/src/ScreenContinue.cpp index 2b15fa0fe0..373fa4be2f 100644 --- a/src/ScreenContinue.cpp +++ b/src/ScreenContinue.cpp @@ -50,6 +50,9 @@ void ScreenContinue::BeginScreen() bool ScreenContinue::Input( const InputEventPlus &input ) { + if( input.MenuI == GAME_BUTTON_COIN && input.type == IET_FIRST_PRESS ) + ResetTimer(); + if( input.MenuI == GAME_BUTTON_START && input.type == IET_FIRST_PRESS && GAMESTATE->JoinInput(input.pn) ) return true; // handled diff --git a/src/ScreenDebugOverlay.cpp b/src/ScreenDebugOverlay.cpp index 1361f81ab7..e3e26a8c15 100644 --- a/src/ScreenDebugOverlay.cpp +++ b/src/ScreenDebugOverlay.cpp @@ -15,6 +15,7 @@ #include "RageTextureManager.h" #include "MemoryCardManager.h" #include "NoteSkinManager.h" +#include "Bookkeeper.h" #include "ProfileManager.h" #include "CodeDetector.h" #include "RageInput.h" @@ -1034,7 +1035,7 @@ class DebugLineWriteProfiles : public IDebugLine virtual RString GetPageName() const { return "Profiles"; } virtual void DoAndLog( RString &sMessageOut ) { - // Also save profile info for debugging + // Also save bookkeeping and profile info for debugging // so we don't have to play through a whole song to get new output. if( g_ProfileSlot == ProfileSlot_Machine ) GAMESTATE->SaveLocalData(); diff --git a/src/ScreenSelect.cpp b/src/ScreenSelect.cpp index a41478a01a..bed9829df2 100644 --- a/src/ScreenSelect.cpp +++ b/src/ScreenSelect.cpp @@ -101,7 +101,10 @@ bool ScreenSelect::Input( const InputEventPlus &input ) m_timerIdleComment.GetDeltaTime(); m_timerIdleTimeout.GetDeltaTime(); - + /* Choices may change when more coins are inserted. */ + if( input.MenuI == GAME_BUTTON_COIN && input.type == IET_FIRST_PRESS ) + this->UpdateSelectableChoices(); + if( input.MenuI == GAME_BUTTON_START && input.type == IET_FIRST_PRESS && GAMESTATE->JoinInput(input.pn) ) { // HACK: Only play start sound for the 2nd player who joins. The diff --git a/src/ScreenServiceAction.cpp b/src/ScreenServiceAction.cpp index d6f9cdab70..71bc884c04 100644 --- a/src/ScreenServiceAction.cpp +++ b/src/ScreenServiceAction.cpp @@ -1,6 +1,7 @@ #include "global.h" #include "ScreenServiceAction.h" #include "ThemeManager.h" +#include "Bookkeeper.h" #include "Profile.h" #include "ProfileManager.h" #include "ScreenManager.h" @@ -16,6 +17,14 @@ #include "StepMania.h" #include "NotesLoaderSSC.h" +static LocalizedString BOOKKEEPING_DATA_CLEARED( "ScreenServiceAction", "Bookkeeping data cleared." ); +static RString ClearBookkeepingData() +{ + BOOKKEEPER->ClearAll(); + BOOKKEEPER->WriteToDisk(); + return BOOKKEEPING_DATA_CLEARED.GetValue(); +} + static LocalizedString MACHINE_STATS_CLEARED( "ScreenServiceAction", "Machine stats cleared." ); RString ClearMachineStats() { @@ -405,7 +414,8 @@ void ScreenServiceAction::BeginScreen() { RString (*pfn)() = NULL; - if( *s == "ClearMachineStats" ) pfn = ClearMachineStats; + if( *s == "ClearBookkeepingData" ) pfn = ClearBookkeepingData; + else if( *s == "ClearMachineStats" ) pfn = ClearMachineStats; else if( *s == "ClearMachineEdits" ) pfn = ClearMachineEdits; else if( *s == "ClearMemoryCardEdits" ) pfn = ClearMemoryCardEdits; else if( *s == "TransferStatsMachineToMemoryCard" ) pfn = TransferStatsMachineToMemoryCard; diff --git a/src/StepMania-net2008.vcproj b/src/StepMania-net2008.vcproj index 6b70917388..d85e37f480 100644 --- a/src/StepMania-net2008.vcproj +++ b/src/StepMania-net2008.vcproj @@ -444,6 +444,14 @@ RelativePath="Screen.h" > + + + + @@ -3936,6 +3944,14 @@ RelativePath="AnnouncerManager.h" > + + + + diff --git a/src/StepMania-net2010.vcxproj b/src/StepMania-net2010.vcxproj index ce6cf4c69a..8b0b897bd3 100644 --- a/src/StepMania-net2010.vcxproj +++ b/src/StepMania-net2010.vcxproj @@ -364,6 +364,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)verstub.obj" + @@ -769,6 +770,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)verstub.obj" + HAVE_VERSION_INFO;%(PreprocessorDefinitions) @@ -1676,6 +1678,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)verstub.obj" + @@ -2088,6 +2091,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)verstub.obj" + diff --git a/src/StepMania-net2010.vcxproj.filters b/src/StepMania-net2010.vcxproj.filters index 9537dbd12d..f1863366af 100644 --- a/src/StepMania-net2010.vcxproj.filters +++ b/src/StepMania-net2010.vcxproj.filters @@ -123,6 +123,9 @@ Screens + + Screens + Screens @@ -1290,6 +1293,9 @@ Global Singletons + + Global Singletons + Global Singletons @@ -1619,6 +1625,9 @@ Screens + + Screens + Screens @@ -2816,6 +2825,9 @@ Global Singletons + + Global Singletons + Global Singletons diff --git a/src/StepMania-net2011.vcxproj b/src/StepMania-net2011.vcxproj index 3d3a486577..cb07dac972 100644 --- a/src/StepMania-net2011.vcxproj +++ b/src/StepMania-net2011.vcxproj @@ -382,6 +382,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)" + @@ -787,6 +788,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)" + HAVE_VERSION_INFO;%(PreprocessorDefinitions) @@ -1694,6 +1696,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)" + @@ -2106,6 +2109,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)" + diff --git a/src/StepMania-net2011.vcxproj.filters b/src/StepMania-net2011.vcxproj.filters index f7da9a3879..f1863366af 100644 --- a/src/StepMania-net2011.vcxproj.filters +++ b/src/StepMania-net2011.vcxproj.filters @@ -123,6 +123,9 @@ Screens + + Screens + Screens @@ -1290,6 +1293,9 @@ Global Singletons + + Global Singletons + Global Singletons @@ -1619,6 +1625,9 @@ Screens + + Screens + Screens @@ -2816,6 +2825,9 @@ Global Singletons + + Global Singletons + Global Singletons @@ -3118,4 +3130,4 @@ BaseClasses - \ No newline at end of file + diff --git a/src/StepMania.cpp b/src/StepMania.cpp index 6995a2cc86..16b46a8a95 100644 --- a/src/StepMania.cpp +++ b/src/StepMania.cpp @@ -57,6 +57,7 @@ //#include "BackgroundCache.h" #include "UnlockManager.h" #include "RageFileManager.h" +#include "Bookkeeper.h" #include "LightsManager.h" #include "ModelManager.h" #include "CryptManager.h" @@ -300,6 +301,7 @@ void ShutdownGame() SAFE_DELETE( NOTESKIN ); SAFE_DELETE( THEME ); SAFE_DELETE( ANNOUNCER ); + SAFE_DELETE( BOOKKEEPER ); SAFE_DELETE( LIGHTSMAN ); SAFE_DELETE( SOUNDMAN ); SAFE_DELETE( FONT ); @@ -1110,6 +1112,7 @@ int main(int argc, char* argv[]) SOUNDMAN->Init(); SOUNDMAN->SetMixVolume(); SOUND = new GameSoundManager; + BOOKKEEPER = new Bookkeeper; LIGHTSMAN = new LightsManager; INPUTFILTER = new InputFilter; INPUTMAPPER = new InputMapper; @@ -1232,6 +1235,63 @@ RString StepMania::SaveScreenshot( RString sDir, bool bSaveCompressed, bool bMak return sFileName; } +void StepMania::InsertCoin( int iNum, bool bCountInBookkeeping ) +{ + if( bCountInBookkeeping ) + { + LIGHTSMAN->PulseCoinCounter(); + BOOKKEEPER->CoinInserted(); + } + int iNumCoinsOld = GAMESTATE->m_iCoins; + GAMESTATE->m_iCoins.Set( GAMESTATE->m_iCoins + iNum ); + + int iCredits = GAMESTATE->m_iCoins / PREFSMAN->m_iCoinsPerCredit; + bool bMaxCredits = iCredits >= MAX_NUM_CREDITS; + if( bMaxCredits ) + GAMESTATE->m_iCoins.Set( MAX_NUM_CREDITS * PREFSMAN->m_iCoinsPerCredit ); + + LOG->Trace("%i coins inserted, %i needed to play", GAMESTATE->m_iCoins.Get(), PREFSMAN->m_iCoinsPerCredit.Get() ); + if( iNumCoinsOld != GAMESTATE->m_iCoins ) + SCREENMAN->PlayCoinSound(); + else + SCREENMAN->PlayInvalidSound(); + + /* If AutoJoin and a player is already joined, then try to join a player. + * (If no players are joined, they'll join on the first JoinInput.) */ + if( GAMESTATE->m_bAutoJoin.Get() && GAMESTATE->GetNumSidesJoined() > 0 ) + { + if( GAMESTATE->GetNumSidesJoined() > 0 && GAMESTATE->JoinPlayers() ) + SCREENMAN->PlayStartSound(); + } + + // TODO: remove this redundant message and things that depend on it + Message msg( "CoinInserted" ); + // below params are unused + //msg.SetParam( "Coins", GAMESTATE->m_iCoins ); + //msg.SetParam( "Inserted", iNum ); + //msg.SetParam( "MaxCredits", bMaxCredits ); + MESSAGEMAN->Broadcast( msg ); +} + +void StepMania::InsertCredit() +{ + InsertCoin( PREFSMAN->m_iCoinsPerCredit, false ); +} + +void StepMania::ClearCredits() +{ + LOG->Trace("%i coins cleared", GAMESTATE->m_iCoins.Get() ); + GAMESTATE->m_iCoins.Set( 0 ); + SCREENMAN->PlayInvalidSound(); + + // TODO: remove this redundant message and things that depend on it + Message msg( "CoinInserted" ); + // below params are unused + //msg.SetParam( "Coins", GAMESTATE->m_iCoins ); + //msg.SetParam( "Clear", true ); + MESSAGEMAN->Broadcast( msg ); +} + /* Returns true if the key has been handled and should be discarded, false if * the key should be sent on to screens. */ static LocalizedString SERVICE_SWITCH_PRESSED ( "StepMania", "Service switch pressed" ); @@ -1260,12 +1320,21 @@ bool HandleGlobalInputs( const InputEventPlus &input ) } return true; + case GAME_BUTTON_COIN: + // Handle a coin insertion. + if( GAMESTATE->IsEditing() ) // no coins while editing + { + LOG->Trace( "Ignored coin insertion (editing)" ); + break; + } + StepMania::InsertCoin(); + return false; // Attract needs to know because it goes to TitleMenu on > 1 credit default: break; } /* Re-added for StepMania 3.9 theming veterans, plus it's just faster than * the debug menu. The Shift button only reloads the metrics, unlike in 3.9 - * (where it saved machine profile). -aj */ + * (where it saved bookkeeping and machine profile). -aj */ bool bIsShiftHeld = INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT), &input.InputList) || INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT), &input.InputList); bool bIsCtrlHeld = INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL), &input.InputList) || diff --git a/src/StepMania.h b/src/StepMania.h index 7cd72c28da..a489de6c78 100644 --- a/src/StepMania.h +++ b/src/StepMania.h @@ -20,6 +20,10 @@ namespace StepMania // If successful, return filename of screenshot in sDir, else return "" RString SaveScreenshot( RString sDir, bool bSaveCompressed, bool bMakeSignature, int iIndex = -1 ); + void InsertCoin( int iNum = 1, bool bCountInBookkeeping = true ); + void InsertCredit(); + void ClearCredits(); + void GetPreferredVideoModeParams( VideoModeParams ¶msOut ); bool GetHighResolutionTextures(); }