diff --git a/data/images/rewindprevply/1.5.png b/data/images/rewindprevply/1.5.png new file mode 100644 index 00000000..1311e111 Binary files /dev/null and b/data/images/rewindprevply/1.5.png differ diff --git a/data/images/rewindprevply/1.png b/data/images/rewindprevply/1.png new file mode 100644 index 00000000..0f41db49 Binary files /dev/null and b/data/images/rewindprevply/1.png differ diff --git a/data/images/rewindprevply/2.png b/data/images/rewindprevply/2.png new file mode 100644 index 00000000..5db32f9d Binary files /dev/null and b/data/images/rewindprevply/2.png differ diff --git a/data/transl/catalan.txt b/data/transl/catalan.txt index 5b40db32..5ed3afec 100644 --- a/data/transl/catalan.txt +++ b/data/transl/catalan.txt @@ -139,9 +139,10 @@ $gameShowSplatRuler Mostra el regle d'esclafades. $gameHighlightGoals Ressalta els teus propis caus i objectius. $gameStateSave Desa la posició ràpidament. $gameStateLoad Carrrega ràpidament una posició. -$gameShowTweaker Mostra l'ajustador de repeticions -$gameFramestepBack %s per fer un pas enrere, %s per saltar enrere. -$gameFramestepAhead %s per fer un pas endavant, %s per saltar endavant. +$gameShowTweaker Mostra l'ajustador de repeticions. +$gameRewindPrevPly Rebobina l'habilitat més recent. +$gameRewindOneTick %s per fer un pas enrere, %s per saltar enrere. +$gameSkipOneTick %s per fer un pas endavant, %s per saltar endavant. $gameFastForward %s per avançar ràpidament, %s per a avanç turbo. $gameRestart Reiniciar el nivell. $gameNuke Bomba nuclear. Fes doble clic per activar-la. @@ -317,7 +318,7 @@ $optionTitle Opcions|Va al menú d'opcions des del menú principal. $optionGroupGeneral General $optionGroupGraphics Gràfics $optionGroupControls Controls -$optionGroupReplay Repetitió +$optionGroupGameControls Controls del joc $optionGroupGameKeys Tecles del joc $optionGroupEditorKeys Tecles de l'editor $optionGroupMenuKeys Tecles del menú @@ -367,10 +368,11 @@ $optionInsertAssignments Insertar habilitats|After ◀▮, assigning skills pres $optionKeyForceLeft Forçar l'esquerra|Mantenir per assignar habilitats als lix encarats a l'esquerra.|És útil en un manat dens de lix. $optionKeyForceRight Forçar la dreta|Mantenir per assignar habilitats als lix encarats a la dreta.|És útil en un manat dens de lix. $optionKeyPause Pausar|Pausar el joc.|Pots escollir si assignar habilitats hauria de despausar o no, veure avall. -$optionKeyFrameBackMany ◀▮ 1 segon.|Rebobina el joc 1 segon. -$optionKeyFrameBackOne ◀▮ 1 fotograma|Rebobina el joc 1 fotograma, és a dir, ¹⁄₁₅ de segon. -$optionKeyFrameAheadOne ▮▶ 1 fotograma|Avança el joc 1 fotograma, és a dir, ¹⁄₁₅ de segon. -$optionKeyFrameAheadMany ▮▶ 10 segons|Avança el joc 10 segons. +$optionKeyRewindPrevPly ⬚◀◀|Rebobina l'habilitat més recent.|Then, click air to erase the assignment, or unpause to replay it. +$optionKeyRewindOneSecond ◀▮ 1 segon.|Rebobina el joc 1 segon. +$optionKeyRewindOneTick ◀▮ 1 fotograma|Rebobina el joc 1 tick, és a dir, ¹⁄₁₅ de segon. +$optionKeySkipOneTick ▮▶ 1 fotograma|Avança el joc 1 tick, és a dir, ¹⁄₁₅ de segon. +$optionKeySkipTenSeconds ▮▶ 10 segons|Avança el joc 10 segons. $optionKeySpeedFast ▶▶|Activa l'avanç ràpid.|L'avanç ràpid és 4 vegades més ràpid que la velocitat normal. $optionKeySpeedTurbo ▶▶▶|Activa l'avanç turbo|L'avanç turbo és 36 vegades més ràpid que la velocitat normal. $optionKeyRestart Reiniciar|Reinicia el nivell des del començament. Totes les accions es repetiran.|Per interrompre la repetició, fes clic a l'aire. diff --git a/data/transl/english.txt b/data/transl/english.txt index 6c020104..f4c09928 100644 --- a/data/transl/english.txt +++ b/data/transl/english.txt @@ -140,8 +140,9 @@ $gameHighlightGoals Highlight own hatches and goals. $gameStateSave Quicksave game position. $gameStateLoad Load quicksaved position. $gameShowTweaker Show replay tweaker. -$gameFramestepBack %s to step back, %s to jump back. -$gameFramestepAhead %s to step ahead, %s to jump ahead. +$gameRewindPrevPly Rewind your previous skill assignment. +$gameRewindOneTick %s to rewind 1 tick, %s to rewind 1 second. +$gameSkipOneTick %s to advance 1 tick, %s to skip 10 seconds. $gameFastForward %s for fast-forward, %s for turbo. $gameRestart Restart level. $gameNuke Nuke. Double-click to activate. @@ -315,7 +316,7 @@ $optionTitle Options|From the main menu, go to the options menu. $optionGroupGeneral General $optionGroupGraphics Graphics $optionGroupControls Controls -$optionGroupReplay Replay +$optionGroupGameControls Game Controls $optionGroupGameKeys Game Keys $optionGroupEditorKeys Editor Keys $optionGroupMenuKeys Menu Keys @@ -365,10 +366,11 @@ $optionInsertAssignments Insert Assignments|After ◀▮, assigning skills prese $optionKeyForceLeft Force left|Hold to assign skills to lix facing left.|This is useful in a dense bunch of lix. $optionKeyForceRight Force right|Hold to assign skills to lix facing right.|This is useful in a dense bunch of lix. $optionKeyPause Pause|Pause the game.|You can choose whether skill assignments should unpause, see below. -$optionKeyFrameBackMany ◀▮ 1 sec.|Rewind the game by 1 second. -$optionKeyFrameBackOne ◀▮ 1 frame|Rewind the game by 1 frame, i.e., by ¹⁄₁₅ of a second. -$optionKeyFrameAheadOne ▮▶ 1 frame|Advance the game by 1 frame, i.e., by ¹⁄₁₅ of a second. -$optionKeyFrameAheadMany ▮▶ 10 sec.|Advance the game by 10 seconds. +$optionKeyRewindPrevPly ⬚◀◀|Rewind your most recent skill assignment.|Then, click air to erase the assignment, or unpause to replay it. +$optionKeyRewindOneSecond ◀▮ 1 Sec.|Rewind the game by 1 second. +$optionKeyRewindOneTick ◀▮ 1 Tick|Rewind the game by 1 tick, i.e., by ¹⁄₁₅ of a second. +$optionKeySkipOneTick ▮▶ 1 Tick|Advance the game by 1 tick, i.e., by ¹⁄₁₅ of a second. +$optionKeySkipTenSeconds ▮▶ 10 Sec.|Advance the game by 10 seconds. $optionKeySpeedFast ▶▶|Toggle fast-forward.|Fast-forward is 4 times faster than normal speed. $optionKeySpeedTurbo ▶▶▶|Toggle turbo-fast-forward.|Turbo-fast-forward is 36 times faster than normal speed. $optionKeyRestart Restart|Restart the level from the beginning. All your actions will replay.|To interrupt the replay, click into the air. diff --git a/data/transl/german.txt b/data/transl/german.txt index 3be732a1..4734c5c9 100644 --- a/data/transl/german.txt +++ b/data/transl/german.txt @@ -136,8 +136,9 @@ $gameHighlightGoals Eigene Klappen und Ziele hervorheben. $gameStateSave Spielstand schnellspeichern. $gameStateLoad Schnellgespeicherten Spielstand laden. $gameShowTweaker Replay-Justierer anzeigen. -$gameFramestepBack %s für Schritt zurück, %s für Sprung zurück. -$gameFramestepAhead %s für Schritt vorwärts, %s für Sprung vorwärts. +$gameRewindPrevPly Deine letzte Fähigkeitszuweisung zurückspulen. +$gameRewindOneTick %s spult 1 Tick zurück, %s spult 1 Sekunde zurück. +$gameSkipOneTick %s geht 1 Tick vor, %s springt 10 Sekunden vor. $gameFastForward %s für schnellen Vorlauf, %s für Turbo. $gameRestart Level neu starten. $gameNuke Atombombe. Aktiviere per Doppelklick. @@ -304,7 +305,7 @@ $optionTitle Optionen|Vom Hauptmenü das Optionsmenü aufrufen. $optionGroupGeneral Allgemein $optionGroupGraphics Grafik $optionGroupControls Steuerung -$optionGroupReplay Replay +$optionGroupGameControls Spielsteuerung $optionGroupGameKeys Spieltasten $optionGroupEditorKeys Editortasten $optionGroupMenuKeys Menütasten @@ -357,10 +358,11 @@ $optionInsertAssignments Zuweisungen einfügen|Nach ◀▮ belassen neue Zuweisu $optionKeyForceLeft Nur links|Halte gedrückt, um Fähigkeiten an Linksläufer zuzuweisen.|Das ist nützlich in dichten Ansammlungen von Lix. $optionKeyForceRight Nur rechts|Halte gedrückt, um Fähigkeiten an Rechtsläufer zuzuweisen.|Das ist nützlich in dichten Ansammlungen von Lix. $optionKeyPause Pause|Das Spiel pausieren.|Du kannst unten bestimmen, ob Fähigkeitszuweisungen die Pause beenden. -$optionKeyFrameBackMany ◀▮ 1 Sek.|Das Spiel um 1 Sekunde zurückspulen. -$optionKeyFrameBackOne ◀▮ 1 Bild|Das Spiel um 1 Physik-Update zurückspulen, also um ¹⁄₁₅ einer Sekunde. -$optionKeyFrameAheadOne ▮▶ 1 Bild|Das Spiel um 1 Physik-Update vorspulen, also um ¹⁄₁₅ einer Sekunde. -$optionKeyFrameAheadMany ▮▶ 10 Sek.|Das Spiel um 10 Sekunden vorspulen. +$optionKeyRewindPrevPly ⬚◀◀|Deine letzte Fähigkeitszuweisung zurückspulen.|Klicke anschließend in die Luft, um die Zuweisung zu löschen. +$optionKeyRewindOneSecond ◀▮ 1 Sek.|Das Spiel um 1 Sekunde zurückspulen. +$optionKeyRewindOneTick ◀▮ 1 Tick|Das Spiel um 1 Physik-Update zurückspulen, also um ¹⁄₁₅ einer Sekunde. +$optionKeySkipOneTick ▮▶ 1 Tick|Das Spiel um 1 Physik-Update vorspulen, also um ¹⁄₁₅ einer Sekunde. +$optionKeySkipTenSeconds ▮▶ 10 Sek.|Das Spiel um 10 Sekunden vorspulen. $optionKeySpeedFast ▶▶|Schnellen Vorlauf an- und ausschalten.|Schneller Vorlauf ist 4-mal so schnell wie normales Spiel. $optionKeySpeedTurbo ▶▶▶|Turbo-Vorlauf an- und ausschalten.|Turbo-Vorlauf ist 36-mal so schnell wie normales Spiel. $optionKeyRestart Neustart|Den Level komplett von vorne starten, mit Replay deiner Aktionen.|Um das Replay abzubrechen, klicke in die Luft. diff --git a/data/transl/swedish.txt b/data/transl/swedish.txt index d266332b..42172bda 100644 --- a/data/transl/swedish.txt +++ b/data/transl/swedish.txt @@ -140,8 +140,9 @@ $gameHighlightGoals Markera egna luckor och mål. $gameStateSave Snabbspara spelposition. $gameStateLoad Läs in snabbsparad position. $gameShowTweaker Visa repristrimmare. -$gameFramestepBack %s för att kliva bakåt, %s för att hoppa bakåt. -$gameFramestepAhead %s för att kliva framåt, %s för att hoppa framåt. +$gameRewindPrevPly Spola tillbaka din senaste tilldelning av förmågor. +$gameRewindOneTick %s för att spola tillbaka 1 tick, %s för 1 sekund. +$gameSkipOneTick %s för att flytta fram 1 tick, %s för 10 sekunder. $gameFastForward %s för att snabbspola framåt, %s för turbo. $gameRestart Starta om bana. $gameNuke Spräng. Dubbelklicka för att aktivera. @@ -315,7 +316,7 @@ $optionTitle Inställningar|Gå till menyn för inställningar från huvudmenyn. $optionGroupGeneral Allmänt $optionGroupGraphics Grafik $optionGroupControls Kontroller -$optionGroupReplay Repris +$optionGroupGameControls Spelkontroller $optionGroupGameKeys Speltangenter $optionGroupEditorKeys Redigerartangenter $optionGroupMenuKeys Menytangenter @@ -365,10 +366,11 @@ $optionInsertAssignments Infoga ny tilldelningen|After ◀▮, assigning skills $optionKeyForceLeft Tvinga vänster|Håll för att tildela förmågor till vänsterriktade lix.|Detta är användbart i en tät grupp av lix. $optionKeyForceRight Tvinga höger|Håll för att tilldela förmågor till högerriktade lix.|Detta är användbart i en tät grupp av lix. $optionKeyPause Pausa|Pausa spelet.|Du kan välja om tilldelning av förmågor borde opausa, se nedanför. -$optionKeyFrameBackMany ◀▮ 1 sek.|Spola tillbaka spelet med 1 sekund. -$optionKeyFrameBackOne ◀▮ 1 bild|Spola tillbaka spelet med 1 bild, dvs med ¹⁄₁₅ av en sekund. -$optionKeyFrameAheadOne ▮▶ 1 bild|Spola fram spelet med 1 bild, dvs med ¹⁄₁₅ av en sekund. -$optionKeyFrameAheadMany ▮▶ 10 sek.|Spola fram spelet med 10 sekunder. +$optionKeyRewindPrevPly ⬚◀◀|Spola tillbaka din senaste tilldelning av förmågor.|Klicka sedan i luften för att radera tilldelningen eller låta den spelas upp igen. +$optionKeyRewindOneSecond ◀▮ 1 sek.|Spola tillbaka spelet med 1 sekund. +$optionKeyRewindOneTick ◀▮ 1 tick|Spola tillbaka spelet med 1 tick, dvs med ¹⁄₁₅ av en sekund. +$optionKeySkipOneTick ▮▶ 1 tick|Spola fram spelet med 1 tick, dvs med ¹⁄₁₅ av en sekund. +$optionKeySkipTenSeconds ▮▶ 10 sek.|Spola fram spelet med 10 sekunder. $optionKeySpeedFast ▶▶|Växla snabbspolning framåt.|Snabbspolning framåt är 4 bilder snabbare än normal hastighet. $optionKeySpeedTurbo ▶▶▶|Växla turbosnabbspolning framåt.|Turbosnappspolning framåt är 36 bilder snabbare än normal hastighet. $optionKeyRestart Starta om|Starta om banan från början. Alla dina åtgärder kommer att repriseras.|Klicka i luften för att avbryta reprisen. @@ -381,7 +383,7 @@ $optionKeyHighlightGoals Markera mål|Markera egna luckor och mål under nätver $optionKeyNuke Spräng|Spräng alla dina lix i enspelarläge för att klara banan.|Starta övertid i flerspelarläge om du har räddat minst 1 lix. $optionAvoidBuilderQueuing Föredra spamning framför köläggning|Föredra byggaretilldelningar framför icke-byggare istället för att kölägga till existerande byggare.|Du kan hålla omvänd prioritering för att göra det du inte föredrar. -$optionAvoidBatterToExploder Föredra slagmän framför icke-exploderare.|Föredra slagmäntilldelningar framför gångare istället för slagmäntilldeningar framför tidsinställda exploderare|Du kan hålla omvänd prioritering. +$optionAvoidBatterToExploder Föredra slagmän framför icke-exploderare.|Föredra slagmäntilldelningar framför gångare istället för slagmäntilldelningar framför tidsinställda exploderare|Du kan hålla omvänd prioritering. $optionUnpauseOnAssign Fortsätt spelet vid tilldelning av förmåga|Fortsätt spelet då du tilldelar en förmåga under paus.|Om inte förbockat kommer tilldelning av förmågor under paus att fortsätta spelet med 1 bild. $optionKeyMenuOkay Okej/ja|Spela den markerade banan. Spara och stäng dialogfönster. diff --git a/src/file/lang/enum_.d b/src/file/lang/enum_.d index cf02a474..07af0161 100644 --- a/src/file/lang/enum_.d +++ b/src/file/lang/enum_.d @@ -133,8 +133,9 @@ enum Lang { gameStateSave, gameStateLoad, gameShowTweaker, - gameFramestepBack, - gameFramestepAhead, + gameRewindPrevPly, + gameRewindOneTick, + gameSkipOneTick, gameFastForward, gameRestart, gameNuke, @@ -285,7 +286,7 @@ enum Lang { optionGroupGeneral, optionGroupGraphics, optionGroupControls, - optionGroupReplay, + optionGroupGameControls, optionGroupGameKeys, optionGroupEditorKeys, optionGroupMenuKeys, @@ -339,10 +340,11 @@ enum Lang { optionKeyForceLeft, optionKeyForceRight, optionKeyPause, - optionKeyFrameBackMany, - optionKeyFrameBackOne, - optionKeyFrameAheadOne, - optionKeyFrameAheadMany, + optionKeyRewindPrevPly, + optionKeyRewindOneSecond, + optionKeyRewindOneTick, + optionKeySkipOneTick, + optionKeySkipTenSeconds, optionKeySpeedFast, optionKeySpeedTurbo, optionKeyRestart, diff --git a/src/file/option/allopts.d b/src/file/option/allopts.d index 8c3aad73..ab1ca34b 100644 --- a/src/file/option/allopts.d +++ b/src/file/option/allopts.d @@ -139,10 +139,11 @@ UserOption!KeySet keyForceLeft, keyForceRight, keyPause, - keyFrameBackMany, - keyFrameBackOne, - keyFrameAheadOne, - keyFrameAheadMany, + keyRewindPrevPly, + keyRewindOneSecond, + keyRewindOneTick, + keySkipOneTick, + keySkipTenSeconds, keySpeedFast, keySpeedTurbo, keyRestart, @@ -368,10 +369,16 @@ do { keyForceLeft = newKey2("keyForceLeft", Lang.optionKeyForceLeft, ALLEGRO_KEY_S, ALLEGRO_KEY_LEFT); keyForceRight = newKey2("keyForceRight", Lang.optionKeyForceRight, ALLEGRO_KEY_F, ALLEGRO_KEY_RIGHT); keyPause = newKey2("keyPause", Lang.optionKeyPause, ALLEGRO_KEY_SPACE, hardware.keyenum.keyMMB); - keyFrameBackMany = newKey("keySpeedBackMany", Lang.optionKeyFrameBackMany, ALLEGRO_KEY_1); - keyFrameBackOne = newKey("keySpeedBackOne", Lang.optionKeyFrameBackOne, ALLEGRO_KEY_2); - keyFrameAheadOne = newKey("keySpeedAheadOne", Lang.optionKeyFrameAheadOne, ALLEGRO_KEY_3); - keyFrameAheadMany = newKey("keySpeedAheadMany", Lang.optionKeyFrameAheadMany, ALLEGRO_KEY_6); + keyRewindPrevPly = newOpt("keyRewindPrevPly", + Lang.optionKeyRewindPrevPly, KeySet()); + keyRewindOneSecond = newKey("keySpeedBackMany", + Lang.optionKeyRewindOneSecond, ALLEGRO_KEY_1); + keyRewindOneTick = newKey("keySpeedBackOne", + Lang.optionKeyRewindOneTick, ALLEGRO_KEY_2); + keySkipOneTick = newKey("keySpeedAheadOne", + Lang.optionKeySkipOneTick, ALLEGRO_KEY_3); + keySkipTenSeconds = newKey("keySpeedAheadMany", + Lang.optionKeySkipTenSeconds, ALLEGRO_KEY_6); keySpeedFast = newKey("keySpeedFast", Lang.optionKeySpeedFast, ALLEGRO_KEY_4); keySpeedTurbo = newKey("keySpeedTurbo", Lang.optionKeySpeedTurbo, ALLEGRO_KEY_5); keyRestart = newKey("keyRestart", Lang.optionKeyRestart, ALLEGRO_KEY_F1); diff --git a/src/game/core/speed.d b/src/game/core/speed.d index 39b3f97e..d691bfde 100644 --- a/src/game/core/speed.d +++ b/src/game/core/speed.d @@ -1,9 +1,10 @@ module game.core.speed; +import std.algorithm; import core.time; -static import basics.globals; import basics.alleg5; +static import basics.globals; import file.option; // replayAfterFrameBack import game.core.game; import game.nurse.cache : DuringTurbo; @@ -32,16 +33,21 @@ void dispatchTweaks(Game game) void updatePhysicsAccordingToSpeedButtons(Game game) { with (game) { - if (pan.framestepBackOne) { - with (LoadStateRAII(game)) - game.nurse.framestepBackBy(1); + if (pan.rewindPrevPly) { + game.nurse.framestepBackBy(game.numPhyusToBackstepToPrevPly); + game.finishFramestepping(AndThen.pauseUnlessAtBeginning); } - else if (pan.framestepBackMany) { - with (LoadStateRAII(game)) - game.nurse.framestepBackBy(Game.updatesBackMany); + else if (pan.rewindOneSecond) { + game.nurse.framestepBackBy(Game.updatesBackMany); + game.finishFramestepping(AndThen.pause); + } + if (pan.rewindOneTick) { + game.nurse.framestepBackBy(1); + game.finishFramestepping(AndThen.pause); } else if (pan.restart) { - game.restartLevel(); + game.nurse.restartLevel(); + game.finishFramestepping(AndThen.unpause); } else if (pan.saveState) { nurse.saveUserState(); @@ -50,17 +56,19 @@ void updatePhysicsAccordingToSpeedButtons(Game game) { with (game) hardware.sound.playQuiet(Sound.CLOCK); } else if (pan.loadState) { - if (nurse.userStateExists) - with (LoadStateRAII(game)) { - nurse.loadUserState(); - _effect.quickload(); - } + if (nurse.userStateExists) { + nurse.loadUserState(); + _effect.quickload(); + game.finishFramestepping(AndThen.pause); + } } - else if (pan.framestepAheadOne) { + else if (pan.skipOneTick) { game.upd(1, DuringTurbo.no); + game.pan.pause = true; } - else if (pan.framestepAheadMany) { + else if (pan.skipTenSeconds) { game.upd(updatesAheadMany, DuringTurbo.no); + // Don't pause. Don't unpause either. Keep pause as-is. } else if (pan.paused && isMouseOnLand && mouseClickLeft) { // Clicking into the non-panel screen advances physics once. @@ -83,14 +91,6 @@ void updatePhysicsAccordingToSpeedButtons(Game game) { with (game) } } }} -// end with (game), end function updatePhysicsAccordingToSpeedButtons - -void restartLevel(Game game) -{ - game.pan.setSpeedNormal(); - with (LoadStateRAII(game)) - game.nurse.restartLevel(); -} // The server tells us the milliseconds since game start, and the net client // has added our lag. We think in Phyus or Allegro ticks, not in millis, @@ -120,11 +120,22 @@ void recordServersWishSinceGameStart( private: ////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -struct LoadStateRAII +enum AndThen { + pause, + pauseUnlessAtBeginning, + unpause +} + +void finishFramestepping(Game game, in AndThen andThen) { - private Game _game; - this(Game g) { _game = g; } - ~this() { _game.setLastPhyuToNow(); } + game.setLastPhyuToNow(); + final switch (andThen) { + case AndThen.pause: game.pan.pause = true; return; + case AndThen.unpause: game.pan.pause = false; return; + case AndThen.pauseUnlessAtBeginning: + game.pan.pause = (game.nurse.updatesSinceZero != 0); + return; + } } // Combat the network time-lag, affect _alticksToAdjust. @@ -158,3 +169,13 @@ private void upd(Game game, in int howmany, in DuringTurbo duringTurbo) game.nurse.updateTo(Phyu(before + howmany), duringTurbo); game.setLastPhyuToNow(); } + +int numPhyusToBackstepToPrevPly(Game game) +{ + immutable Phyu now = game.nurse.now; + immutable Phyu target = game.replay.allPlies + .filter!(ply => ply.when <= now) + .map!(ply => ply.when) + .fold!max(Phyu(now - game.nurse.updatesSinceZero)); + return now - target + 1; // The +1 goes back to the phyu before that ply. +} diff --git a/src/game/panel/base.d b/src/game/panel/base.d index a6261b9c..30acc458 100644 --- a/src/game/panel/base.d +++ b/src/game/panel/base.d @@ -64,8 +64,9 @@ public: // Copy-pasted function names from RightButtons. static foreach (field; ["paused", "speedIsNormal", "speedIsFast", "speedIsTurbo", "restart", "saveState", "loadState", - "framestepBackOne", "framestepBackMany", "framestepAheadOne", - "framestepAheadMany", "splatRulerIsOn", "tweakerIsOn", + "rewindPrevPly", "rewindOneSecond", "rewindOneTick", + "skipOneTick", "skipTenSeconds", + "splatRulerIsOn", "tweakerIsOn", "highlightGoalsExecute", "nukeDoubleclicked"] ) { import std.format; diff --git a/src/game/panel/rightbut.d b/src/game/panel/rightbut.d index 33a5e2d4..b0d6350a 100644 --- a/src/game/panel/rightbut.d +++ b/src/game/panel/rightbut.d @@ -35,10 +35,11 @@ public: bool restart() { return false; } bool saveState() { return false; } bool loadState() { return false; } - bool framestepBackOne() { return false; } - bool framestepBackMany() { return false; } - bool framestepAheadOne() { return false; } - bool framestepAheadMany() { return false; } + bool rewindPrevPly() { return false; } + bool rewindOneTick() { return false; } + bool rewindOneSecond() { return false; } + bool skipOneTick() { return false; } + bool skipTenSeconds() { return false; } bool splatRulerIsOn() { return false; } bool tweakerIsOn() { return false; } @@ -191,10 +192,11 @@ mixin template TapeRecorderMixin() { bool speedIsFast() { return _trbs.speedIsFast; } bool speedIsTurbo() { return _trbs.speedIsTurbo; } bool restart() { return _trbs.restart; } - bool framestepBackOne() { return _trbs.framestepBackOne; } - bool framestepBackMany() { return _trbs.framestepBackMany; } - bool framestepAheadOne() { return _trbs.framestepAheadOne; } - bool framestepAheadMany() { return _trbs.framestepAheadMany; } + bool rewindPrevPly() { return _trbs.rewindPrevPly; } + bool rewindOneTick() { return _trbs.rewindOneTick; } + bool rewindOneSecond() { return _trbs.rewindOneSecond; } + bool skipOneTick() { return _trbs.skipOneTick; } + bool skipTenSeconds() { return _trbs.skipTenSeconds; } } private void makeTapeRecorder(Geom g) diff --git a/src/game/panel/taperec.d b/src/game/panel/taperec.d index ac90e69b..ee488a15 100644 --- a/src/game/panel/taperec.d +++ b/src/game/panel/taperec.d @@ -33,34 +33,35 @@ private: enum frameTurbo = 5; // All the buttons are non-null, always - BitmapButton _pause, _restart; + BitmapButton _pause, _restart, _rewindPrevPly; NukeButton _nuke; - TwoTasksButton _speedBack, _speedAhead, _speedFast; + TwoTasksButton _rewind, _skip, _speedFast; public: this(Geom g) { super(g); - void newBut(T)(ref T b, int x, int y, int frame, + void newBut(T)(ref T b, int x, int y, InternalImage img, int frame, in UserOption!KeySet keyLeft = null, in UserOption!KeySet keyRight = null) if (is(T : BitmapButton)) { b = new T(new Geom(x * xlg/4f, y * ylg/2f, xlg/4f, ylg/2f), - InternalImage.gamePanel.toCutbit); + img.toCutbit); b.xf = frame; b.hotkey = keyLeft ? keyLeft.value : KeySet(); static if (is (T == TwoTasksButton)) b.hotkeyRight = keyRight ? keyRight.value : KeySet(); addChild(b); } - newBut(_restart, 0, 0, 8, opt.keyRestart); - _restart.resize(xlg/2f, ylg/2f); // Until we have a better layout idea. - - newBut(_speedBack, 0, 1, 10, opt.keyFrameBackOne, opt.keyFrameBackMany); - newBut(_speedAhead, 1, 1, 3, - opt.keyFrameAheadOne, opt.keyFrameAheadMany); - newBut(_speedFast, 2, 1, frameFast, + newBut(_rewindPrevPly, 0, 0, InternalImage.rewindPrevPly, 0, + opt.keyRewindPrevPly); + newBut(_restart, 1, 0, InternalImage.gamePanel, 8, opt.keyRestart); + newBut(_rewind, 0, 1, InternalImage.gamePanel, 10, + opt.keyRewindOneTick, opt.keyRewindOneSecond); + newBut(_skip, 1, 1, InternalImage.gamePanel, 3, + opt.keySkipOneTick, opt.keySkipTenSeconds); + newBut(_speedFast, 2, 1, InternalImage.gamePanel, frameFast, opt.keySpeedFast, opt.keySpeedTurbo); _nuke = new NukeButton(new Geom(2 * xlg/4f, 0, xlg/4f, ylg/2f), @@ -82,10 +83,11 @@ public: bool speedIsTurbo() { return ! paused && _speedFast.on && _speedFast.xf == frameTurbo;} bool restart() { return _restart.execute; } - bool framestepBackOne() { return _speedBack.executeLeft; } - bool framestepBackMany() { return _speedBack.executeRight; } - bool framestepAheadOne() { return _speedAhead.executeLeft; } - bool framestepAheadMany() { return _speedAhead.executeRight; } + bool rewindOneTick() { return _rewind.executeLeft; } + bool rewindOneSecond() { return _rewind.executeRight; } + bool rewindPrevPly() { return _rewindPrevPly.execute; } + bool skipOneTick() { return _skip.executeLeft; } + bool skipTenSeconds() { return _skip.executeRight; } bool nukeDoubleclicked() { return _nuke.doubleclicked; } } @@ -100,8 +102,9 @@ public: do { return _pause.isMouseHere ? Tooltip.ID.pause : _nuke.isMouseHere ? Tooltip.ID.nuke - : _speedBack.isMouseHere ? Tooltip.ID.framestepBack - : _speedAhead.isMouseHere ? Tooltip.ID.framestepAhead + : _rewindPrevPly.isMouseHere ? Tooltip.ID.rewindPrevPly + : _rewind.isMouseHere ? Tooltip.ID.rewindOneTick + : _skip.isMouseHere ? Tooltip.ID.skipOneTick : _restart.isMouseHere ? Tooltip.ID.restart : Tooltip.ID.fastForward; } @@ -121,20 +124,13 @@ public: protected: override void calcSelf() { - assert (!!_pause && !!_speedBack && !!_speedAhead && !!_speedFast); if (_pause.execute) setSpeedTo(paused ? 1 : 0); else if (_speedFast.executeLeft) setSpeedTo(_speedFast.on ? 1 : 2); else if (_speedFast.executeRight) setSpeedTo(_speedFast.xf == frameTurbo ? 1 : 3); - else if (_speedBack.executeLeft || _speedBack.executeRight - || _speedAhead.executeLeft) - setSpeedTo(0); - // We don't handle (speed back to normal) on level restart. - // Game will tell us to set the speed. Reason: Not only we can - // restart the level, but the game can get that command from - // the end-of-level dialog. + // See game.core.speed for pausing/unpausing on framestepping. } private: diff --git a/src/game/panel/tooltip.d b/src/game/panel/tooltip.d index 283242c2..bed59180 100644 --- a/src/game/panel/tooltip.d +++ b/src/game/panel/tooltip.d @@ -32,13 +32,14 @@ struct Tooltip { // When several are requested, only the most important is shown. enum ID : IdSet { pause = 0x1, - showSplatRuler = 0x4, - highlightGoals = 0x8, - stateSave = 0x10, - stateLoad = 0x20, - showTweaker = 0x40, - framestepBack = 0x80, - framestepAhead = 0x100, + showSplatRuler = 0x2, + highlightGoals = 0x4, + stateSave = 0x8, + stateLoad = 0x10, + showTweaker = 0x20, + rewindPrevPly = 0x40, + rewindOneTick = 0x80, + skipOneTick = 0x100, fastForward = 0x200, restart = 0x400, nuke = 0x800, @@ -116,8 +117,9 @@ Tooltip makeTooltip(Tooltip.ID id) nothrow @nogc @safe case ID.stateSave: return none(Lang.gameStateSave); case ID.stateLoad: return none(Lang.gameStateLoad); case ID.showTweaker: return none(Lang.gameShowTweaker); - case ID.framestepBack: return mouse(Lang.gameFramestepBack); - case ID.framestepAhead: return mouse(Lang.gameFramestepAhead); + case ID.rewindPrevPly: return none(Lang.gameRewindPrevPly); + case ID.rewindOneTick: return mouse(Lang.gameRewindOneTick); + case ID.skipOneTick: return mouse(Lang.gameSkipOneTick); case ID.fastForward: return mouse(Lang.gameFastForward); case ID.restart: return none(Lang.gameRestart); case ID.nuke: return none(Lang.gameNuke); diff --git a/src/graphic/internal/names.d b/src/graphic/internal/names.d index 8dc5b327..255f07d9 100644 --- a/src/graphic/internal/names.d +++ b/src/graphic/internal/names.d @@ -35,6 +35,7 @@ enum InternalImage { menuCheckmark, mouse, previewIcon, + rewindPrevPly, skillsInPanel, skillsInTweaker, } @@ -78,6 +79,7 @@ string toBasenameNoExt(in InternalImage id) @nogc case menuCheckmark: return "checkbox"; case mouse: return "mouse"; case previewIcon: return "toruspreview"; + case rewindPrevPly: return "rewindprevply"; case skillsInPanel: return "skillsinpanel"; case skillsInTweaker: return "tweakerskills"; } @@ -96,6 +98,7 @@ bool needGuiRecoloring(in InternalImage id) @nogc case lobbySpec: case menuCheckmark: case previewIcon: + case rewindPrevPly: case skillsInTweaker: return true; default: diff --git a/src/menu/options.d b/src/menu/options.d index aaa35592..6732aebb 100644 --- a/src/menu/options.d +++ b/src/menu/options.d @@ -27,7 +27,8 @@ private: Explainer explainer; enum OptionGroup { - general, graphics, controls, replay, gameKeys, editorKeys, menuKeys + general, graphics, controls, gameControls, + gameKeys, editorKeys, menuKeys } Enumap!(OptionGroup, TextButton) groupButtons; @@ -65,7 +66,7 @@ public this() mkGrpButton(OptionGroup.general, Lang.optionGroupGeneral); mkGrpButton(OptionGroup.graphics, Lang.optionGroupGraphics); mkGrpButton(OptionGroup.controls, Lang.optionGroupControls); - mkGrpButton(OptionGroup.replay, Lang.optionGroupReplay); + mkGrpButton(OptionGroup.gameControls, Lang.optionGroupGameControls); mkGrpButton(OptionGroup.gameKeys, Lang.optionGroupGameKeys); mkGrpButton(OptionGroup.editorKeys, Lang.optionGroupEditorKeys); mkGrpButton(OptionGroup.menuKeys, Lang.optionGroupMenuKeys); @@ -163,7 +164,7 @@ void populateOptionGroups() populateGeneral(); populateGraphics(); populateControls(); - populateReplayOptions(); + populateGameControls(); populateGameKeys(); populateEditorKeys(); populateMenuKeys(); @@ -221,7 +222,6 @@ void populateGraphics() fac.y = bottomHalfY; grp ~= [ fac.factory!BoolOption(paintTorusSeams), - fac.factory!BoolOption(ingameTooltips), fac.factory!BoolOption(showFPS), ]; fac = facRight(); @@ -233,20 +233,6 @@ void populateGraphics() fac.factory!ResolutionOption(screenHardwareFullscreenX, screenHardwareFullscreenY), ]; - fac.y = bottomHalfY; - auto cfg = NumPickConfig(); - cfg.digits = 3; - cfg.min = 0; - cfg.max = 300; - cfg.stepSmall = 2; - cfg.stepMedium = 20; - grp ~= [ - fac.factory!RadioIntOption(splatRulerDesign, - Lang.optionSplatRulerDesign2Bars, - Lang.optionSplatRulerDesign094, - Lang.optionSplatRulerDesign3Bars), - fac.factory!NumPickOption(cfg, splatRulerSnapPixels), - ]; } void populateControls() @@ -277,10 +263,10 @@ void populateControls() addNumPick(holdToScrollSpeed, 1); } -void populateReplayOptions() +void populateGameControls() { auto fac = facLeft(); - groups[OptionGroup.replay] ~= [ + groups[OptionGroup.gameControls] ~= [ fac.factory!RadioBoolOption(replayAfterFrameBack, Lang.optionRewindIsBrowse, true, Lang.optionRewindIsUndo, false), @@ -289,6 +275,27 @@ void populateReplayOptions() fac.factory!HeadingAndBoolOptions(Lang.optionWhenTweakerShown, insertAssignmentsWhenTweakerShown), ]; + fac = facRight(); + groups[OptionGroup.gameControls] ~= [ + fac.factory!BoolOption(unpauseOnAssign), + fac.factory!BoolOption(avoidBuilderQueuing), + fac.factory!BoolOption(avoidBatterToExploder), + fac.factory!BoolOption(ingameTooltips), + ]; + fac.y += 20 + fac.spaceBelow; + auto cfg = NumPickConfig(); + cfg.digits = 3; + cfg.min = 0; + cfg.max = 300; + cfg.stepSmall = 2; + cfg.stepMedium = 20; + groups[OptionGroup.gameControls] ~= [ + fac.factory!RadioIntOption(splatRulerDesign, + Lang.optionSplatRulerDesign2Bars, + Lang.optionSplatRulerDesign094, + Lang.optionSplatRulerDesign3Bars), + fac.factory!NumPickOption(cfg, splatRulerSnapPixels), + ]; } void populateGameKeys() @@ -326,10 +333,11 @@ void populateGameKeys() ]; fac.y += 10f; groups[OptionGroup.gameKeys] ~= [ - fac.factory!HotkeyOption(keyFrameBackMany, watcher), - fac.factory!HotkeyOption(keyFrameBackOne, watcher), - fac.factory!HotkeyOption(keyFrameAheadOne, watcher), - fac.factory!HotkeyOption(keyFrameAheadMany, watcher), + fac.factory!HotkeyOption(keyRewindPrevPly, watcher), + fac.factory!HotkeyOption(keyRewindOneSecond, watcher), + fac.factory!HotkeyOption(keyRewindOneTick, watcher), + fac.factory!HotkeyOption(keySkipOneTick, watcher), + fac.factory!HotkeyOption(keySkipTenSeconds, watcher), ]; fac = facKeys!2; @@ -345,20 +353,6 @@ void populateGameKeys() fac.factory!HotkeyOption(keyShowSplatRuler, watcher), fac.factory!HotkeyOption(keyShowTweaker, watcher), ]; - - fac = facLeft(); - fac.y = 310f; - fac.xl = fac.xl - 10; // Mouse hover area shouldn't obscure other options - groups[OptionGroup.gameKeys] ~= [ - fac.factory!BoolOption(unpauseOnAssign), - ]; - fac = facRight(); - fac.x = xForBoolOptionsBelowHotkeys + keyButtonXl - 20f; - fac.y = 310f; - groups[OptionGroup.gameKeys] ~= [ - fac.factory!BoolOption(avoidBuilderQueuing), - fac.factory!BoolOption(avoidBatterToExploder), - ]; } void populateEditorKeys()