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:
@@ -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)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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.
|
* 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))
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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?
|
||||||
|
|||||||
@@ -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) {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,22 +686,33 @@ 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);
|
||||||
timingPointIndex++;
|
if (timingPoint.velocity >= 0) {
|
||||||
|
beatLengthBase = beatLength = timingPoint.beatLength;
|
||||||
|
SoundController.setSampleSet(timingPoint.sampleType);
|
||||||
|
SoundController.setSampleVolume(timingPoint.sampleVolume);
|
||||||
|
timingPointIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leadInTime = osu.audioLeadIn + approachTime;
|
leadInTime = osu.audioLeadIn + approachTime;
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,17 +288,22 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user