From 5f3ce74c64f9a58cf093f978580b50153fc18da3 Mon Sep 17 00:00:00 2001 From: Pavel Kolchev Date: Tue, 31 Mar 2015 18:14:52 +0300 Subject: [PATCH 1/3] Implemented half/double time mod. Dynamic bpm, map length in song select menu. Fixed replay and spinner with these mods. --- src/itdelatrisu/opsu/GameMod.java | 41 +++++++++++++++++-- src/itdelatrisu/opsu/OsuGroupNode.java | 12 +++--- .../opsu/audio/MusicController.java | 4 +- src/itdelatrisu/opsu/objects/Spinner.java | 2 +- src/itdelatrisu/opsu/states/Game.java | 10 ++--- src/itdelatrisu/opsu/states/SongMenu.java | 5 ++- 6 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java index a7bd3e97..d1a7052b 100644 --- a/src/itdelatrisu/opsu/GameMod.java +++ b/src/itdelatrisu/opsu/GameMod.java @@ -33,7 +33,7 @@ public enum GameMod { "Easy", "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."), NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, Input.KEY_W, 0.5f, "NoFail", "You can't fail. No matter what."), - HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f, false, + HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f, "HalfTime", "Less zoom."), HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, Input.KEY_A, 1.06f, "HardRock", "Everything just got a bit harder..."), @@ -41,7 +41,7 @@ public enum GameMod { "SuddenDeath", "Miss a note and fail."), // PERFECT (Category.HARD, 1, GameImage.MOD_PERFECT, "PF", 64, Input.KEY_S, 1f, // "Perfect", "SS or quit."), - DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f, false, + DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f, "DoubleTime", "Zoooooooooom."), // NIGHTCORE (Category.HARD, 2, GameImage.MOD_NIGHTCORE, "NT", 64, Input.KEY_D, 1.12f, // "Nightcore", "uguuuuuuuu"), @@ -170,9 +170,14 @@ public enum GameMod { Collections.reverse(Arrays.asList(VALUES_REVERSED)); } + private static boolean justChanged = false; + /** The last calculated score multiplier, or -1f if it must be recalculated. */ private static float scoreMultiplier = -1f; + /** */ + private static float speedMultiplier = -1f; + /** * Initializes the game mods. * @param width the container width @@ -198,7 +203,7 @@ public enum GameMod { mod.active = false; } - scoreMultiplier = -1f; + scoreMultiplier = speedMultiplier = -1f; } /** @@ -216,6 +221,32 @@ public enum GameMod { return scoreMultiplier; } + /** + * + */ + public static float getSpeedMultiplier() { + if (speedMultiplier < 0f) { + float multiplier = 1f; + if (DOUBLE_TIME.isActive()) + multiplier = 1.5f; + else if (HALF_TIME.isActive()) + multiplier = 0.75f; + speedMultiplier = multiplier; + } + return speedMultiplier; + } + + /** + * + */ + public static boolean justChanged() { + if (justChanged) { + justChanged = false; + return true; + } + return false; + } + /** * Returns the current game mod state (bitwise OR of active mods). */ @@ -233,6 +264,7 @@ public enum GameMod { * @param state the state (bitwise OR of active mods) */ public static void loadModState(int state) { + scoreMultiplier = speedMultiplier = -1f; for (GameMod mod : GameMod.values()) mod.active = ((state & mod.getBit()) > 0); } @@ -352,7 +384,8 @@ public enum GameMod { return; active = !active; - scoreMultiplier = -1f; + scoreMultiplier = speedMultiplier = -1f; + justChanged = true; if (checkInverse) { if (AUTO.isActive()) { diff --git a/src/itdelatrisu/opsu/OsuGroupNode.java b/src/itdelatrisu/opsu/OsuGroupNode.java index 8c8e15d2..db095130 100644 --- a/src/itdelatrisu/opsu/OsuGroupNode.java +++ b/src/itdelatrisu/opsu/OsuGroupNode.java @@ -118,16 +118,18 @@ public class OsuGroupNode { return null; OsuFile osu = osuFiles.get(osuFileIndex); + long endTime = (long) (osu.endTime / GameMod.getSpeedMultiplier()); + int bpmMin = (int) (osu.bpmMin * GameMod.getSpeedMultiplier()); + int bpmMax = (int) (osu.bpmMax * GameMod.getSpeedMultiplier()); String[] info = new String[5]; info[0] = osu.toString(); info[1] = String.format("Mapped by %s", osu.creator); info[2] = String.format("Length: %d:%02d BPM: %s Objects: %d", - TimeUnit.MILLISECONDS.toMinutes(osu.endTime), - TimeUnit.MILLISECONDS.toSeconds(osu.endTime) - - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(osu.endTime)), - (osu.bpmMax <= 0) ? "--" : - ((osu.bpmMin == osu.bpmMax) ? osu.bpmMin : String.format("%d-%d", osu.bpmMin, osu.bpmMax)), + TimeUnit.MILLISECONDS.toMinutes(endTime), + TimeUnit.MILLISECONDS.toSeconds(endTime) - + TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(endTime)), + (bpmMax <= 0) ? "--" : ((bpmMin == bpmMax) ? bpmMin : String.format("%d-%d", bpmMin, bpmMax)), (osu.hitObjectCircle + osu.hitObjectSlider + osu.hitObjectSpinner)); info[3] = String.format("Circles: %d Sliders: %d Spinners: %d", osu.hitObjectCircle, osu.hitObjectSlider, osu.hitObjectSpinner); diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index 7c93c15d..0050785d 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -279,13 +279,13 @@ public class MusicController { * Plays the current track. * @param loop whether or not to loop the track */ - public static void play(boolean loop) { + public static void play(float pitch, boolean loop) { if (trackExists()) { trackEnded = false; if (loop) player.loop(); else - player.play(); + player.play(pitch, 1f); } } diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 1f5033d5..89c9ca9d 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -135,7 +135,7 @@ public class Spinner implements HitObject { Utils.COLOR_BLACK_ALPHA.a = oldAlpha; // rpm - int rpm = Math.abs(Math.round(sumVelocity / storedVelocities.length * 60)); + int rpm = Math.abs(Math.round(sumVelocity * GameMod.getSpeedMultiplier() / storedVelocities.length * 60)); Image rpmImg = GameImage.SPINNER_RPM.getImage(); rpmImg.setAlpha(alpha); rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f); diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 094116f5..28204fb3 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -1023,11 +1023,6 @@ public class Game extends BasicGameState { // reset game data resetGameData(); - // needs to play before setting position to resume without lag later - MusicController.play(false); - MusicController.setPosition(0); - MusicController.pause(); - // initialize object maps for (int i = 0; i < osu.objects.length; i++) { OsuHitObject hitObject = osu.objects[i]; @@ -1119,6 +1114,11 @@ public class Game extends BasicGameState { leadInTime = osu.audioLeadIn + approachTime; restart = Restart.FALSE; + + // needs to play before setting position to resume without lag later + MusicController.play(GameMod.getSpeedMultiplier(), false); + MusicController.setPosition(0); + MusicController.pause(); } skipButton.resetHover(); diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 87704504..30f2153f 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -336,7 +336,7 @@ public class SongMenu extends BasicGameState { int iconWidth = musicNote.getWidth(); // song info text - if (songInfo == null) { + if (songInfo == null || GameMod.justChanged()) { songInfo = focusNode.getInfo(); if (Options.useUnicodeMetadata()) { // load glyphs OsuFile osu = focusNode.osuFiles.get(0); @@ -349,7 +349,8 @@ public class SongMenu extends BasicGameState { headerTextY += Utils.FONT_LARGE.getLineHeight() - 8; Utils.FONT_DEFAULT.drawString(marginX + iconWidth * 1.05f, headerTextY, songInfo[1], Color.white); headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 2; - Utils.FONT_BOLD.drawString(marginX, headerTextY, songInfo[2], Color.white); + Utils.FONT_BOLD.drawString(marginX, headerTextY, songInfo[2], + (GameMod.DOUBLE_TIME.isActive()) ? Color.red : (GameMod.HALF_TIME.isActive()) ? Color.green : Color.white); headerTextY += Utils.FONT_BOLD.getLineHeight() - 4; Utils.FONT_DEFAULT.drawString(marginX, headerTextY, songInfo[3], Color.white); headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 4; From d8425197a771fc4e7b2ef6b9fea26150adf592b9 Mon Sep 17 00:00:00 2001 From: Pavel Kolchev Date: Thu, 2 Apr 2015 19:38:45 +0300 Subject: [PATCH 2/3] Implement playback speed in replays. --- res/playback-05x.png | Bin 0 -> 2201 bytes res/playback-1x.png | Bin 0 -> 2070 bytes res/playback-2x.png | Bin 0 -> 2195 bytes src/itdelatrisu/opsu/GameImage.java | 4 ++ src/itdelatrisu/opsu/MenuButton.java | 5 ++ .../opsu/audio/MusicController.java | 12 ++++- .../opsu/replay/PlaybackSpeed.java | 50 ++++++++++++++++++ src/itdelatrisu/opsu/states/Game.java | 43 ++++++++++++--- 8 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 res/playback-05x.png create mode 100644 res/playback-1x.png create mode 100644 res/playback-2x.png create mode 100644 src/itdelatrisu/opsu/replay/PlaybackSpeed.java diff --git a/res/playback-05x.png b/res/playback-05x.png new file mode 100644 index 0000000000000000000000000000000000000000..358d7e0c752ba578021fac37081a2cd1895f55d3 GIT binary patch literal 2201 zcmV;K2xj+*P)z;o9_%1Uj!b)AI6C>Gh(2cDC`c z@~t^|cfk&{TJ-a`%_!Z{bkj2;1a46k(Mrqza!yfr4iEr*f3{gsQONCk3lh{-pOhP9 zEj&0nk;$C9LX#4|Co<{R=UYUiy@PoJo13ccyyhWq+ghJCNBckMOL>ReGV`iiGV-ch zvQG?Yrwm8+T0`iClC`E&%eZJp5ipVz_T#*jaZP#2aZ%DWKcQ~}%Z|PF`5#obq%Qrv zwep&z4vU|FN3gA2zoA4yX{irKoP6))SnI(xrk1^nO$X*g7!A@j7AS?spMKUL99nM9 z2tTiL`#vspqQP-!g*hYqJ6+F293+|U(H3o37}LCWv1wCky8$aA8qh{JNOCgsCZ|N6 z$$u@b^W&AK)9c2@43!)E`zuLI&Krwj93`)qUX1xqn7bxGa0?~4--5wM9tw+@fWIlq ziS8&~ZaThvRP<=LtOWqDIa(b*+j>e!N?XFszsIhdl`$iHs;Lt#%Kos^%Eu@JJEKB~ zM#q{$Fe0)Dg39!FfC9vi3}uV=I|L~8Z$oh+ zkY&6v_jTi*WocSyI-?erR7z)B!)OdAG9K&1Xz?2>7e=m5LCnvy-t7FadAJ==k2JTR z5D{{T<0D^5_GVi0*(J#;0yPgG!=yix!PO<1BN7)Bw_fE;zM&TCoflD@475*nWf;1BUtKF;mV&CFvqeY5gz=-J zXFin5M5v!KZNNx->YJ5yPrty$?moa;nR{`1{1E0u@iAuy8>s+MF#rIOF41W#wzq$U zhCBK4OPVvEtcskM`GoeJb(d@kt5tp5IK&9L2e|o-G^cTqe86l{uIMr6=zRyrjz_pjU@sBjfh#9nb}}GzTv3b5>co@nMh9g% z3aaes3{lWelE;R>za&i?AFIahiJs0Z5YBcUDdgWdu7V{7AHAzDbW2=Ky7-D<>_;KiRVM;KkNjo4Jd6trQXH^+Q8S z-=BU~$<|M$o61S(`3=6SJF21=7A*=t?J(f1;KI6Sy+En8TI2OY<Erq^Pu!ooey?iQSdl4S|S)fMIFB_I_*QyO0Q2BpL7Cu_k7sy@V!Yf7c>$Vg2vJ z1`+X?1u*rorZ=`YN&%QYXWqfO`uQQDD(Fb3=Bboq{j^~W+O@x02sDA*c&+X{u7Y|+ z#*GN_6)ksD6sZ(VU!0}il^)9-Ik;8Y^6gMN^gm(_ItcmL?t%mkVwnYS@SiAw5B7Hp z9wacpBq&lqLjeE}e480$u))DV3T!9=K$Ox(0sy@uiYNda?y0C%A4*~XS3LIWSG(K2 zKB;Ri_w(jG?S3Nf&CsXY$8dn|e}j6n?Jl7F`Q_7Zp9Xtu_H|H2Jzrzho;9KffFRdU bzPtZ_v2E>8ouz-)00000NkvXXu0mjf>PRnb literal 0 HcmV?d00001 diff --git a/res/playback-1x.png b/res/playback-1x.png new file mode 100644 index 0000000000000000000000000000000000000000..a5949368a70f48382929c956803e6d540403178f GIT binary patch literal 2070 zcmV+x2^?|9z7osMiNz;iTJLlYe_WthKbI#sp--~oQoeqKsXmC6Lj9;~Hw0Q*K1&t>%0khF& z5rj_&3;>Tdi6HzV=%l*<7>zcAAp9b@k^&tF0Ha{$5b*H0l32|?Er9S{a|yx=yl!`_ z=8xJtQ#ndYlT!RfLDoI`V~Nq>d?y!h`u+#~9Qeo_Sj|2ydgQql@FnDVBt)np<@xIp z<%w}qi8{oAGB>U<9lSoidxVOdpcHM--Ws{*p>Z4l023$}x>{Lz`Dy!e$F6jDa%#sN z>Ag$f_b|(9_K$EyApk%SJ!z6iVYM!y*Z_VZ;mE zsY6-O&4&`AReXn!rEi3s!cx=I2S09K`0KpeRjpQG!n6nRM3F({CMr;ruxL*BxdWT; zY5yQs(^j@cbL5vAbvWO_0WgSrbg9x(@uD_GbyM!*K6BAemF9{a+7#8-@_t1e%+SV2 zkG`}asQEsZ_yfWCT%%6)b{>4S@knouuGSloVML*6!-gD{r!=q;HjcvVDRQQwRF8_N@7a zO~KYBPY6K*ML-3-;_>@M#+D1h**2xkrA84Ik5A+#hBh|T^Orki?1k+7kl)X29|OSr z*svp@6zAq`S0CT9M9Op*g+r$*?3eU%7AdxqfmB0@6lZ4sPPHwLBWY_hyHDTJng+UN zL;=wmqcU5ZE##aDukp%9977nssH-#{cx;BawDb)H0tdYL+9pd)_c)91@TZ2eXa1}N z0Hw1{;oZYWZA~n~;bxFvR#aM}2ZR|gimo1e#~K?yJ#yKP7m_jTZPMi+_R{(mKI_qC zqR2N(xDIYCPMWSHHOJ4`3?!5X!8uF3?Iv5gVSndU;RiNx#aEJx?`Nqp(jJuNU%F=G ziCFM%ql{QXe<)frCz`v~P{hY&|NFLsgb2<#(*gj)007c4Q_+!^pI0u3<#77iZQW;X zYkP*Soe?>y-$8vnLnV5z%**|OmO1+R;cCk>^D`8j`35^s-D3t6<|jnj;at^ON0Xg^ zxwBb#yZpShL9Z|~B4$A8U}Kb`1@q^I6>dnBPS=EC(py{U>5wuBPy~dqlP7Df*$FEY zDfii>b+Y@>L`fIgTG?&|Gywpdo3z!aW4G)w3LJpLZlX;_2b-miMjX40cuIWQAYn=( zCkQ^je3?2(sL($rs87FG7L6XB4W#kvDO%I2umb14xefa;>+T?*(*7lQ%I(Qal3}xv z36e?ZwbkPknA-gebjGB$1y${v-ujomzDwQ1h}gpuAP5bM3Hf06N||u|U13VnZ#z^! z+pd5AYvZ6CrmgXc<=ibKZ2C=lNLKm+Y1fT9`nT=~+dvtqLW?wF3jqM&#GxccAwr${ zR>mWa`Loeu=%i-KU`lK(5m8(3>@yg62JPwiC)-(2VO30Cjz8ToO(ph_1Pv=DIn!{T z5^g=J@Cf-U>2uV7NS+}fAchsoS4sD#KcJ42|3?ObfR?OW8J0THf>Sa!8y?H6Hvc4T zr+8~@o8ntLXCdU=kQoDvMKF8b{E&yo$_Ei;1o%I__YeDz<|cA!^P;)(k1FjJPBtjd z;UxE>^1`jkoTW2WpA>FZPLep#iBspTJP`}NZ7{I*d}AxFZ|0}PujlIbBuC_}ctBmS z{*j0oq($n|PwjeE{NYE&q`Xfp(-Ss|-dZ(AN%|b>1ZIBb#P3OK(RxhmH zRcX3+;X={O2rJ6p`-0__ixEZu^(^-mwHu!>{m;7w0070=aJvECsb#DfB5 zU!1QtJXv(X`ox;ul9FHGaM!NF7yxQ&*6Ct02EUngWpaHE5-0*phVd8ol}H3Ac#01f z?~Gb(dWXe6f3e*`WC2wVyLmhlF!M5}{aYLZcL#kRs^ZKTh$)cn%dGskQ`~ zgIw^K-3=}UdGg{Nq}_oA0Z{U~^@@_8j}^UlGT&ZsHNphM|FG{G2mx@Ov%9-!vhNfa zv$DfSZU=#r9 zbUGacSGms#$^(cn^d)&-&r$$x=T}$LP)WJ?8SQx5Q zS80(d)TOi*M^~aax@}i>)mm}T`al_!TGmmdmcl5OwYW1|-MY2A+xnow6i9d^Az$*n z?*0LhR}yfvL!8O)pKo&R{q8yUJNKM>?wue)NCSBBXlMZd*aZD>+u_9pLb)C=8Ez}Q zxJ4oWc({%5GB{o*Jpy2_mpmV@k31a&fRVRy@OYd?5-Hc~fXG9Zd--K?neNEBtva`I z;vxiH$$x1C0q@U$JFKm6W_TdqLVMhJ4=_Fr$aNzr*Xz){+(tmiiF|V-5P<$|T?X)I z?u@7WGv`lJOc@u38L0!ltSl2UKDpjuV8ey`o{%V_oDJzAdCzNU001IOVCrZh6&0uW zbw&R%wX$LNKjtIEpodvz9eaBrsDGUsSh}&=QE_qk#fCrNA;IGQXK_yTKX2lto*;X ztUK{fV|>OQ;{^jR>mp+CDBMn~l^Wlhr5m(gtzkkak;8}==@YxN!W(zTga`A@ZbIJ- z`n`uO%RjDeiA(>Bp|Y8mM@P-X5wwvR&{YyqeB8u#F9dq0BvD8b!2 zs{cMjF@$4+#2x`c426)Tt)4W?zOvbBw7#1E6*nn9iu3R2G+5%%KdNi2 zH~A6djo*y+L6V3-6mjD02~6kDSLDi;5W8a-Rq%9tBsbo#zV5R4ZM%wO=j`y=H1Veq zK!|%Cq8))C;B9&9f)1^TS3=`exv;d7ziRX&p^S~{ZK@xo#P4RU416aRQLm-FXFA?A z&H|{%H4kM&BB!#+QD}gdIFa8>mq@A!-D5q4=!5oemU1k}&{)#NQ?h zGWWDyL*wjh#cjpali7hONzW^{Z@g_5X{GF1M;XPb#xu*G38w#hr9h0;-!brvO72?F zV*x#@u zmSZYwjqJSFhh?RYKDofHeKtwWa5qW*mo_V4ClS#H9%`#E33u!iaP4>H;__PCrM4g| zp&0_Q(APydQ3XNgg zQ1>og>CHpqTNlc3E1ns3)gwdQbp z?>-7Y9nvwK6aWCtsHo9?G-@|C5dks8y$%AM9qp1;BJisT6DUUHx+YHu^ge4^+rA}v z1ywfH_$9bHCn8YcqzD?)p5)XK;3R?^@B;pLSGFc`{0Pd>%*n4VPV_Cxcsb;Jkl~GH*`%vsybY|CD&9=Eu23G7!(?qg7DlVa2*UI zZ_V3le0^V)jTto+znMITeKwrK20_`!4hbYuS9`HzY2i1vxhZw?aPRui7cHeEI_LWqp7HajdoSBr zJz(PEo8C)tgg|dcxRO6|5E)dGNii!nM!jG(g$^98<~+?o4xCnZeXfFfMTWC0qP{Oa zLQy0Wv@kVIeIOx>IbD*^@BD701qL25haH4mq&qL3gRNW-*!xcu&j-7^1^40^V9Dzw zkA?sM9{e`b%W#9ef#lf`2>=m78YBSd9Z`}9z~G*WT6W<{4A2#iz1rn&xzi`<8q4t< zx~1Junq71U=>9jTGu@5?%AH*002ovPDHLkV1lYr9QptN literal 0 HcmV?d00001 diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 12f9a814..50b36914 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -104,6 +104,10 @@ public enum GameImage { } }, + REPLAY_05XPLAYBACK ("playback-05x", "png"), + REPLAY_1XPLAYBACK ("playback-1x", "png"), + REPLAY_2XPLAYBACK ("playback-2x", "png"), + // Circle HITCIRCLE ("hitcircle", "png"), HITCIRCLE_OVERLAY ("hitcircleoverlay", "png"), diff --git a/src/itdelatrisu/opsu/MenuButton.java b/src/itdelatrisu/opsu/MenuButton.java index de04a0e3..8631a90b 100644 --- a/src/itdelatrisu/opsu/MenuButton.java +++ b/src/itdelatrisu/opsu/MenuButton.java @@ -279,6 +279,11 @@ public class MenuButton { */ public void removeHoverEffects() { hoverEffect = 0; } + /** + * Sets the image of the button. + */ + public void setImage(Image image) { img = image; } + /** * Sets the "expand" hover effect. */ diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index 0050785d..8fc58c99 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -279,13 +279,13 @@ public class MusicController { * Plays the current track. * @param loop whether or not to loop the track */ - public static void play(float pitch, boolean loop) { + public static void play(boolean loop) { if (trackExists()) { trackEnded = false; if (loop) player.loop(); else - player.play(pitch, 1f); + player.play(); } } @@ -297,6 +297,14 @@ public class MusicController { SoundStore.get().setMusicVolume((isTrackDimmed()) ? volume * dimLevel : volume); } + /** + * Sets the music pitch. + * @param pitch [0, ..] + */ + public static void setPitch(float pitch) { + SoundStore.get().setMusicPitch(pitch); + } + /** * Returns whether or not the current track has ended. */ diff --git a/src/itdelatrisu/opsu/replay/PlaybackSpeed.java b/src/itdelatrisu/opsu/replay/PlaybackSpeed.java new file mode 100644 index 00000000..7d69efbd --- /dev/null +++ b/src/itdelatrisu/opsu/replay/PlaybackSpeed.java @@ -0,0 +1,50 @@ +package itdelatrisu.opsu.replay; + +import itdelatrisu.opsu.GameImage; +import itdelatrisu.opsu.GameMod; +import org.newdawn.slick.Image; + +public enum PlaybackSpeed { + NORMAL(GameImage.REPLAY_1XPLAYBACK, 1f), + DOUBLE(GameImage.REPLAY_2XPLAYBACK, 2f), + HALF(GameImage.REPLAY_05XPLAYBACK, 0.5f); + + /** The file name of the button image. */ + private GameImage gameImage; + + /** The speed modifier of the playback. */ + private float modifier; + + PlaybackSpeed(GameImage gameImage, float modifier) { + this.gameImage = gameImage; + this.modifier = modifier; + } + + private static int index = 1; + + public static PlaybackSpeed next() { + PlaybackSpeed next = values()[index++ % values().length]; + if((GameMod.DOUBLE_TIME.isActive() && next == PlaybackSpeed.DOUBLE) || + (GameMod.HALF_TIME.isActive() && next == PlaybackSpeed.HALF)) + next = next(); + + return next; + } + + public static void reset() { + index = 1; + } + + /** + * Returns the image. + * @return the associated image + */ + public Image getImage() { return gameImage.getImage(); } + + /** + * Returns the speed modifier. + * @return the speed + */ + public float getModifier() { return modifier; } +} + diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 28204fb3..c8348a8a 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -50,6 +50,7 @@ import java.io.File; import java.util.LinkedList; import java.util.Stack; +import itdelatrisu.opsu.replay.PlaybackSpeed; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.Display; import org.newdawn.slick.Animation; @@ -131,6 +132,9 @@ public class Game extends BasicGameState { /** Skip button (displayed at song start, when necessary). */ private MenuButton skipButton; + /** Playback button (displayed in replays). */ + private MenuButton playbackButton; + /** Current timing point index in timingPoints ArrayList. */ private int timingPointIndex; @@ -527,6 +531,9 @@ public class Game extends BasicGameState { cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY); } + if (isReplay || GameMod.AUTO.isActive()) + playbackButton.draw(); + if (isReplay) UI.draw(g, replayX, replayY, replayKeyPressed); else if (GameMod.AUTO.isActive()) @@ -544,6 +551,8 @@ public class Game extends BasicGameState { UI.update(delta); int mouseX = input.getMouseX(), mouseY = input.getMouseY(); skipButton.hoverUpdate(delta, mouseX, mouseY); + if (isReplay || GameMod.AUTO.isActive()) + playbackButton.hoverUpdate(delta, mouseX, mouseY); int trackPosition = MusicController.getPosition(); // returning from pause screen: must click previous mouse position @@ -871,17 +880,25 @@ public class Game extends BasicGameState { @Override public void mousePressed(int button, int x, int y) { - if (Options.isMouseDisabled()) - return; - // watching replay - if (isReplay) { - // only allow skip button - if (button != Input.MOUSE_MIDDLE_BUTTON && skipButton.contains(x, y)) + if (isReplay || GameMod.AUTO.isActive()) { + // allow skip button + if (button != Input.MOUSE_MIDDLE_BUTTON && skipButton.contains(x, y)) { skipIntro(); + return; + } + if (button != Input.MOUSE_MIDDLE_BUTTON && playbackButton.contains(x, y)) { + PlaybackSpeed playbackSpeed = PlaybackSpeed.next(); + playbackButton.setImage(playbackSpeed.getImage()); + MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier()); + return; + } return; } + if (Options.isMouseDisabled()) + return; + // mouse wheel: pause the game if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) { int trackPosition = MusicController.getPosition(); @@ -1085,6 +1102,8 @@ public class Game extends BasicGameState { previousMods = GameMod.getModState(); GameMod.loadModState(replay.mods); + PlaybackSpeed.reset(); + // load initial data replayX = container.getWidth() / 2; replayY = container.getHeight() / 2; @@ -1116,12 +1135,15 @@ public class Game extends BasicGameState { restart = Restart.FALSE; // needs to play before setting position to resume without lag later - MusicController.play(GameMod.getSpeedMultiplier(), false); + MusicController.play(false); MusicController.setPosition(0); + MusicController.setPitch(GameMod.getSpeedMultiplier()); MusicController.pause(); } skipButton.resetHover(); + if (isReplay || GameMod.AUTO.isActive()) + playbackButton.resetHover(); } @Override @@ -1280,6 +1302,7 @@ public class Game extends BasicGameState { MusicController.resume(); } MusicController.setPosition(firstObjectTime - SKIP_OFFSET); + MusicController.setPitch(GameMod.getSpeedMultiplier()); replaySkipTime = (isReplay) ? -1 : trackPosition; if (isReplay) { replayX = (int) skipButton.getX(); @@ -1317,6 +1340,12 @@ public class Game extends BasicGameState { } skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT); + if (isReplay || GameMod.AUTO.isActive()) { + Image playback = GameImage.REPLAY_1XPLAYBACK.getImage(); + playbackButton = new MenuButton(playback, width * 0.98f - (playback.getWidth() / 2f), height * 0.25f); + playbackButton.setHoverExpand(1.1f, MenuButton.Expand.CENTER); + } + // load other images... ((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages(); data.loadImages(); From f810965921e3ca6582de1350a599ef883e35f246 Mon Sep 17 00:00:00 2001 From: Pavel Kolchev Date: Fri, 3 Apr 2015 15:01:18 +0300 Subject: [PATCH 3/3] DT/HF/Playback changes. Can watch HalfTime on half speed. Reset pitch on leaving the game state. Load songInfo when entering select song menu. Playback button fades in on hover instead of expands. Reverted spinner changes. It should be fixed separately. --- src/itdelatrisu/opsu/GameMod.java | 14 ----------- src/itdelatrisu/opsu/MenuButton.java | 5 ---- src/itdelatrisu/opsu/OsuGroupNode.java | 7 +++--- src/itdelatrisu/opsu/Utils.java | 4 +++ src/itdelatrisu/opsu/objects/Spinner.java | 2 +- .../opsu/replay/PlaybackSpeed.java | 22 ++++++++++++---- src/itdelatrisu/opsu/states/Game.java | 12 ++++----- src/itdelatrisu/opsu/states/SongMenu.java | 25 ++++++++++++++----- 8 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java index d1a7052b..d5e09a5f 100644 --- a/src/itdelatrisu/opsu/GameMod.java +++ b/src/itdelatrisu/opsu/GameMod.java @@ -170,8 +170,6 @@ public enum GameMod { Collections.reverse(Arrays.asList(VALUES_REVERSED)); } - private static boolean justChanged = false; - /** The last calculated score multiplier, or -1f if it must be recalculated. */ private static float scoreMultiplier = -1f; @@ -236,17 +234,6 @@ public enum GameMod { return speedMultiplier; } - /** - * - */ - public static boolean justChanged() { - if (justChanged) { - justChanged = false; - return true; - } - return false; - } - /** * Returns the current game mod state (bitwise OR of active mods). */ @@ -385,7 +372,6 @@ public enum GameMod { active = !active; scoreMultiplier = speedMultiplier = -1f; - justChanged = true; if (checkInverse) { if (AUTO.isActive()) { diff --git a/src/itdelatrisu/opsu/MenuButton.java b/src/itdelatrisu/opsu/MenuButton.java index 8631a90b..de04a0e3 100644 --- a/src/itdelatrisu/opsu/MenuButton.java +++ b/src/itdelatrisu/opsu/MenuButton.java @@ -279,11 +279,6 @@ public class MenuButton { */ public void removeHoverEffects() { hoverEffect = 0; } - /** - * Sets the image of the button. - */ - public void setImage(Image image) { img = image; } - /** * Sets the "expand" hover effect. */ diff --git a/src/itdelatrisu/opsu/OsuGroupNode.java b/src/itdelatrisu/opsu/OsuGroupNode.java index db095130..b51eab5b 100644 --- a/src/itdelatrisu/opsu/OsuGroupNode.java +++ b/src/itdelatrisu/opsu/OsuGroupNode.java @@ -118,9 +118,10 @@ public class OsuGroupNode { return null; OsuFile osu = osuFiles.get(osuFileIndex); - long endTime = (long) (osu.endTime / GameMod.getSpeedMultiplier()); - int bpmMin = (int) (osu.bpmMin * GameMod.getSpeedMultiplier()); - int bpmMax = (int) (osu.bpmMax * GameMod.getSpeedMultiplier()); + float speedModifier = GameMod.getSpeedMultiplier(); + long endTime = (long) (osu.endTime / speedModifier); + int bpmMin = (int) (osu.bpmMin * speedModifier); + int bpmMax = (int) (osu.bpmMax * speedModifier); String[] info = new String[5]; info[0] = osu.toString(); info[1] = String.format("Mapped by %s", diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index 61baf19a..33f1f42a 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -49,6 +49,7 @@ import java.util.Scanner; import javax.imageio.ImageIO; +import itdelatrisu.opsu.replay.PlaybackSpeed; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; @@ -180,6 +181,9 @@ public class Utils { // initialize game mods GameMod.init(width, height); + // initialize playback buttons + PlaybackSpeed.init(width, height); + // initialize hit objects OsuHitObject.init(width, height); diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 89c9ca9d..1f5033d5 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -135,7 +135,7 @@ public class Spinner implements HitObject { Utils.COLOR_BLACK_ALPHA.a = oldAlpha; // rpm - int rpm = Math.abs(Math.round(sumVelocity * GameMod.getSpeedMultiplier() / storedVelocities.length * 60)); + int rpm = Math.abs(Math.round(sumVelocity / storedVelocities.length * 60)); Image rpmImg = GameImage.SPINNER_RPM.getImage(); rpmImg.setAlpha(alpha); rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f); diff --git a/src/itdelatrisu/opsu/replay/PlaybackSpeed.java b/src/itdelatrisu/opsu/replay/PlaybackSpeed.java index 7d69efbd..e8248a9e 100644 --- a/src/itdelatrisu/opsu/replay/PlaybackSpeed.java +++ b/src/itdelatrisu/opsu/replay/PlaybackSpeed.java @@ -2,6 +2,7 @@ package itdelatrisu.opsu.replay; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameMod; +import itdelatrisu.opsu.MenuButton; import org.newdawn.slick.Image; public enum PlaybackSpeed { @@ -12,6 +13,9 @@ public enum PlaybackSpeed { /** The file name of the button image. */ private GameImage gameImage; + /** The button of the playback. */ + private MenuButton button; + /** The speed modifier of the playback. */ private float modifier; @@ -20,12 +24,20 @@ public enum PlaybackSpeed { this.modifier = modifier; } + public static void init(int width, int height) { + // create buttons + for (PlaybackSpeed playback : PlaybackSpeed.values()) { + Image img = playback.gameImage.getImage(); + playback.button = new MenuButton(img, width * 0.98f - (img.getWidth() / 2f), height * 0.25f); + playback.button.setHoverFade(); + } + } + private static int index = 1; public static PlaybackSpeed next() { PlaybackSpeed next = values()[index++ % values().length]; - if((GameMod.DOUBLE_TIME.isActive() && next == PlaybackSpeed.DOUBLE) || - (GameMod.HALF_TIME.isActive() && next == PlaybackSpeed.HALF)) + if((GameMod.DOUBLE_TIME.isActive() && next == PlaybackSpeed.DOUBLE)) next = next(); return next; @@ -36,10 +48,10 @@ public enum PlaybackSpeed { } /** - * Returns the image. - * @return the associated image + * Returns the button. + * @return the associated button */ - public Image getImage() { return gameImage.getImage(); } + public MenuButton getButton() { return button; } /** * Returns the speed modifier. diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index c8348a8a..57156c58 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -889,7 +889,7 @@ public class Game extends BasicGameState { } if (button != Input.MOUSE_MIDDLE_BUTTON && playbackButton.contains(x, y)) { PlaybackSpeed playbackSpeed = PlaybackSpeed.next(); - playbackButton.setImage(playbackSpeed.getImage()); + playbackButton = playbackSpeed.getButton(); MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier()); return; } @@ -1158,6 +1158,9 @@ public class Game extends BasicGameState { // replays if (isReplay) GameMod.loadModState(previousMods); + + // reset playback speed + MusicController.setPitch(1f); } /** @@ -1340,11 +1343,8 @@ public class Game extends BasicGameState { } skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT); - if (isReplay || GameMod.AUTO.isActive()) { - Image playback = GameImage.REPLAY_1XPLAYBACK.getImage(); - playbackButton = new MenuButton(playback, width * 0.98f - (playback.getWidth() / 2f), height * 0.25f); - playbackButton.setHoverExpand(1.1f, MenuButton.Expand.CENTER); - } + if (isReplay || GameMod.AUTO.isActive()) + playbackButton = PlaybackSpeed.NORMAL.getButton(); // load other images... ((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages(); diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 30f2153f..ed2cace2 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -336,12 +336,8 @@ public class SongMenu extends BasicGameState { int iconWidth = musicNote.getWidth(); // song info text - if (songInfo == null || GameMod.justChanged()) { - songInfo = focusNode.getInfo(); - if (Options.useUnicodeMetadata()) { // load glyphs - OsuFile osu = focusNode.osuFiles.get(0); - Utils.loadGlyphs(Utils.FONT_LARGE, osu.titleUnicode, osu.artistUnicode); - } + if (songInfo == null) { + songInfo = getSongInfo(); } marginX += 5; float headerTextY = marginY; @@ -983,6 +979,9 @@ public class SongMenu extends BasicGameState { resetGame = false; } + // load song info + songInfo = getSongInfo(); + // state-based action if (stateAction != null) { switch (stateAction) { @@ -1303,6 +1302,20 @@ public class SongMenu extends BasicGameState { return null; // incorrect map } + /** + * Returns an array of strings containing song information. + * @return the String array + */ + private String[] getSongInfo () { + songInfo = focusNode.getInfo(); + if (Options.useUnicodeMetadata()) { // load glyphs + OsuFile osu = focusNode.osuFiles.get(0); + Utils.loadGlyphs(Utils.FONT_LARGE, osu.titleUnicode, osu.artistUnicode); + } + return songInfo; + } + + /** * Starts the game. */