Added initial sound effect support.

- Added SoundController module, which uses Java Sound since OpenAL has a slight delay on playing sounds.
- Uploaded all effect WAVs. (credits: WWWskin, AL's IA, Fantasy's Skin, Minimalist Miku)
- Added a missing entry in credits.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-01 01:14:03 -04:00
parent 60eaa42997
commit 0604a25822
54 changed files with 500 additions and 61 deletions

View File

@ -23,4 +23,5 @@ Projects
The following projects were referenced in creating opsu!: The following projects were referenced in creating opsu!:
* "Wojtkosu" - Wojtek Kowaluk (https://osu.ppy.sh/forum/t/97260) * "Wojtkosu" - Wojtek Kowaluk (https://osu.ppy.sh/forum/t/97260)
* "osu-parser" - nojhamster (https://github.com/nojhamster/osu-parser)
* "osu! web" - pictuga (https://github.com/pictuga/osu-web) * "osu! web" - pictuga (https://github.com/pictuga/osu-web)

BIN
res/applause.wav Normal file

Binary file not shown.

BIN
res/combobreak.wav Normal file

Binary file not shown.

BIN
res/count1s.wav Normal file

Binary file not shown.

BIN
res/count2s.wav Normal file

Binary file not shown.

BIN
res/count3s.wav Normal file

Binary file not shown.

BIN
res/drum-hitclap.wav Normal file

Binary file not shown.

BIN
res/drum-hitfinish.wav Normal file

Binary file not shown.

BIN
res/drum-hitnormal.wav Normal file

Binary file not shown.

BIN
res/drum-hitwhistle.wav Normal file

Binary file not shown.

BIN
res/drum-sliderslide.wav Normal file

Binary file not shown.

BIN
res/drum-slidertick.wav Normal file

Binary file not shown.

BIN
res/drum-sliderwhistle.wav Normal file

Binary file not shown.

BIN
res/failsound.wav Normal file

Binary file not shown.

BIN
res/gos.wav Normal file

Binary file not shown.

BIN
res/menuback.wav Normal file

Binary file not shown.

BIN
res/menuclick.wav Normal file

Binary file not shown.

BIN
res/menuhit.wav Normal file

Binary file not shown.

BIN
res/normal-hitclap.wav Normal file

Binary file not shown.

BIN
res/normal-hitfinish.wav Normal file

Binary file not shown.

BIN
res/normal-hitnormal.wav Normal file

Binary file not shown.

BIN
res/normal-hitwhistle.wav Normal file

Binary file not shown.

BIN
res/normal-sliderslide.wav Normal file

Binary file not shown.

BIN
res/normal-slidertick.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
res/readys.wav Normal file

Binary file not shown.

BIN
res/sectionfail.wav Normal file

Binary file not shown.

BIN
res/sectionpass.wav Normal file

Binary file not shown.

BIN
res/shutter.wav Normal file

Binary file not shown.

BIN
res/soft-hitclap.wav Normal file

Binary file not shown.

BIN
res/soft-hitfinish.wav Normal file

Binary file not shown.

BIN
res/soft-hitnormal.wav Normal file

Binary file not shown.

BIN
res/soft-hitwhistle.wav Normal file

Binary file not shown.

BIN
res/soft-sliderslide.wav Normal file

Binary file not shown.

BIN
res/soft-slidertick.wav Normal file

Binary file not shown.

BIN
res/soft-sliderwhistle.wav Normal file

Binary file not shown.

BIN
res/spinner-osu.wav Normal file

Binary file not shown.

BIN
res/spinnerbonus.wav Normal file

Binary file not shown.

BIN
res/spinnerspin.wav Normal file

Binary file not shown.

View File

@ -717,29 +717,41 @@ public class GameScore {
} }
} }
/**
* Resets the combo streak to zero.
*/
private void resetComboStreak() {
if (combo >= 20)
SoundController.playSound(SoundController.SOUND_COMBOBREAK);
combo = 0;
if (Options.isModActive(Options.MOD_SUDDEN_DEATH))
health = 0f;
}
/** /**
* Handles a slider tick result. * Handles a slider tick result.
* @param time the tick start time * @param time the tick start time
* @param result the hit result (HIT_* constants) * @param result the hit result (HIT_* constants)
* @param x the x coordinate * @param x the x coordinate
* @param y the y coordinate * @param y the y coordinate
* @param hitSound the object's hit sound
*/ */
public void sliderTickResult(int time, int result, float x, float y) { public void sliderTickResult(int time, int result, float x, float y, byte hitSound) {
int hitValue = 0; int hitValue = 0;
switch (result) { switch (result) {
case HIT_SLIDER30: case HIT_SLIDER30:
hitValue = 30; hitValue = 30;
incrementComboStreak(); incrementComboStreak();
changeHealth(1f); changeHealth(1f);
SoundController.playHitSound(hitSound);
break; break;
case HIT_SLIDER10: case HIT_SLIDER10:
hitValue = 10; hitValue = 10;
incrementComboStreak(); incrementComboStreak();
SoundController.playHitSound(SoundController.HIT_SLIDERTICK);
break; break;
case HIT_MISS: case HIT_MISS:
combo = 0; resetComboStreak();
if (Options.isModActive(Options.MOD_SUDDEN_DEATH))
health = 0f;
break; break;
default: default:
return; return;
@ -760,8 +772,10 @@ public class GameScore {
* @param y the y coordinate * @param y the y coordinate
* @param color the combo color * @param color the combo color
* @param end true if this is the last hit object in the combo * @param end true if this is the last hit object in the combo
* @param hitSound the object's hit sound
*/ */
public void hitResult(int time, int result, float x, float y, Color color, boolean end) { public void hitResult(int time, int result, float x, float y, Color color,
boolean end, byte hitSound) {
int hitValue = 0; int hitValue = 0;
switch (result) { switch (result) {
case HIT_300: case HIT_300:
@ -784,15 +798,15 @@ public class GameScore {
hitValue = 0; hitValue = 0;
changeHealth(-10f); changeHealth(-10f);
comboEnd |= 2; comboEnd |= 2;
combo = 0; resetComboStreak();
if (Options.isModActive(Options.MOD_SUDDEN_DEATH))
health = 0f;
objectCount++; objectCount++;
break; break;
default: default:
return; return;
} }
if (hitValue > 0) { if (hitValue > 0) {
SoundController.playHitSound(hitSound);
// game mod score multipliers // game mod score multipliers
float modMultiplier = 1f; float modMultiplier = 1f;
if (Options.isModActive(Options.MOD_NO_FAIL)) if (Options.isModActive(Options.MOD_NO_FAIL))

View File

@ -143,6 +143,9 @@ public class Opsu extends StateBasedGame {
} }
Options.TMP_DIR.deleteOnExit(); Options.TMP_DIR.deleteOnExit();
// load sounds
SoundController.init();
app.start(); app.start();
} catch (SlickException e) { } catch (SlickException e) {
Log.error("Error while creating game container.", e); Log.error("Error while creating game container.", e);

View File

@ -40,7 +40,7 @@ public class OsuFile implements Comparable<OsuFile> {
// public String audioHash = ""; // audio hash (deprecated) // public String audioHash = ""; // audio hash (deprecated)
public int previewTime = -1; // start position of music preview (in ms) public int previewTime = -1; // start position of music preview (in ms)
public byte countdown = 0; // countdown type (0:disabled, 1:normal, 2:half, 3:double) public byte countdown = 0; // countdown type (0:disabled, 1:normal, 2:half, 3:double)
public String sampleSet = ""; // ? ("Normal", "Soft") public String sampleSet = ""; // sound samples ("None", "Normal", "Soft")
public float stackLeniency = 0.7f; // how often closely placed hit objects will be stacked together public float stackLeniency = 0.7f; // how often closely placed hit objects will be stacked together
public byte mode = 0; // game mode (0:osu!, 1:taiko, 2:catch the beat, 3:osu!mania) public byte mode = 0; // game mode (0:osu!, 1:taiko, 2:catch the beat, 3:osu!mania)
public boolean letterboxInBreaks = false; // whether the letterbox (top/bottom black bars) appears during breaks public boolean letterboxInBreaks = false; // whether the letterbox (top/bottom black bars) appears during breaks

View File

@ -38,7 +38,6 @@ public class OsuHitObject {
SOUND_NORMAL = 0, SOUND_NORMAL = 0,
SOUND_WHISTLE = 2, SOUND_WHISTLE = 2,
SOUND_FINISH = 4, SOUND_FINISH = 4,
SOUND_WHISTLEFINISH = 6,
SOUND_CLAP = 8; SOUND_CLAP = 8;
/** /**

View File

@ -26,8 +26,8 @@ public class OsuTimingPoint {
public float beatLength; // (non-inherited) ms per beat public float beatLength; // (non-inherited) ms per beat
public int velocity = 0; // (inherited) slider multiplier = -100 / value public int velocity = 0; // (inherited) slider multiplier = -100 / value
public int meter; // beats per measure public int meter; // beats per measure
public byte sampleType; // sound samples (0:none, 1:normal, 2:soft) public byte sampleType; // sound samples (0:none, 1:normal, 2:soft, 3:drum)
public byte sampleTypeCustom; // custom samples (0:default, 1:custom1, 2:custom2 public byte sampleTypeCustom; // custom samples (0:default, 1:custom1, 2:custom2)
public int sampleVolume; // volume of samples (0~100) public int sampleVolume; // volume of samples (0~100)
public boolean inherited; // is this timing point inherited? public boolean inherited; // is this timing point inherited?
public boolean kiai; // is Kiai Mode active? public boolean kiai; // is Kiai Mode active?

View File

@ -0,0 +1,285 @@
/*
* opsu! - an open-source osu! client
* Copyright (C) 2014 Jeffrey Han
*
* opsu! is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu! is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu;
import itdelatrisu.opsu.states.Options;
import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
/**
* Controller for all sound effects.
* Note: Uses Java Sound because OpenAL lags too much for accurate hit sounds.
*/
public class SoundController {
/**
* Sound effect constants.
*/
public static final int
SOUND_APPLAUSE = 0,
SOUND_COMBOBREAK = 1,
// SOUND_COUNT = , // ?
SOUND_COUNT1 = 2,
SOUND_COUNT2 = 3,
SOUND_COUNT3 = 4,
SOUND_FAIL = 5,
SOUND_GO = 6,
SOUND_MENUBACK = 7,
SOUND_MENUCLICK = 8,
SOUND_MENUHIT = 9,
SOUND_READY = 10,
SOUND_SECTIONFAIL = 11,
SOUND_SECTIONPASS = 12,
SOUND_SHUTTER = 13,
SOUND_SPINNERBONUS = 14,
SOUND_SPINNEROSU = 15,
SOUND_SPINNERSPIN = 16,
SOUND_MAX = 17; // not a sound
/**
* Sound effect names (indexed by SOUND_* constants).
*/
private static final String[] soundNames = {
"applause",
"combobreak",
// "count", // ?
"count1s",
"count2s",
"count3s",
"failsound",
"gos",
"menuback",
"menuclick",
"menuhit",
"readys",
"sectionfail",
"sectionpass",
"shutter",
"spinnerbonus",
"spinner-osu",
"spinnerspin",
};
/**
* Sound effects (indexed by SOUND_* constants).
*/
private static Clip[] sounds = new Clip[SOUND_MAX];
/**
* Sound sample sets.
*/
private static final String[] sampleSets = {
"normal",
"soft",
"drum",
// "taiko"
};
/**
* Current sample set (index in sampleSet[] array).
*/
private static int sampleSetIndex = -1;
/**
* Hit sound effects.
*/
public static final int
HIT_CLAP = 0,
HIT_FINISH = 1,
HIT_NORMAL = 2,
HIT_WHISTLE = 3,
HIT_SLIDERSLIDE = 4,
HIT_SLIDERTICK = 5,
HIT_SLIDERWHISTLE = 6,
HIT_MAX = 7; // not a sound
/**
* Hit sound effect names (indexed by HIT_* constants).
*/
private static final String[] hitSoundNames = {
"hitclap",
"hitfinish",
"hitnormal",
"hitwhistle",
"sliderslide",
"slidertick",
"sliderwhistle"
};
/**
* Hit sound effects (indexed by sampleSets[], HIT_* constants).
*/
private static Clip[][] hitSounds = new Clip[sampleSets.length][HIT_MAX];
/**
* Sample volume multiplier, from timing points [0, 1].
*/
private static float sampleVolumeMultiplier = 1f;
// This class should not be instantiated.
private SoundController() {}
/**
* Loads and returns a Clip from a resource.
* @param ref the resource name
* @return the loaded and opened clip
*/
private static Clip loadClip(String ref) {
try {
URL url = ResourceLoader.getResource(ref);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
return clip;
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
Log.error(String.format("Failed to load file '%s'.", ref), e);
}
return null;
}
/**
* Loads all sound files.
*/
public static void init() {
// TODO: support MP3 sounds?
// menu and game sounds
for (int i = 0; i < SOUND_MAX; i++)
sounds[i] = loadClip(String.format("%s.wav", soundNames[i]));
// hit sounds
for (int i = 0; i < sampleSets.length; i++) {
for (int j = 0; j < HIT_MAX; j++)
hitSounds[i][j] = loadClip(String.format("%s-%s.wav", sampleSets[i], hitSoundNames[j]));
}
}
/**
* Sets the sample set to use when playing hit sounds.
* @param sampleSet the sample set ("None", "Normal", "Soft", "Drum")
*/
public static void setSampleSet(String sampleSet) {
sampleSetIndex = -1;
for (int i = 0; i < sampleSets.length; i++) {
if (sampleSet.equalsIgnoreCase(sampleSets[i])) {
sampleSetIndex = i;
return;
}
}
}
/**
* Sets the sample set to use when playing hit sounds.
* @param sampleType the sample set (0:none, 1:normal, 2:soft, 3:drum)
*/
public static void setSampleSet(byte sampleType) {
if (sampleType >= 0 && sampleType <= 3)
sampleSetIndex = sampleType - 1;
}
/**
* Sets the sample volume (modifies the global sample volume).
* @param volume the sample volume [0, 100]
*/
public static void setSampleVolume(int volume) {
if (volume >= 0 && volume <= 100)
sampleVolumeMultiplier = volume / 100f;
}
/**
* Plays a sound clip.
* @param clip the Clip to play
* @param volume the volume [0, 1]
*/
private static void playClip(Clip clip, float volume) {
if (volume > 0f) {
// stop clip if running
if (clip.isRunning()) {
clip.stop();
clip.flush();
}
// set volume
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
float dB = (float) (Math.log(volume) / Math.log(10.0) * 20.0);
gainControl.setValue(dB * sampleVolumeMultiplier);
// play clip
clip.setFramePosition(0);
clip.start();
}
}
/**
* Plays a sound.
* @param sound the sound (SOUND_* constant)
*/
public static void playSound(int sound) {
if (sound < 0 || sound >= SOUND_MAX)
return;
playClip(sounds[sound], Options.getEffectVolume());
}
/**
* Plays hit sound(s) using an OsuHitObject bitmask.
* @param hitSound the sound (bitmask)
*/
public static void playHitSound(byte hitSound) {
if (sampleSetIndex < 0 || hitSound < 0)
return;
float volume = Options.getEffectVolume();
if (volume == 0f)
return;
// play all sounds
if (hitSound == OsuHitObject.SOUND_NORMAL)
playClip(hitSounds[sampleSetIndex][HIT_NORMAL], volume);
else {
if ((hitSound & OsuHitObject.SOUND_WHISTLE) > 0)
playClip(hitSounds[sampleSetIndex][HIT_WHISTLE], volume);
if ((hitSound & OsuHitObject.SOUND_FINISH) > 0)
playClip(hitSounds[sampleSetIndex][HIT_FINISH], volume);
if ((hitSound & OsuHitObject.SOUND_CLAP) > 0)
playClip(hitSounds[sampleSetIndex][HIT_CLAP], volume);
}
}
/**
* Plays a hit sound.
* @param sound (HIT_* constant)
*/
public static void playHitSound(int sound) {
if (sampleSetIndex < 0 || sound < 0 || sound > HIT_MAX)
return;
playClip(hitSounds[sampleSetIndex][sound], Options.getEffectVolume());
}
}

View File

@ -172,7 +172,9 @@ public class Circle {
if (distance < circleRadius) { if (distance < circleRadius) {
int result = hitResult(hitObject.time); int result = hitResult(hitObject.time);
if (result > -1) { if (result > -1) {
score.hitResult(hitObject.time, result, hitObject.x, hitObject.y, color, comboEnd); score.hitResult(hitObject.time, result, hitObject.x, hitObject.y,
color, comboEnd, hitObject.hitSound
);
return true; return true;
} }
} }
@ -192,11 +194,11 @@ public class Circle {
if (overlap || trackPosition > hitObject.time + hitResultOffset[GameScore.HIT_50]) { if (overlap || trackPosition > hitObject.time + hitResultOffset[GameScore.HIT_50]) {
if (isAutoMod) // "auto" mod: catch any missed notes due to lag if (isAutoMod) // "auto" mod: catch any missed notes due to lag
score.hitResult(hitObject.time, GameScore.HIT_300, score.hitResult(hitObject.time, GameScore.HIT_300,
hitObject.x, hitObject.y, color, comboEnd); hitObject.x, hitObject.y, color, comboEnd, hitObject.hitSound);
else // no more points can be scored, so send a miss else // no more points can be scored, so send a miss
score.hitResult(hitObject.time, GameScore.HIT_MISS, score.hitResult(hitObject.time, GameScore.HIT_MISS,
hitObject.x, hitObject.y, null, comboEnd); hitObject.x, hitObject.y, null, comboEnd, hitObject.hitSound);
return true; return true;
} }
@ -204,7 +206,7 @@ public class Circle {
else if (isAutoMod) { else if (isAutoMod) {
if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[GameScore.HIT_300]) { if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[GameScore.HIT_300]) {
score.hitResult(hitObject.time, GameScore.HIT_300, score.hitResult(hitObject.time, GameScore.HIT_300,
hitObject.x, hitObject.y, color, comboEnd); hitObject.x, hitObject.y, color, comboEnd, hitObject.hitSound);
return true; return true;
} }
} }

View File

@ -384,10 +384,11 @@ public class Slider {
if (currentRepeats % 2 == 0) // last circle if (currentRepeats % 2 == 0) // last circle
score.hitResult(hitObject.time + (int) sliderTimeTotal, result, score.hitResult(hitObject.time + (int) sliderTimeTotal, result,
hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], color, comboEnd); hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex],
color, comboEnd, hitObject.hitSound);
else // first circle else // first circle
score.hitResult(hitObject.time + (int) sliderTimeTotal, result, score.hitResult(hitObject.time + (int) sliderTimeTotal, result,
hitObject.x, hitObject.y, color, comboEnd); hitObject.x, hitObject.y, color, comboEnd, hitObject.hitSound);
return result; return result;
} }
@ -420,7 +421,8 @@ public class Slider {
if (result > -1) { if (result > -1) {
sliderClicked = true; sliderClicked = true;
score.sliderTickResult(hitObject.time, result, hitObject.x, hitObject.y); score.sliderTickResult(hitObject.time, result,
hitObject.x, hitObject.y, hitObject.hitSound);
return true; return true;
} }
} }
@ -465,9 +467,11 @@ public class Slider {
sliderClicked = true; sliderClicked = true;
if (isAutoMod) { // "auto" mod: catch any missed notes due to lag if (isAutoMod) { // "auto" mod: catch any missed notes due to lag
ticksHit++; ticksHit++;
score.sliderTickResult(hitObject.time, GameScore.HIT_SLIDER30, hitObject.x, hitObject.y); score.sliderTickResult(hitObject.time, GameScore.HIT_SLIDER30,
hitObject.x, hitObject.y, hitObject.hitSound);
} else } else
score.sliderTickResult(hitObject.time, GameScore.HIT_MISS, hitObject.x, hitObject.y); score.sliderTickResult(hitObject.time, GameScore.HIT_MISS,
hitObject.x, hitObject.y, hitObject.hitSound);
} }
// "auto" mod: send a perfect hit result // "auto" mod: send a perfect hit result
@ -475,7 +479,8 @@ public class Slider {
if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[GameScore.HIT_300]) { if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[GameScore.HIT_300]) {
ticksHit++; ticksHit++;
sliderClicked = true; sliderClicked = true;
score.sliderTickResult(hitObject.time, GameScore.HIT_SLIDER30, hitObject.x, hitObject.y); score.sliderTickResult(hitObject.time, GameScore.HIT_SLIDER30,
hitObject.x, hitObject.y, hitObject.hitSound);
} }
} }
} }
@ -540,24 +545,26 @@ public class Slider {
ticksHit++; ticksHit++;
if (currentRepeats % 2 > 0) // last circle if (currentRepeats % 2 > 0) // last circle
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30, score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30,
hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex]); hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex],
hitObject.hitSound);
else // first circle else // first circle
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30, score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30,
c[0], c[1]); c[0], c[1], hitObject.hitSound);
} }
// held during new tick // held during new tick
if (isNewTick) { if (isNewTick) {
ticksHit++; ticksHit++;
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER10, c[0], c[1]); score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER10,
c[0], c[1], (byte) -1);
} }
} else { } else {
followCircleActive = false; followCircleActive = false;
if (isNewRepeat) if (isNewRepeat)
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0); score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, hitObject.hitSound);
if (isNewTick) if (isNewTick)
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0); score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, (byte) -1);
} }
return false; return false;

View File

@ -21,6 +21,7 @@ package itdelatrisu.opsu.objects;
import itdelatrisu.opsu.GameScore; import itdelatrisu.opsu.GameScore;
import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.MusicController;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.SoundController;
import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.states.Options; import itdelatrisu.opsu.states.Options;
@ -163,16 +164,19 @@ public class Spinner {
int result; int result;
float ratio = rotations / rotationsNeeded; float ratio = rotations / rotationsNeeded;
if (ratio >= 1.0f || if (ratio >= 1.0f ||
Options.isModActive(Options.MOD_AUTO) || Options.isModActive(Options.MOD_SPUN_OUT)) Options.isModActive(Options.MOD_AUTO) ||
Options.isModActive(Options.MOD_SPUN_OUT)) {
result = GameScore.HIT_300; result = GameScore.HIT_300;
else if (ratio >= 0.8f) SoundController.playSound(SoundController.SOUND_SPINNEROSU);
} else if (ratio >= 0.8f)
result = GameScore.HIT_100; result = GameScore.HIT_100;
else if (ratio >= 0.5f) else if (ratio >= 0.5f)
result = GameScore.HIT_50; result = GameScore.HIT_50;
else else
result = GameScore.HIT_MISS; result = GameScore.HIT_MISS;
score.hitResult(hitObject.endTime, result, width / 2, height / 2, Color.transparent, true); score.hitResult(hitObject.endTime, result, width / 2, height / 2,
Color.transparent, true, (byte) -1);
return result; return result;
} }
@ -240,10 +244,13 @@ public class Spinner {
// added one whole rotation... // added one whole rotation...
if (Math.floor(newRotations) > rotations) { if (Math.floor(newRotations) > rotations) {
if (newRotations > rotationsNeeded) // extra rotations if (newRotations > rotationsNeeded) { // extra rotations
score.changeScore(1000); score.changeScore(1000);
else SoundController.playSound(SoundController.SOUND_SPINNERBONUS);
} else {
score.changeScore(100); score.changeScore(100);
SoundController.playSound(SoundController.SOUND_SPINNERSPIN);
}
} }
rotations = newRotations; rotations = newRotations;

View File

@ -25,6 +25,7 @@ import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.OsuFile; import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.OsuTimingPoint; import itdelatrisu.opsu.OsuTimingPoint;
import itdelatrisu.opsu.SoundController;
import itdelatrisu.opsu.objects.Circle; import itdelatrisu.opsu.objects.Circle;
import itdelatrisu.opsu.objects.Slider; import itdelatrisu.opsu.objects.Slider;
import itdelatrisu.opsu.objects.Spinner; import itdelatrisu.opsu.objects.Spinner;
@ -134,6 +135,11 @@ public class Game extends BasicGameState {
*/ */
private int breakTime = 0; private int breakTime = 0;
/**
* Whether the break sound has been played.
*/
private boolean breakSound;
/** /**
* Skip button (displayed at song start, when necessary). * Skip button (displayed at song start, when necessary).
*/ */
@ -164,6 +170,13 @@ public class Game extends BasicGameState {
countdown2, // "1" text countdown2, // "1" text
countdownGo; // "GO!" text countdownGo; // "GO!" text
/**
* Whether the countdown sound has been played.
*/
private boolean
countdownReadySound, countdown3Sound, countdown1Sound,
countdown2Sound, countdownGoSound;
/** /**
* Glowing hit circle outline which must be clicked when returning from pause menu. * Glowing hit circle outline which must be clicked when returning from pause menu.
*/ */
@ -276,10 +289,19 @@ public class Game extends BasicGameState {
trackPosition - breakTime > 2000 && trackPosition - breakTime > 2000 &&
trackPosition - breakTime < 5000) { trackPosition - breakTime < 5000) {
// show break start // show break start
if (score.getHealth() >= 50) if (score.getHealth() >= 50) {
breakStartPass.drawCentered(width / 2f, height / 2f); breakStartPass.drawCentered(width / 2f, height / 2f);
else if (!breakSound) {
SoundController.playSound(SoundController.SOUND_SECTIONPASS);
breakSound = true;
}
} else {
breakStartFail.drawCentered(width / 2f, height / 2f); breakStartFail.drawCentered(width / 2f, height / 2f);
if (!breakSound) {
SoundController.playSound(SoundController.SOUND_SECTIONFAIL);
breakSound = true;
}
}
} else if (breakLength >= 4000) { } else if (breakLength >= 4000) {
// show break end (flash twice for 500ms) // show break end (flash twice for 500ms)
int endTimeDiff = endTime - trackPosition; int endTimeDiff = endTime - trackPosition;
@ -326,18 +348,41 @@ public class Game extends BasicGameState {
if (osu.countdown > 0) { // TODO: implement half/double rate settings if (osu.countdown > 0) { // TODO: implement half/double rate settings
int timeDiff = osu.objects[0].time - trackPosition; int timeDiff = osu.objects[0].time - trackPosition;
if (timeDiff >= 500 && timeDiff < 3000) { if (timeDiff >= 500 && timeDiff < 3000) {
if (timeDiff >= 1500) if (timeDiff >= 1500) {
countdownReady.drawCentered(width / 2, height / 2); countdownReady.drawCentered(width / 2, height / 2);
if (!countdownReadySound) {
if (timeDiff < 2000) SoundController.playSound(SoundController.SOUND_READY);
countdownReadySound = true;
}
}
if (timeDiff < 2000) {
countdown3.draw(0, 0); countdown3.draw(0, 0);
if (timeDiff < 1500) if (!countdown3Sound) {
SoundController.playSound(SoundController.SOUND_COUNT3);
countdown3Sound = true;
}
}
if (timeDiff < 1500) {
countdown2.draw(width - countdown2.getWidth(), 0); countdown2.draw(width - countdown2.getWidth(), 0);
if (timeDiff < 1000) if (!countdown2Sound) {
SoundController.playSound(SoundController.SOUND_COUNT2);
countdown2Sound = true;
}
}
if (timeDiff < 1000) {
countdown1.drawCentered(width / 2, height / 2); countdown1.drawCentered(width / 2, height / 2);
if (!countdown1Sound) {
SoundController.playSound(SoundController.SOUND_COUNT1);
countdown1Sound = true;
}
}
} else if (timeDiff >= -500 && timeDiff < 500) { } else if (timeDiff >= -500 && timeDiff < 500) {
countdownGo.setAlpha((timeDiff < 0) ? 1 - (timeDiff / -1000f) : 1); countdownGo.setAlpha((timeDiff < 0) ? 1 - (timeDiff / -1000f) : 1);
countdownGo.drawCentered(width / 2, height / 2); countdownGo.drawCentered(width / 2, height / 2);
if (!countdownGoSound) {
SoundController.playSound(SoundController.SOUND_GO);
countdownGoSound = true;
}
} }
} }
@ -432,6 +477,8 @@ public class Game extends BasicGameState {
beatLengthBase = beatLength = timingPoint.beatLength; beatLengthBase = beatLength = timingPoint.beatLength;
else else
beatLength = beatLengthBase * (timingPoint.velocity / -100f); beatLength = beatLengthBase * (timingPoint.velocity / -100f);
SoundController.setSampleSet(timingPoint.sampleType);
SoundController.setSampleVolume(timingPoint.sampleVolume);
timingPointIndex++; timingPointIndex++;
} }
} }
@ -456,6 +503,7 @@ public class Game extends BasicGameState {
} else if (trackPosition >= breakValue) { } else if (trackPosition >= breakValue) {
// start a break // start a break
breakTime = breakValue; breakTime = breakValue;
breakSound = false;
breakIndex++; breakIndex++;
return; return;
} }
@ -638,23 +686,34 @@ public class Game extends BasicGameState {
} }
} }
// reset indexes // reset data
MusicController.setPosition(0); MusicController.setPosition(0);
MusicController.pause(); MusicController.pause();
score.clear(); score.clear();
objectIndex = 0; objectIndex = 0;
breakIndex = 0; breakIndex = 0;
breakTime = 0; breakTime = 0;
breakSound = false;
timingPointIndex = 0; timingPointIndex = 0;
pauseTime = -1; pauseTime = -1;
pausedMouseX = -1; pausedMouseX = -1;
pausedMouseY = -1; pausedMouseY = -1;
countdownReadySound = false;
countdown3Sound = false;
countdown1Sound = false;
countdown2Sound = false;
countdownGoSound = false;
// load the first timingPoint // load the first timingPoint
if (!osu.timingPoints.isEmpty() && osu.timingPoints.get(0).velocity >= 0) { if (!osu.timingPoints.isEmpty()) {
beatLengthBase = beatLength = osu.timingPoints.get(0).beatLength; OsuTimingPoint timingPoint = osu.timingPoints.get(0);
if (timingPoint.velocity >= 0) {
beatLengthBase = beatLength = timingPoint.beatLength;
SoundController.setSampleSet(timingPoint.sampleType);
SoundController.setSampleVolume(timingPoint.sampleVolume);
timingPointIndex++; timingPointIndex++;
} }
}
leadInTime = osu.audioLeadIn + approachTime; leadInTime = osu.audioLeadIn + approachTime;
restart = RESTART_FALSE; restart = RESTART_FALSE;
@ -675,6 +734,7 @@ public class Game extends BasicGameState {
MusicController.resume(); MusicController.resume();
} }
MusicController.setPosition(osu.objects[0].time - skipOffsetTime); MusicController.setPosition(osu.objects[0].time - skipOffsetTime);
SoundController.playSound(SoundController.SOUND_MENUHIT);
return true; return true;
} }
return false; return false;

View File

@ -21,6 +21,7 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GUIMenuButton; import itdelatrisu.opsu.GUIMenuButton;
import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.MusicController;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.SoundController;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer; import org.newdawn.slick.GameContainer;
@ -142,6 +143,7 @@ public class GamePauseMenu extends BasicGameState {
if (Game.getRestart() == Game.RESTART_LOSE) { if (Game.getRestart() == Game.RESTART_LOSE) {
MusicController.stop(); MusicController.stop();
MusicController.playAt(Game.getOsuFile().previewTime, true); MusicController.playAt(Game.getOsuFile().previewTime, true);
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
} else } else
unPause(Game.RESTART_FALSE); unPause(Game.RESTART_FALSE);
@ -171,6 +173,7 @@ public class GamePauseMenu extends BasicGameState {
} else if (backButton.contains(x, y)) { } else if (backButton.contains(x, y)) {
MusicController.pause(); // lose state MusicController.pause(); // lose state
MusicController.playAt(Game.getOsuFile().previewTime, true); MusicController.playAt(Game.getOsuFile().previewTime, true);
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
} }
} }
@ -179,9 +182,10 @@ public class GamePauseMenu extends BasicGameState {
public void enter(GameContainer container, StateBasedGame game) public void enter(GameContainer container, StateBasedGame game)
throws SlickException { throws SlickException {
pauseStartTime = System.currentTimeMillis(); pauseStartTime = System.currentTimeMillis();
if (Game.getRestart() == Game.RESTART_LOSE) if (Game.getRestart() == Game.RESTART_LOSE) {
MusicController.fadeOut(FADEOUT_TIME); MusicController.fadeOut(FADEOUT_TIME);
else SoundController.playSound(SoundController.SOUND_FAIL);
} else
MusicController.pause(); MusicController.pause();
} }
@ -189,6 +193,10 @@ public class GamePauseMenu extends BasicGameState {
* Unpause and return to the Game state. * Unpause and return to the Game state.
*/ */
private void unPause(byte restart) { private void unPause(byte restart) {
if (restart == Game.RESTART_MANUAL)
SoundController.playSound(SoundController.SOUND_MENUHIT);
else
SoundController.playSound(SoundController.SOUND_MENUBACK);
Game.setRestart(restart); Game.setRestart(restart);
game.enterState(Opsu.STATE_GAME); game.enterState(Opsu.STATE_GAME);
} }

View File

@ -23,6 +23,7 @@ import itdelatrisu.opsu.GameScore;
import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.MusicController;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.OsuFile; import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.SoundController;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
@ -143,7 +144,9 @@ public class GameRanking extends BasicGameState {
public void keyPressed(int key, char c) { public void keyPressed(int key, char c) {
switch (key) { switch (key) {
case Input.KEY_ESCAPE: case Input.KEY_ESCAPE:
MusicController.pause();
MusicController.playAt(Game.getOsuFile().previewTime, true); MusicController.playAt(Game.getOsuFile().previewTime, true);
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
break; break;
case Input.KEY_F12: case Input.KEY_F12:
@ -162,12 +165,15 @@ public class GameRanking extends BasicGameState {
OsuFile osu = Game.getOsuFile(); OsuFile osu = Game.getOsuFile();
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString())); Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
Game.setRestart(Game.RESTART_MANUAL); Game.setRestart(Game.RESTART_MANUAL);
SoundController.playSound(SoundController.SOUND_MENUHIT);
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
} else if (exitButton.contains(x, y)) } else if (exitButton.contains(x, y)) {
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
else if (Options.getBackButton().contains(x, y)) { } else if (Options.getBackButton().contains(x, y)) {
MusicController.stop(); MusicController.pause();
MusicController.playAt(Game.getOsuFile().previewTime, true); MusicController.playAt(Game.getOsuFile().previewTime, true);
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
} }
} }
@ -176,5 +182,6 @@ public class GameRanking extends BasicGameState {
public void enter(GameContainer container, StateBasedGame game) public void enter(GameContainer container, StateBasedGame game)
throws SlickException { throws SlickException {
Display.setTitle(game.getTitle()); Display.setTitle(game.getTitle());
SoundController.playSound(SoundController.SOUND_APPLAUSE);
} }
} }

View File

@ -22,6 +22,7 @@ import itdelatrisu.opsu.GUIMenuButton;
import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.MusicController;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.OsuGroupNode; import itdelatrisu.opsu.OsuGroupNode;
import itdelatrisu.opsu.SoundController;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@ -287,19 +288,24 @@ public class MainMenu extends BasicGameState {
logoTimer = 0; logoTimer = 0;
playButton.getImage().setAlpha(0f); playButton.getImage().setAlpha(0f);
exitButton.getImage().setAlpha(0f); exitButton.getImage().setAlpha(0f);
SoundController.playSound(SoundController.SOUND_MENUHIT);
} }
} }
// other button actions (if visible) // other button actions (if visible)
else if (logoClicked) { else if (logoClicked) {
if (logo.contains(x, y)) if (logo.contains(x, y)) {
SoundController.playSound(SoundController.SOUND_MENUHIT);
logoTimer = MOVE_DELAY; logoTimer = MOVE_DELAY;
else if (playButton.contains(x, y)) } else if (playButton.contains(x, y)) {
SoundController.playSound(SoundController.SOUND_MENUHIT);
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
else if (exitButton.contains(x, y)) } else if (exitButton.contains(x, y)) {
SoundController.playSound(SoundController.SOUND_MENUHIT);
game.enterState(Opsu.STATE_MAINMENUEXIT); game.enterState(Opsu.STATE_MAINMENUEXIT);
} }
} }
}
@Override @Override
public void keyPressed(int key, char c) { public void keyPressed(int key, char c) {

View File

@ -20,6 +20,7 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GUIMenuButton; import itdelatrisu.opsu.GUIMenuButton;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.SoundController;
import java.awt.Font; import java.awt.Font;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -148,12 +149,13 @@ public class Options extends BasicGameState {
// OPTIONS_FULLSCREEN = , // OPTIONS_FULLSCREEN = ,
OPTIONS_TARGET_FPS = 1, OPTIONS_TARGET_FPS = 1,
OPTIONS_MUSIC_VOLUME = 2, OPTIONS_MUSIC_VOLUME = 2,
OPTIONS_MUSIC_OFFSET = 3, OPTIONS_EFFECT_VOLUME = 3,
OPTIONS_SCREENSHOT_FORMAT = 4, OPTIONS_MUSIC_OFFSET = 4,
OPTIONS_DISPLAY_FPS = 5, OPTIONS_SCREENSHOT_FORMAT = 5,
OPTIONS_HIT_LIGHTING = 6, OPTIONS_DISPLAY_FPS = 6,
OPTIONS_COMBO_BURSTS = 7, OPTIONS_HIT_LIGHTING = 7,
OPTIONS_MAX = 8; // not an option OPTIONS_COMBO_BURSTS = 8,
OPTIONS_MAX = 9; // not an option
/** /**
* Screen resolutions. * Screen resolutions.
@ -208,7 +210,12 @@ public class Options extends BasicGameState {
/** /**
* Default music volume. * Default music volume.
*/ */
private static int musicVolume = 20; private static int musicVolume = 30;
/**
* Default sound effect volume.
*/
private static int effectVolume = 20;
/** /**
* Offset time, in milliseconds, for music position-related elements. * Offset time, in milliseconds, for music position-related elements.
@ -258,8 +265,8 @@ public class Options extends BasicGameState {
Options.game = game; Options.game = game;
this.input = container.getInput(); this.input = container.getInput();
// game settings; // game settings
container.setTargetFrameRate(60); container.setTargetFrameRate(targetFPS[targetFPSindex]);
container.setMouseCursor("cursor.png", 16, 16); container.setMouseCursor("cursor.png", 16, 16);
container.setMusicVolume(getMusicVolume()); container.setMusicVolume(getMusicVolume());
container.setShowFPS(false); container.setShowFPS(false);
@ -375,6 +382,10 @@ public class Options extends BasicGameState {
String.format("%d%%", musicVolume), String.format("%d%%", musicVolume),
"Global music volume." "Global music volume."
); );
this.drawOption(g, OPTIONS_EFFECT_VOLUME, "Effect Volume",
String.format("%d%%", effectVolume),
"Sound effect volume."
);
this.drawOption(g, OPTIONS_MUSIC_OFFSET, "Music Offset", this.drawOption(g, OPTIONS_MUSIC_OFFSET, "Music Offset",
String.format("%dms", musicOffset), String.format("%dms", musicOffset),
"Adjust this value if hit objects are out of sync." "Adjust this value if hit objects are out of sync."
@ -509,6 +520,14 @@ public class Options extends BasicGameState {
container.setMusicVolume(getMusicVolume()); container.setMusicVolume(getMusicVolume());
return; return;
} }
if (isOptionClicked(OPTIONS_EFFECT_VOLUME, oldy)) {
effectVolume += diff;
if (effectVolume < 0)
effectVolume = 0;
else if (effectVolume > 100)
effectVolume = 100;
return;
}
if (isOptionClicked(OPTIONS_MUSIC_OFFSET, oldy)) { if (isOptionClicked(OPTIONS_MUSIC_OFFSET, oldy)) {
musicOffset += diff; musicOffset += diff;
if (musicOffset < -500) if (musicOffset < -500)
@ -601,6 +620,12 @@ public class Options extends BasicGameState {
*/ */
public static float getMusicVolume() { return musicVolume / 100f; } public static float getMusicVolume() { return musicVolume / 100f; }
/**
* Returns the default sound effect volume.
* @return the sound volume [0, 1]
*/
public static float getEffectVolume() { return effectVolume / 100f; }
/** /**
* Returns the music offset time. * Returns the music offset time.
* @return the offset (in milliseconds) * @return the offset (in milliseconds)
@ -639,6 +664,8 @@ public class Options extends BasicGameState {
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss"); SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
String file = date.format(new Date()); String file = date.format(new Date());
SoundController.playSound(SoundController.SOUND_SHUTTER);
// copy the screen // copy the screen
Image screen = new Image(container.getWidth(), container.getHeight()); Image screen = new Image(container.getWidth(), container.getHeight());
container.getGraphics().copyArea(screen, 0, 0); container.getGraphics().copyArea(screen, 0, 0);
@ -760,6 +787,11 @@ public class Options extends BasicGameState {
if (i >= 0 && i <= 100) if (i >= 0 && i <= 100)
musicVolume = i; musicVolume = i;
break; break;
case "VolumeEffect":
i = Integer.parseInt(value);
if (i >= 0 && i <= 100)
effectVolume = i;
break;
case "Offset": case "Offset":
i = Integer.parseInt(value); i = Integer.parseInt(value);
if (i >= -500 && i <= 500) if (i >= -500 && i <= 500)
@ -827,6 +859,8 @@ public class Options extends BasicGameState {
writer.newLine(); writer.newLine();
writer.write(String.format("VolumeMusic = %d", musicVolume)); writer.write(String.format("VolumeMusic = %d", musicVolume));
writer.newLine(); writer.newLine();
writer.write(String.format("VolumeEffect = %d", effectVolume));
writer.newLine();
writer.write(String.format("Offset = %d", musicOffset)); writer.write(String.format("Offset = %d", musicOffset));
writer.newLine(); writer.newLine();
writer.write(String.format("ScreenshotFormat = %d", screenshotFormatIndex)); writer.write(String.format("ScreenshotFormat = %d", screenshotFormatIndex));

View File

@ -25,6 +25,7 @@ import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuGroupList; import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuGroupNode; import itdelatrisu.opsu.OsuGroupNode;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.SoundController;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
@ -343,6 +344,7 @@ public class SongMenu extends BasicGameState {
// back // back
if (Options.getBackButton().contains(x, y)) { if (Options.getBackButton().contains(x, y)) {
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
return; return;
} }
@ -422,8 +424,10 @@ public class SongMenu extends BasicGameState {
if (!search.getText().isEmpty()) { if (!search.getText().isEmpty()) {
search.setText(""); search.setText("");
searchTimer = SEARCH_DELAY; searchTimer = SEARCH_DELAY;
} else } else {
SoundController.playSound(SoundController.SOUND_MENUBACK);
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
}
break; break;
case Input.KEY_F1: case Input.KEY_F1:
game.enterState(Opsu.STATE_OPTIONS, new EmptyTransition(), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_OPTIONS, new EmptyTransition(), new FadeInTransition(Color.black));
@ -592,8 +596,10 @@ public class SongMenu extends BasicGameState {
if (MusicController.isConverting()) if (MusicController.isConverting())
return; return;
SoundController.playSound(SoundController.SOUND_MENUHIT);
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString())); Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
OsuParser.parseHitObjects(osu); OsuParser.parseHitObjects(osu);
SoundController.setSampleSet(osu.sampleSet);
Game.setOsuFile(osu); Game.setOsuFile(osu);
Game.setRestart(Game.RESTART_NEW); Game.setRestart(Game.RESTART_NEW);
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));