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:
parent
60eaa42997
commit
0604a25822
|
@ -23,4 +23,5 @@ Projects
|
|||
The following projects were referenced in creating opsu!:
|
||||
|
||||
* "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)
|
BIN
res/applause.wav
Normal file
BIN
res/applause.wav
Normal file
Binary file not shown.
BIN
res/combobreak.wav
Normal file
BIN
res/combobreak.wav
Normal file
Binary file not shown.
BIN
res/count1s.wav
Normal file
BIN
res/count1s.wav
Normal file
Binary file not shown.
BIN
res/count2s.wav
Normal file
BIN
res/count2s.wav
Normal file
Binary file not shown.
BIN
res/count3s.wav
Normal file
BIN
res/count3s.wav
Normal file
Binary file not shown.
BIN
res/drum-hitclap.wav
Normal file
BIN
res/drum-hitclap.wav
Normal file
Binary file not shown.
BIN
res/drum-hitfinish.wav
Normal file
BIN
res/drum-hitfinish.wav
Normal file
Binary file not shown.
BIN
res/drum-hitnormal.wav
Normal file
BIN
res/drum-hitnormal.wav
Normal file
Binary file not shown.
BIN
res/drum-hitwhistle.wav
Normal file
BIN
res/drum-hitwhistle.wav
Normal file
Binary file not shown.
BIN
res/drum-sliderslide.wav
Normal file
BIN
res/drum-sliderslide.wav
Normal file
Binary file not shown.
BIN
res/drum-slidertick.wav
Normal file
BIN
res/drum-slidertick.wav
Normal file
Binary file not shown.
BIN
res/drum-sliderwhistle.wav
Normal file
BIN
res/drum-sliderwhistle.wav
Normal file
Binary file not shown.
BIN
res/failsound.wav
Normal file
BIN
res/failsound.wav
Normal file
Binary file not shown.
BIN
res/gos.wav
Normal file
BIN
res/gos.wav
Normal file
Binary file not shown.
BIN
res/menuback.wav
Normal file
BIN
res/menuback.wav
Normal file
Binary file not shown.
BIN
res/menuclick.wav
Normal file
BIN
res/menuclick.wav
Normal file
Binary file not shown.
BIN
res/menuhit.wav
Normal file
BIN
res/menuhit.wav
Normal file
Binary file not shown.
BIN
res/normal-hitclap.wav
Normal file
BIN
res/normal-hitclap.wav
Normal file
Binary file not shown.
BIN
res/normal-hitfinish.wav
Normal file
BIN
res/normal-hitfinish.wav
Normal file
Binary file not shown.
BIN
res/normal-hitnormal.wav
Normal file
BIN
res/normal-hitnormal.wav
Normal file
Binary file not shown.
BIN
res/normal-hitwhistle.wav
Normal file
BIN
res/normal-hitwhistle.wav
Normal file
Binary file not shown.
BIN
res/normal-sliderslide.wav
Normal file
BIN
res/normal-sliderslide.wav
Normal file
Binary file not shown.
BIN
res/normal-slidertick.wav
Normal file
BIN
res/normal-slidertick.wav
Normal file
Binary file not shown.
BIN
res/normal-sliderwhistle.wav
Normal file
BIN
res/normal-sliderwhistle.wav
Normal file
Binary file not shown.
BIN
res/readys.wav
Normal file
BIN
res/readys.wav
Normal file
Binary file not shown.
BIN
res/sectionfail.wav
Normal file
BIN
res/sectionfail.wav
Normal file
Binary file not shown.
BIN
res/sectionpass.wav
Normal file
BIN
res/sectionpass.wav
Normal file
Binary file not shown.
BIN
res/shutter.wav
Normal file
BIN
res/shutter.wav
Normal file
Binary file not shown.
BIN
res/soft-hitclap.wav
Normal file
BIN
res/soft-hitclap.wav
Normal file
Binary file not shown.
BIN
res/soft-hitfinish.wav
Normal file
BIN
res/soft-hitfinish.wav
Normal file
Binary file not shown.
BIN
res/soft-hitnormal.wav
Normal file
BIN
res/soft-hitnormal.wav
Normal file
Binary file not shown.
BIN
res/soft-hitwhistle.wav
Normal file
BIN
res/soft-hitwhistle.wav
Normal file
Binary file not shown.
BIN
res/soft-sliderslide.wav
Normal file
BIN
res/soft-sliderslide.wav
Normal file
Binary file not shown.
BIN
res/soft-slidertick.wav
Normal file
BIN
res/soft-slidertick.wav
Normal file
Binary file not shown.
BIN
res/soft-sliderwhistle.wav
Normal file
BIN
res/soft-sliderwhistle.wav
Normal file
Binary file not shown.
BIN
res/spinner-osu.wav
Normal file
BIN
res/spinner-osu.wav
Normal file
Binary file not shown.
BIN
res/spinnerbonus.wav
Normal file
BIN
res/spinnerbonus.wav
Normal file
Binary file not shown.
BIN
res/spinnerspin.wav
Normal file
BIN
res/spinnerspin.wav
Normal file
Binary file not shown.
|
@ -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.
|
||||
* @param time the tick start time
|
||||
* @param result the hit result (HIT_* constants)
|
||||
* @param x the x 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;
|
||||
switch (result) {
|
||||
case HIT_SLIDER30:
|
||||
hitValue = 30;
|
||||
incrementComboStreak();
|
||||
changeHealth(1f);
|
||||
SoundController.playHitSound(hitSound);
|
||||
break;
|
||||
case HIT_SLIDER10:
|
||||
hitValue = 10;
|
||||
incrementComboStreak();
|
||||
SoundController.playHitSound(SoundController.HIT_SLIDERTICK);
|
||||
break;
|
||||
case HIT_MISS:
|
||||
combo = 0;
|
||||
if (Options.isModActive(Options.MOD_SUDDEN_DEATH))
|
||||
health = 0f;
|
||||
resetComboStreak();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
@ -760,8 +772,10 @@ public class GameScore {
|
|||
* @param y the y coordinate
|
||||
* @param color the combo color
|
||||
* @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;
|
||||
switch (result) {
|
||||
case HIT_300:
|
||||
|
@ -784,15 +798,15 @@ public class GameScore {
|
|||
hitValue = 0;
|
||||
changeHealth(-10f);
|
||||
comboEnd |= 2;
|
||||
combo = 0;
|
||||
if (Options.isModActive(Options.MOD_SUDDEN_DEATH))
|
||||
health = 0f;
|
||||
resetComboStreak();
|
||||
objectCount++;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (hitValue > 0) {
|
||||
SoundController.playHitSound(hitSound);
|
||||
|
||||
// game mod score multipliers
|
||||
float modMultiplier = 1f;
|
||||
if (Options.isModActive(Options.MOD_NO_FAIL))
|
||||
|
|
|
@ -143,6 +143,9 @@ public class Opsu extends StateBasedGame {
|
|||
}
|
||||
Options.TMP_DIR.deleteOnExit();
|
||||
|
||||
// load sounds
|
||||
SoundController.init();
|
||||
|
||||
app.start();
|
||||
} catch (SlickException e) {
|
||||
Log.error("Error while creating game container.", e);
|
||||
|
|
|
@ -40,7 +40,7 @@ public class OsuFile implements Comparable<OsuFile> {
|
|||
// public String audioHash = ""; // audio hash (deprecated)
|
||||
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 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 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
|
||||
|
|
|
@ -38,7 +38,6 @@ public class OsuHitObject {
|
|||
SOUND_NORMAL = 0,
|
||||
SOUND_WHISTLE = 2,
|
||||
SOUND_FINISH = 4,
|
||||
SOUND_WHISTLEFINISH = 6,
|
||||
SOUND_CLAP = 8;
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,8 +26,8 @@ public class OsuTimingPoint {
|
|||
public float beatLength; // (non-inherited) ms per beat
|
||||
public int velocity = 0; // (inherited) slider multiplier = -100 / value
|
||||
public int meter; // beats per measure
|
||||
public byte sampleType; // sound samples (0:none, 1:normal, 2:soft)
|
||||
public byte sampleTypeCustom; // custom samples (0:default, 1:custom1, 2:custom2
|
||||
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 int sampleVolume; // volume of samples (0~100)
|
||||
public boolean inherited; // is this timing point inherited?
|
||||
public boolean kiai; // is Kiai Mode active?
|
||||
|
|
285
src/itdelatrisu/opsu/SoundController.java
Normal file
285
src/itdelatrisu/opsu/SoundController.java
Normal 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());
|
||||
}
|
||||
}
|
|
@ -172,7 +172,9 @@ public class Circle {
|
|||
if (distance < circleRadius) {
|
||||
int result = hitResult(hitObject.time);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -192,11 +194,11 @@ public class Circle {
|
|||
if (overlap || trackPosition > hitObject.time + hitResultOffset[GameScore.HIT_50]) {
|
||||
if (isAutoMod) // "auto" mod: catch any missed notes due to lag
|
||||
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
|
||||
score.hitResult(hitObject.time, GameScore.HIT_MISS,
|
||||
hitObject.x, hitObject.y, null, comboEnd);
|
||||
hitObject.x, hitObject.y, null, comboEnd, hitObject.hitSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -204,7 +206,7 @@ public class Circle {
|
|||
else if (isAutoMod) {
|
||||
if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -384,10 +384,11 @@ public class Slider {
|
|||
|
||||
if (currentRepeats % 2 == 0) // last circle
|
||||
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
|
||||
score.hitResult(hitObject.time + (int) sliderTimeTotal, result,
|
||||
hitObject.x, hitObject.y, color, comboEnd);
|
||||
hitObject.x, hitObject.y, color, comboEnd, hitObject.hitSound);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -420,7 +421,8 @@ public class Slider {
|
|||
|
||||
if (result > -1) {
|
||||
sliderClicked = true;
|
||||
score.sliderTickResult(hitObject.time, result, hitObject.x, hitObject.y);
|
||||
score.sliderTickResult(hitObject.time, result,
|
||||
hitObject.x, hitObject.y, hitObject.hitSound);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -465,9 +467,11 @@ public class Slider {
|
|||
sliderClicked = true;
|
||||
if (isAutoMod) { // "auto" mod: catch any missed notes due to lag
|
||||
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
|
||||
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
|
||||
|
@ -475,7 +479,8 @@ public class Slider {
|
|||
if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[GameScore.HIT_300]) {
|
||||
ticksHit++;
|
||||
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++;
|
||||
if (currentRepeats % 2 > 0) // last circle
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30,
|
||||
hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex]);
|
||||
hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex],
|
||||
hitObject.hitSound);
|
||||
else // first circle
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30,
|
||||
c[0], c[1]);
|
||||
c[0], c[1], hitObject.hitSound);
|
||||
}
|
||||
|
||||
// held during new tick
|
||||
if (isNewTick) {
|
||||
ticksHit++;
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER10, c[0], c[1]);
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER10,
|
||||
c[0], c[1], (byte) -1);
|
||||
}
|
||||
} else {
|
||||
followCircleActive = false;
|
||||
|
||||
if (isNewRepeat)
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0);
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, hitObject.hitSound);
|
||||
if (isNewTick)
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0);
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, (byte) -1);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -21,6 +21,7 @@ package itdelatrisu.opsu.objects;
|
|||
import itdelatrisu.opsu.GameScore;
|
||||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.states.Options;
|
||||
|
||||
|
@ -163,16 +164,19 @@ public class Spinner {
|
|||
int result;
|
||||
float ratio = rotations / rotationsNeeded;
|
||||
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;
|
||||
else if (ratio >= 0.8f)
|
||||
SoundController.playSound(SoundController.SOUND_SPINNEROSU);
|
||||
} else if (ratio >= 0.8f)
|
||||
result = GameScore.HIT_100;
|
||||
else if (ratio >= 0.5f)
|
||||
result = GameScore.HIT_50;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -240,10 +244,13 @@ public class Spinner {
|
|||
|
||||
// added one whole rotation...
|
||||
if (Math.floor(newRotations) > rotations) {
|
||||
if (newRotations > rotationsNeeded) // extra rotations
|
||||
if (newRotations > rotationsNeeded) { // extra rotations
|
||||
score.changeScore(1000);
|
||||
else
|
||||
SoundController.playSound(SoundController.SOUND_SPINNERBONUS);
|
||||
} else {
|
||||
score.changeScore(100);
|
||||
SoundController.playSound(SoundController.SOUND_SPINNERSPIN);
|
||||
}
|
||||
}
|
||||
|
||||
rotations = newRotations;
|
||||
|
|
|
@ -25,6 +25,7 @@ import itdelatrisu.opsu.Opsu;
|
|||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.OsuTimingPoint;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.objects.Circle;
|
||||
import itdelatrisu.opsu.objects.Slider;
|
||||
import itdelatrisu.opsu.objects.Spinner;
|
||||
|
@ -134,6 +135,11 @@ public class Game extends BasicGameState {
|
|||
*/
|
||||
private int breakTime = 0;
|
||||
|
||||
/**
|
||||
* Whether the break sound has been played.
|
||||
*/
|
||||
private boolean breakSound;
|
||||
|
||||
/**
|
||||
* Skip button (displayed at song start, when necessary).
|
||||
*/
|
||||
|
@ -164,6 +170,13 @@ public class Game extends BasicGameState {
|
|||
countdown2, // "1" 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.
|
||||
*/
|
||||
|
@ -276,10 +289,19 @@ public class Game extends BasicGameState {
|
|||
trackPosition - breakTime > 2000 &&
|
||||
trackPosition - breakTime < 5000) {
|
||||
// show break start
|
||||
if (score.getHealth() >= 50)
|
||||
if (score.getHealth() >= 50) {
|
||||
breakStartPass.drawCentered(width / 2f, height / 2f);
|
||||
else
|
||||
if (!breakSound) {
|
||||
SoundController.playSound(SoundController.SOUND_SECTIONPASS);
|
||||
breakSound = true;
|
||||
}
|
||||
} else {
|
||||
breakStartFail.drawCentered(width / 2f, height / 2f);
|
||||
if (!breakSound) {
|
||||
SoundController.playSound(SoundController.SOUND_SECTIONFAIL);
|
||||
breakSound = true;
|
||||
}
|
||||
}
|
||||
} else if (breakLength >= 4000) {
|
||||
// show break end (flash twice for 500ms)
|
||||
int endTimeDiff = endTime - trackPosition;
|
||||
|
@ -326,18 +348,41 @@ public class Game extends BasicGameState {
|
|||
if (osu.countdown > 0) { // TODO: implement half/double rate settings
|
||||
int timeDiff = osu.objects[0].time - trackPosition;
|
||||
if (timeDiff >= 500 && timeDiff < 3000) {
|
||||
if (timeDiff >= 1500)
|
||||
if (timeDiff >= 1500) {
|
||||
countdownReady.drawCentered(width / 2, height / 2);
|
||||
|
||||
if (timeDiff < 2000)
|
||||
if (!countdownReadySound) {
|
||||
SoundController.playSound(SoundController.SOUND_READY);
|
||||
countdownReadySound = true;
|
||||
}
|
||||
}
|
||||
if (timeDiff < 2000) {
|
||||
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);
|
||||
if (timeDiff < 1000)
|
||||
if (!countdown2Sound) {
|
||||
SoundController.playSound(SoundController.SOUND_COUNT2);
|
||||
countdown2Sound = true;
|
||||
}
|
||||
}
|
||||
if (timeDiff < 1000) {
|
||||
countdown1.drawCentered(width / 2, height / 2);
|
||||
if (!countdown1Sound) {
|
||||
SoundController.playSound(SoundController.SOUND_COUNT1);
|
||||
countdown1Sound = true;
|
||||
}
|
||||
}
|
||||
} else if (timeDiff >= -500 && timeDiff < 500) {
|
||||
countdownGo.setAlpha((timeDiff < 0) ? 1 - (timeDiff / -1000f) : 1);
|
||||
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;
|
||||
else
|
||||
beatLength = beatLengthBase * (timingPoint.velocity / -100f);
|
||||
SoundController.setSampleSet(timingPoint.sampleType);
|
||||
SoundController.setSampleVolume(timingPoint.sampleVolume);
|
||||
timingPointIndex++;
|
||||
}
|
||||
}
|
||||
|
@ -456,6 +503,7 @@ public class Game extends BasicGameState {
|
|||
} else if (trackPosition >= breakValue) {
|
||||
// start a break
|
||||
breakTime = breakValue;
|
||||
breakSound = false;
|
||||
breakIndex++;
|
||||
return;
|
||||
}
|
||||
|
@ -638,22 +686,33 @@ public class Game extends BasicGameState {
|
|||
}
|
||||
}
|
||||
|
||||
// reset indexes
|
||||
// reset data
|
||||
MusicController.setPosition(0);
|
||||
MusicController.pause();
|
||||
score.clear();
|
||||
objectIndex = 0;
|
||||
breakIndex = 0;
|
||||
breakTime = 0;
|
||||
breakSound = false;
|
||||
timingPointIndex = 0;
|
||||
pauseTime = -1;
|
||||
pausedMouseX = -1;
|
||||
pausedMouseY = -1;
|
||||
countdownReadySound = false;
|
||||
countdown3Sound = false;
|
||||
countdown1Sound = false;
|
||||
countdown2Sound = false;
|
||||
countdownGoSound = false;
|
||||
|
||||
// load the first timingPoint
|
||||
if (!osu.timingPoints.isEmpty() && osu.timingPoints.get(0).velocity >= 0) {
|
||||
beatLengthBase = beatLength = osu.timingPoints.get(0).beatLength;
|
||||
timingPointIndex++;
|
||||
if (!osu.timingPoints.isEmpty()) {
|
||||
OsuTimingPoint timingPoint = osu.timingPoints.get(0);
|
||||
if (timingPoint.velocity >= 0) {
|
||||
beatLengthBase = beatLength = timingPoint.beatLength;
|
||||
SoundController.setSampleSet(timingPoint.sampleType);
|
||||
SoundController.setSampleVolume(timingPoint.sampleVolume);
|
||||
timingPointIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
leadInTime = osu.audioLeadIn + approachTime;
|
||||
|
@ -675,6 +734,7 @@ public class Game extends BasicGameState {
|
|||
MusicController.resume();
|
||||
}
|
||||
MusicController.setPosition(osu.objects[0].time - skipOffsetTime);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -21,6 +21,7 @@ package itdelatrisu.opsu.states;
|
|||
import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
|
@ -142,6 +143,7 @@ public class GamePauseMenu extends BasicGameState {
|
|||
if (Game.getRestart() == Game.RESTART_LOSE) {
|
||||
MusicController.stop();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
} else
|
||||
unPause(Game.RESTART_FALSE);
|
||||
|
@ -171,6 +173,7 @@ public class GamePauseMenu extends BasicGameState {
|
|||
} else if (backButton.contains(x, y)) {
|
||||
MusicController.pause(); // lose state
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
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)
|
||||
throws SlickException {
|
||||
pauseStartTime = System.currentTimeMillis();
|
||||
if (Game.getRestart() == Game.RESTART_LOSE)
|
||||
if (Game.getRestart() == Game.RESTART_LOSE) {
|
||||
MusicController.fadeOut(FADEOUT_TIME);
|
||||
else
|
||||
SoundController.playSound(SoundController.SOUND_FAIL);
|
||||
} else
|
||||
MusicController.pause();
|
||||
}
|
||||
|
||||
|
@ -189,6 +193,10 @@ public class GamePauseMenu extends BasicGameState {
|
|||
* Unpause and return to the Game state.
|
||||
*/
|
||||
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.enterState(Opsu.STATE_GAME);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import itdelatrisu.opsu.GameScore;
|
|||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.newdawn.slick.Color;
|
||||
|
@ -143,7 +144,9 @@ public class GameRanking extends BasicGameState {
|
|||
public void keyPressed(int key, char c) {
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
MusicController.pause();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
|
@ -162,12 +165,15 @@ public class GameRanking extends BasicGameState {
|
|||
OsuFile osu = Game.getOsuFile();
|
||||
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
|
||||
Game.setRestart(Game.RESTART_MANUAL);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
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));
|
||||
else if (Options.getBackButton().contains(x, y)) {
|
||||
MusicController.stop();
|
||||
} else if (Options.getBackButton().contains(x, y)) {
|
||||
MusicController.pause();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
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)
|
||||
throws SlickException {
|
||||
Display.setTitle(game.getTitle());
|
||||
SoundController.playSound(SoundController.SOUND_APPLAUSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import itdelatrisu.opsu.GUIMenuButton;
|
|||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
@ -287,17 +288,22 @@ public class MainMenu extends BasicGameState {
|
|||
logoTimer = 0;
|
||||
playButton.getImage().setAlpha(0f);
|
||||
exitButton.getImage().setAlpha(0f);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
}
|
||||
}
|
||||
|
||||
// other button actions (if visible)
|
||||
else if (logoClicked) {
|
||||
if (logo.contains(x, y))
|
||||
if (logo.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
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));
|
||||
else if (exitButton.contains(x, y))
|
||||
} else if (exitButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
game.enterState(Opsu.STATE_MAINMENUEXIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package itdelatrisu.opsu.states;
|
|||
|
||||
import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.io.BufferedReader;
|
||||
|
@ -148,12 +149,13 @@ public class Options extends BasicGameState {
|
|||
// OPTIONS_FULLSCREEN = ,
|
||||
OPTIONS_TARGET_FPS = 1,
|
||||
OPTIONS_MUSIC_VOLUME = 2,
|
||||
OPTIONS_MUSIC_OFFSET = 3,
|
||||
OPTIONS_SCREENSHOT_FORMAT = 4,
|
||||
OPTIONS_DISPLAY_FPS = 5,
|
||||
OPTIONS_HIT_LIGHTING = 6,
|
||||
OPTIONS_COMBO_BURSTS = 7,
|
||||
OPTIONS_MAX = 8; // not an option
|
||||
OPTIONS_EFFECT_VOLUME = 3,
|
||||
OPTIONS_MUSIC_OFFSET = 4,
|
||||
OPTIONS_SCREENSHOT_FORMAT = 5,
|
||||
OPTIONS_DISPLAY_FPS = 6,
|
||||
OPTIONS_HIT_LIGHTING = 7,
|
||||
OPTIONS_COMBO_BURSTS = 8,
|
||||
OPTIONS_MAX = 9; // not an option
|
||||
|
||||
/**
|
||||
* Screen resolutions.
|
||||
|
@ -208,7 +210,12 @@ public class Options extends BasicGameState {
|
|||
/**
|
||||
* 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.
|
||||
|
@ -258,8 +265,8 @@ public class Options extends BasicGameState {
|
|||
Options.game = game;
|
||||
this.input = container.getInput();
|
||||
|
||||
// game settings;
|
||||
container.setTargetFrameRate(60);
|
||||
// game settings
|
||||
container.setTargetFrameRate(targetFPS[targetFPSindex]);
|
||||
container.setMouseCursor("cursor.png", 16, 16);
|
||||
container.setMusicVolume(getMusicVolume());
|
||||
container.setShowFPS(false);
|
||||
|
@ -375,6 +382,10 @@ public class Options extends BasicGameState {
|
|||
String.format("%d%%", musicVolume),
|
||||
"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",
|
||||
String.format("%dms", musicOffset),
|
||||
"Adjust this value if hit objects are out of sync."
|
||||
|
@ -509,6 +520,14 @@ public class Options extends BasicGameState {
|
|||
container.setMusicVolume(getMusicVolume());
|
||||
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)) {
|
||||
musicOffset += diff;
|
||||
if (musicOffset < -500)
|
||||
|
@ -601,6 +620,12 @@ public class Options extends BasicGameState {
|
|||
*/
|
||||
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.
|
||||
* @return the offset (in milliseconds)
|
||||
|
@ -639,6 +664,8 @@ public class Options extends BasicGameState {
|
|||
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||
String file = date.format(new Date());
|
||||
|
||||
SoundController.playSound(SoundController.SOUND_SHUTTER);
|
||||
|
||||
// copy the screen
|
||||
Image screen = new Image(container.getWidth(), container.getHeight());
|
||||
container.getGraphics().copyArea(screen, 0, 0);
|
||||
|
@ -760,6 +787,11 @@ public class Options extends BasicGameState {
|
|||
if (i >= 0 && i <= 100)
|
||||
musicVolume = i;
|
||||
break;
|
||||
case "VolumeEffect":
|
||||
i = Integer.parseInt(value);
|
||||
if (i >= 0 && i <= 100)
|
||||
effectVolume = i;
|
||||
break;
|
||||
case "Offset":
|
||||
i = Integer.parseInt(value);
|
||||
if (i >= -500 && i <= 500)
|
||||
|
@ -827,6 +859,8 @@ public class Options extends BasicGameState {
|
|||
writer.newLine();
|
||||
writer.write(String.format("VolumeMusic = %d", musicVolume));
|
||||
writer.newLine();
|
||||
writer.write(String.format("VolumeEffect = %d", effectVolume));
|
||||
writer.newLine();
|
||||
writer.write(String.format("Offset = %d", musicOffset));
|
||||
writer.newLine();
|
||||
writer.write(String.format("ScreenshotFormat = %d", screenshotFormatIndex));
|
||||
|
|
|
@ -25,6 +25,7 @@ import itdelatrisu.opsu.OsuFile;
|
|||
import itdelatrisu.opsu.OsuGroupList;
|
||||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.OsuParser;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.newdawn.slick.Color;
|
||||
|
@ -343,6 +344,7 @@ public class SongMenu extends BasicGameState {
|
|||
|
||||
// back
|
||||
if (Options.getBackButton().contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
return;
|
||||
}
|
||||
|
@ -422,8 +424,10 @@ public class SongMenu extends BasicGameState {
|
|||
if (!search.getText().isEmpty()) {
|
||||
search.setText("");
|
||||
searchTimer = SEARCH_DELAY;
|
||||
} else
|
||||
} else {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
}
|
||||
break;
|
||||
case Input.KEY_F1:
|
||||
game.enterState(Opsu.STATE_OPTIONS, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||
|
@ -592,8 +596,10 @@ public class SongMenu extends BasicGameState {
|
|||
if (MusicController.isConverting())
|
||||
return;
|
||||
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
|
||||
OsuParser.parseHitObjects(osu);
|
||||
SoundController.setSampleSet(osu.sampleSet);
|
||||
Game.setOsuFile(osu);
|
||||
Game.setRestart(Game.RESTART_NEW);
|
||||
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
|
|
Loading…
Reference in New Issue
Block a user