Hit object refactoring.
- Moved the bulk of hit object parsing into the OsuHitObject constructor, and made all fields private. Only combo-related data is still set by OsuParser. - Added 'isCircle()', 'isSlider()', 'isSpinner()', and 'isNewCombo()' methods for convenience. Other changes: - Fixed difficulty overrides are no longer affected by game mods. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
2380b11f48
commit
717605564d
|
@ -500,7 +500,7 @@ public class GameScore {
|
|||
g.drawOval(circleX, symbolHeight, circleDiameter, circleDiameter);
|
||||
|
||||
OsuFile osu = MusicController.getOsuFile();
|
||||
int firstObjectTime = osu.objects[0].time;
|
||||
int firstObjectTime = osu.objects[0].getTime();
|
||||
int trackPosition = MusicController.getPosition();
|
||||
if (trackPosition > firstObjectTime) {
|
||||
// map progress (white)
|
||||
|
|
|
@ -32,7 +32,7 @@ public class OsuHitObject {
|
|||
TYPE_SPINNER = 8;
|
||||
|
||||
/**
|
||||
* Hit sound types.
|
||||
* Hit sound types (bits).
|
||||
*/
|
||||
public static final byte
|
||||
SOUND_NORMAL = 0,
|
||||
|
@ -53,39 +53,263 @@ public class OsuHitObject {
|
|||
/**
|
||||
* Max hit object coordinates.
|
||||
*/
|
||||
public static final int
|
||||
private static final int
|
||||
MAX_X = 512,
|
||||
MAX_Y = 384;
|
||||
|
||||
// parsed fields (coordinates are scaled)
|
||||
public float x, y; // start coordinates
|
||||
public int time; // start time, in ms
|
||||
public int type; // hit object type
|
||||
public byte hitSound; // hit sound type
|
||||
public char sliderType; // slider curve type (sliders only)
|
||||
public float[] sliderX; // slider x coordinate list (sliders only)
|
||||
public float[] sliderY; // slider y coordinate list (sliders only)
|
||||
public int repeat; // slider repeat count (sliders only)
|
||||
public float pixelLength; // slider pixel length (sliders only)
|
||||
public int endTime; // end time, in ms (spinners only)
|
||||
/**
|
||||
* The x and y multipliers for hit object coordinates.
|
||||
*/
|
||||
private static float xMultiplier, yMultiplier;
|
||||
|
||||
/**
|
||||
* The x and y offsets for hit object coordinates.
|
||||
*/
|
||||
private static int
|
||||
xOffset, // offset right of border
|
||||
yOffset; // offset below health bar
|
||||
|
||||
/**
|
||||
* Starting coordinates (scaled).
|
||||
*/
|
||||
private float x, y;
|
||||
|
||||
/**
|
||||
* Start time (in ms).
|
||||
*/
|
||||
private int time;
|
||||
|
||||
/**
|
||||
* Hit object type (TYPE_* bitmask).
|
||||
*/
|
||||
private int type;
|
||||
|
||||
/**
|
||||
* Hit sound type (SOUND_* bitmask).
|
||||
*/
|
||||
private byte hitSound;
|
||||
|
||||
/**
|
||||
* Slider curve type (SLIDER_* constant).
|
||||
*/
|
||||
private char sliderType;
|
||||
|
||||
/**
|
||||
* Slider coordinate lists (scaled).
|
||||
*/
|
||||
private float[] sliderX, sliderY;
|
||||
|
||||
/**
|
||||
* Slider repeat count.
|
||||
*/
|
||||
private int repeat;
|
||||
|
||||
/**
|
||||
* Slider pixel length.
|
||||
*/
|
||||
private float pixelLength;
|
||||
|
||||
/**
|
||||
* Spinner end time (in ms).
|
||||
*/
|
||||
private int endTime;
|
||||
|
||||
// additional v10+ parameters not implemented...
|
||||
// addition -> sampl:add:cust:vol:hitsound
|
||||
// edge_hitsound, edge_addition (sliders only)
|
||||
|
||||
// extra fields
|
||||
public int comboIndex; // current index in Color array
|
||||
public int comboNumber; // number to display in hit object
|
||||
/**
|
||||
* Current index in combo color array.
|
||||
*/
|
||||
private int comboIndex;
|
||||
|
||||
/**
|
||||
* Constructor with all required fields.
|
||||
* Number to display in hit object.
|
||||
*/
|
||||
public OsuHitObject(float x, float y, int time, int type, byte hitSound) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.time = time;
|
||||
this.type = type;
|
||||
this.hitSound = hitSound;
|
||||
private int comboNumber;
|
||||
|
||||
/**
|
||||
* Initializes the OsuHitObject data type with container dimensions.
|
||||
* @param width the container width
|
||||
* @param height the container height
|
||||
*/
|
||||
public static void init(int width, int height) {
|
||||
xMultiplier = (width * 0.6f) / MAX_X;
|
||||
yMultiplier = (height * 0.6f) / MAX_Y;
|
||||
xOffset = width / 5;
|
||||
yOffset = height / 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param line the line to be parsed
|
||||
*/
|
||||
public OsuHitObject(String line) {
|
||||
/**
|
||||
* [OBJECT FORMATS]
|
||||
* Circles:
|
||||
* x,y,time,type,hitSound,addition
|
||||
* 256,148,9466,1,2,0:0:0:0:
|
||||
*
|
||||
* Sliders:
|
||||
* x,y,time,type,hitSound,sliderType|curveX:curveY|...,repeat,pixelLength,edgeHitsound,edgeAddition,addition
|
||||
* 300,68,4591,2,0,B|372:100|332:172|420:192,2,180,2|2|2,0:0|0:0|0:0,0:0:0:0:
|
||||
*
|
||||
* Spinners:
|
||||
* x,y,time,type,hitSound,endTime,addition
|
||||
* 256,192,654,12,0,4029,0:0:0:0:
|
||||
*
|
||||
* NOTE: 'addition' is optional, and defaults to "0:0:0:0:".
|
||||
*/
|
||||
String tokens[] = line.split(",");
|
||||
|
||||
// common fields
|
||||
this.x = Integer.parseInt(tokens[0]) * xMultiplier + xOffset;
|
||||
this.y = Integer.parseInt(tokens[1]) * yMultiplier + yOffset;
|
||||
this.time = Integer.parseInt(tokens[2]);
|
||||
this.type = Integer.parseInt(tokens[3]);
|
||||
this.hitSound = Byte.parseByte(tokens[4]);
|
||||
|
||||
// type-specific fields
|
||||
if ((type & OsuHitObject.TYPE_CIRCLE) > 0) {
|
||||
/* 'addition' not implemented. */
|
||||
|
||||
} else if ((type & OsuHitObject.TYPE_SLIDER) > 0) {
|
||||
// slider curve type and coordinates
|
||||
String[] sliderTokens = tokens[5].split("\\|");
|
||||
this.sliderType = sliderTokens[0].charAt(0);
|
||||
this.sliderX = new float[sliderTokens.length - 1];
|
||||
this.sliderY = new float[sliderTokens.length - 1];
|
||||
for (int j = 1; j < sliderTokens.length; j++) {
|
||||
String[] sliderXY = sliderTokens[j].split(":");
|
||||
this.sliderX[j - 1] = Integer.parseInt(sliderXY[0]) * xMultiplier + xOffset;
|
||||
this.sliderY[j - 1] = Integer.parseInt(sliderXY[1]) * yMultiplier + yOffset;
|
||||
}
|
||||
this.repeat = Integer.parseInt(tokens[6]);
|
||||
this.pixelLength = Float.parseFloat(tokens[7]);
|
||||
/* edge fields and 'addition' not implemented. */
|
||||
|
||||
} else { //if ((type & OsuHitObject.TYPE_SPINNER) > 0) {
|
||||
// some 'endTime' fields contain a ':' character (?)
|
||||
int index = tokens[5].indexOf(':');
|
||||
if (index != -1)
|
||||
tokens[5] = tokens[5].substring(0, index);
|
||||
this.endTime = Integer.parseInt(tokens[5]);
|
||||
/* 'addition' not implemented. */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the starting x coordinate.
|
||||
* @return the x coordinate
|
||||
*/
|
||||
public float getX() { return x; }
|
||||
|
||||
/**
|
||||
* Returns the starting y coordinate.
|
||||
* @return the y coordinate
|
||||
*/
|
||||
public float getY() { return y; }
|
||||
|
||||
/**
|
||||
* Returns the start time.
|
||||
* @return the start time (in ms)
|
||||
*/
|
||||
public int getTime() { return time; }
|
||||
|
||||
/**
|
||||
* Returns the hit object type.
|
||||
* @return the object type (TYPE_* bitmask)
|
||||
*/
|
||||
public int getType() { return type; }
|
||||
|
||||
/**
|
||||
* Returns the hit sound type.
|
||||
* @return the sound type (SOUND_* bitmask)
|
||||
*/
|
||||
public byte getHitSoundType() { return hitSound; }
|
||||
|
||||
/**
|
||||
* Returns the slider type.
|
||||
* @return the slider type (SLIDER_* constant)
|
||||
*/
|
||||
public char getSliderType() { return sliderType; }
|
||||
|
||||
/**
|
||||
* Returns a list of slider x coordinates.
|
||||
* @return the slider x coordinates
|
||||
*/
|
||||
public float[] getSliderX() { return sliderX; }
|
||||
|
||||
/**
|
||||
* Returns a list of slider y coordinates.
|
||||
* @return the slider y coordinates
|
||||
*/
|
||||
public float[] getSliderY() { return sliderY; }
|
||||
|
||||
/**
|
||||
* Returns the slider repeat count.
|
||||
* @return the repeat count
|
||||
*/
|
||||
public int getRepeatCount() { return repeat; }
|
||||
|
||||
/**
|
||||
* Returns the slider pixel length.
|
||||
* @return the pixel length
|
||||
*/
|
||||
public float getPixelLength() { return pixelLength; }
|
||||
|
||||
/**
|
||||
* Returns the spinner end time.
|
||||
* @return the end time (in ms)
|
||||
*/
|
||||
public int getEndTime() { return endTime; }
|
||||
|
||||
/**
|
||||
* Sets the current index in the combo color array.
|
||||
* @param comboIndex the combo index
|
||||
*/
|
||||
public void setComboIndex(int comboIndex) { this.comboIndex = comboIndex; }
|
||||
|
||||
/**
|
||||
* Returns the current index in the combo color array.
|
||||
* @return the combo index
|
||||
*/
|
||||
public int getComboIndex() { return comboIndex; }
|
||||
|
||||
/**
|
||||
* Sets the number to display in the hit object.
|
||||
* @param comboNumber the combo number
|
||||
*/
|
||||
public void setComboNumber(int comboNumber) { this.comboNumber = comboNumber; }
|
||||
|
||||
/**
|
||||
* Returns the number to display in the hit object.
|
||||
* @return the combo number
|
||||
*/
|
||||
public int getComboNumber() { return comboNumber; }
|
||||
|
||||
/**
|
||||
* Returns whether or not the hit object is a circle.
|
||||
* @return true if circle
|
||||
*/
|
||||
public boolean isCircle() { return (type & TYPE_CIRCLE) > 0; }
|
||||
|
||||
/**
|
||||
* Returns whether or not the hit object is a slider.
|
||||
* @return true if slider
|
||||
*/
|
||||
public boolean isSlider() { return (type & TYPE_SLIDER) > 0; }
|
||||
|
||||
/**
|
||||
* Returns whether or not the hit object is a spinner.
|
||||
* @return true if spinner
|
||||
*/
|
||||
public boolean isSpinner() { return (type & TYPE_SPINNER) > 0; }
|
||||
|
||||
/**
|
||||
* Returns whether or not the hit object starts a new combo.
|
||||
* @return true if new combo
|
||||
*/
|
||||
public boolean isNewCombo() { return (type & TYPE_NEWCOMBO) > 0; }
|
||||
}
|
|
@ -49,18 +49,6 @@ public class OsuParser {
|
|||
*/
|
||||
private static int totalDirectories = -1;
|
||||
|
||||
/**
|
||||
* The x and y multipliers for hit object coordinates.
|
||||
*/
|
||||
private static float xMultiplier, yMultiplier;
|
||||
|
||||
/**
|
||||
* The x and y offsets for hit object coordinates.
|
||||
*/
|
||||
private static int
|
||||
xOffset, // offset right of border
|
||||
yOffset; // offset below health bar
|
||||
|
||||
// This class should not be instantiated.
|
||||
private OsuParser() {}
|
||||
|
||||
|
@ -71,11 +59,8 @@ public class OsuParser {
|
|||
* @param height the container height
|
||||
*/
|
||||
public static void parseAllFiles(File root, int width, int height) {
|
||||
// set coordinate modifiers
|
||||
xMultiplier = (width * 0.6f) / OsuHitObject.MAX_X;
|
||||
yMultiplier = (height * 0.6f) / OsuHitObject.MAX_Y;
|
||||
xOffset = width / 5;
|
||||
yOffset = height / 5;
|
||||
// initialize hit objects
|
||||
OsuHitObject.init(width, height);
|
||||
|
||||
// progress tracking
|
||||
File[] folders = root.listFiles();
|
||||
|
@ -438,23 +423,7 @@ public class OsuParser {
|
|||
|
||||
/**
|
||||
* Parses all hit objects in an OSU file.
|
||||
*
|
||||
* Object formats:
|
||||
* - Circles [1]:
|
||||
* x,y,time,type,hitSound,addition
|
||||
* 256,148,9466,1,2,0:0:0:0:
|
||||
*
|
||||
* - Sliders [2]:
|
||||
* x,y,time,type,hitSound,sliderType|curveX:curveY|...,repeat,pixelLength,edgeHitsound,edgeAddition,addition
|
||||
* 300,68,4591,2,0,B|372:100|332:172|420:192,2,180,2|2|2,0:0|0:0|0:0,0:0:0:0:
|
||||
*
|
||||
* - Spinners [8]:
|
||||
* x,y,time,type,hitSound,endTime,addition
|
||||
* 256,192,654,12,0,4029,0:0:0:0:
|
||||
*
|
||||
* Notes:
|
||||
* - 'addition' is optional, and defaults to "0:0:0:0:".
|
||||
* - Field descriptions are located in OsuHitObject.java.
|
||||
* @param osu the OsuFile to parse
|
||||
*/
|
||||
public static void parseHitObjects(OsuFile osu) {
|
||||
if (osu.objects != null) // already parsed
|
||||
|
@ -467,72 +436,47 @@ public class OsuParser {
|
|||
String line = in.readLine();
|
||||
while (line != null) {
|
||||
line = line.trim();
|
||||
if (!line.equals("[HitObjects]")) {
|
||||
if (!line.equals("[HitObjects]"))
|
||||
line = in.readLine();
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (line == null) {
|
||||
Log.warn(String.format("No hit objects found in OsuFile '%s'.", osu.toString()));
|
||||
return;
|
||||
}
|
||||
|
||||
// combo info
|
||||
int comboIndex = 0; // color index
|
||||
int comboNumber = 1; // combo number
|
||||
|
||||
int objectIndex = 0;
|
||||
while ((line = in.readLine()) != null && objectIndex < osu.objects.length) {
|
||||
line = line.trim();
|
||||
if (!isValidLine(line))
|
||||
continue;
|
||||
if (line.charAt(0) == '[')
|
||||
break;
|
||||
|
||||
// lines must have at minimum 5 parameters
|
||||
int tokenCount = line.length() - line.replace(",", "").length();
|
||||
if (tokenCount < 4)
|
||||
continue;
|
||||
|
||||
// create a new OsuHitObject for each line
|
||||
OsuHitObject hitObject = new OsuHitObject(line);
|
||||
|
||||
// set combo info
|
||||
// - new combo: get next combo index, reset combo number
|
||||
// - else: maintain combo index, increase combo number
|
||||
if (hitObject.isNewCombo()) {
|
||||
comboIndex = (comboIndex + 1) % osu.combo.length;
|
||||
comboNumber = 1;
|
||||
}
|
||||
hitObject.setComboIndex(comboIndex);
|
||||
hitObject.setComboNumber(comboNumber++);
|
||||
|
||||
int i = 0; // object index
|
||||
int comboIndex = 0; // color index
|
||||
int comboNumber = 1; // combo number
|
||||
String tokens[], sliderTokens[], sliderXY[];
|
||||
|
||||
while ((line = in.readLine()) != null && i < osu.objects.length) {
|
||||
line = line.trim();
|
||||
if (!isValidLine(line))
|
||||
continue;
|
||||
if (line.charAt(0) == '[')
|
||||
break;
|
||||
// create a new OsuHitObject for each line
|
||||
tokens = line.split(",");
|
||||
if (tokens.length < 5)
|
||||
continue;
|
||||
float scaledX = Integer.parseInt(tokens[0]) * xMultiplier + xOffset;
|
||||
float scaledY = Integer.parseInt(tokens[1]) * yMultiplier + yOffset;
|
||||
int type = Integer.parseInt(tokens[3]);
|
||||
osu.objects[i] = new OsuHitObject(
|
||||
scaledX, scaledY, Integer.parseInt(tokens[2]),
|
||||
type, Byte.parseByte(tokens[4])
|
||||
);
|
||||
if ((type & OsuHitObject.TYPE_CIRCLE) > 0) {
|
||||
/* 'addition' not implemented. */
|
||||
} else if ((type & OsuHitObject.TYPE_SLIDER) > 0) {
|
||||
// slider curve type and coordinates
|
||||
sliderTokens = tokens[5].split("\\|");
|
||||
osu.objects[i].sliderType = sliderTokens[0].charAt(0);
|
||||
osu.objects[i].sliderX = new float[sliderTokens.length-1];
|
||||
osu.objects[i].sliderY = new float[sliderTokens.length-1];
|
||||
for (int j = 1; j < sliderTokens.length; j++) {
|
||||
sliderXY = sliderTokens[j].split(":");
|
||||
osu.objects[i].sliderX[j-1] = Integer.parseInt(sliderXY[0]) * xMultiplier + xOffset;
|
||||
osu.objects[i].sliderY[j-1] = Integer.parseInt(sliderXY[1]) * yMultiplier + yOffset;
|
||||
}
|
||||
|
||||
osu.objects[i].repeat = Integer.parseInt(tokens[6]);
|
||||
osu.objects[i].pixelLength = Float.parseFloat(tokens[7]);
|
||||
/* edge fields and 'addition' not implemented. */
|
||||
} else { //if ((type & OsuHitObject.TYPE_SPINNER) > 0) {
|
||||
// some 'endTime' fields contain a ':' character (?)
|
||||
int index = tokens[5].indexOf(':');
|
||||
if (index != -1)
|
||||
tokens[5] = tokens[5].substring(0, index);
|
||||
osu.objects[i].endTime = Integer.parseInt(tokens[5]);
|
||||
/* 'addition' not implemented. */
|
||||
}
|
||||
|
||||
// set combo info
|
||||
// - new combo: get next combo index, reset combo number
|
||||
// - else: maintain combo index, increase combo number
|
||||
if ((osu.objects[i].type & OsuHitObject.TYPE_NEWCOMBO) > 0) {
|
||||
comboIndex = (comboIndex + 1) % osu.combo.length;
|
||||
comboNumber = 1;
|
||||
}
|
||||
osu.objects[i].comboIndex = comboIndex;
|
||||
osu.objects[i].comboNumber = comboNumber++;
|
||||
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
osu.objects[objectIndex++] = hitObject;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.error(String.format("Failed to read file '%s'.", osu.getFile().getAbsolutePath()), e);
|
||||
|
|
|
@ -94,15 +94,15 @@ public class Circle {
|
|||
* @param trackPosition the current track position
|
||||
*/
|
||||
public void draw(int trackPosition) {
|
||||
int timeDiff = hitObject.time - trackPosition;
|
||||
int timeDiff = hitObject.getTime() - trackPosition;
|
||||
|
||||
if (timeDiff >= 0) {
|
||||
float x = hitObject.getX(), y = hitObject.getY();
|
||||
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
||||
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale),
|
||||
hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(GameImage.HITCIRCLE_OVERLAY.getImage(), hitObject.x, hitObject.y, Color.white);
|
||||
Utils.drawCentered(GameImage.HITCIRCLE.getImage(), hitObject.x, hitObject.y, color);
|
||||
score.drawSymbolNumber(hitObject.comboNumber, hitObject.x, hitObject.y,
|
||||
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale), x, y, color);
|
||||
Utils.drawCentered(GameImage.HITCIRCLE_OVERLAY.getImage(), x, y, Color.white);
|
||||
Utils.drawCentered(GameImage.HITCIRCLE.getImage(), x, y, color);
|
||||
score.drawSymbolNumber(hitObject.getComboNumber(), x, y,
|
||||
GameImage.HITCIRCLE.getImage().getWidth() * 0.40f / score.getDefaultSymbolImage(0).getHeight());
|
||||
}
|
||||
}
|
||||
|
@ -139,13 +139,15 @@ public class Circle {
|
|||
* @return true if a hit result was processed
|
||||
*/
|
||||
public boolean mousePressed(int x, int y) {
|
||||
double distance = Math.hypot(hitObject.x - x, hitObject.y - y);
|
||||
double distance = Math.hypot(hitObject.getX() - x, hitObject.getY() - y);
|
||||
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||
if (distance < circleRadius) {
|
||||
int result = hitResult(hitObject.time);
|
||||
int result = hitResult(hitObject.getTime());
|
||||
if (result > -1) {
|
||||
score.hitResult(hitObject.time, result, hitObject.x, hitObject.y,
|
||||
color, comboEnd, hitObject.hitSound
|
||||
score.hitResult(
|
||||
hitObject.getTime(), result,
|
||||
hitObject.getX(), hitObject.getY(),
|
||||
color, comboEnd, hitObject.getHitSoundType()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -159,26 +161,27 @@ public class Circle {
|
|||
* @return true if a hit result (miss) was processed
|
||||
*/
|
||||
public boolean update(boolean overlap) {
|
||||
int time = hitObject.getTime();
|
||||
float x = hitObject.getX(), y = hitObject.getY();
|
||||
byte hitSound = hitObject.getHitSoundType();
|
||||
|
||||
int trackPosition = MusicController.getPosition();
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
boolean isAutoMod = GameMod.AUTO.isActive();
|
||||
|
||||
if (overlap || trackPosition > hitObject.time + hitResultOffset[GameScore.HIT_50]) {
|
||||
if (overlap || trackPosition > 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.hitSound);
|
||||
score.hitResult(time, GameScore.HIT_300, x, y, color, comboEnd, 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.hitSound);
|
||||
score.hitResult(time, GameScore.HIT_MISS, x, y, null, comboEnd, hitSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
// "auto" mod: send a perfect hit result
|
||||
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.hitSound);
|
||||
if (Math.abs(trackPosition - time) < hitResultOffset[GameScore.HIT_300]) {
|
||||
score.hitResult(time, GameScore.HIT_300, x, y, color, comboEnd, hitSound);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,8 +155,8 @@ public class Slider {
|
|||
* Constructor.
|
||||
*/
|
||||
public Bezier() {
|
||||
this.order = hitObject.sliderX.length + 1;
|
||||
this.step = 5 / hitObject.pixelLength;
|
||||
this.order = hitObject.getSliderX().length + 1;
|
||||
this.step = 5 / hitObject.getPixelLength();
|
||||
|
||||
// calculate curve points for drawing
|
||||
int N = (int) (1 / step);
|
||||
|
@ -172,7 +172,7 @@ public class Slider {
|
|||
curveY[N] = getY(order - 1);
|
||||
|
||||
// calculate angles (if needed)
|
||||
if (hitObject.repeat > 1) {
|
||||
if (hitObject.getRepeatCount() > 1) {
|
||||
float[] c1 = pointAt(0f);
|
||||
float[] c2 = pointAt(step);
|
||||
startAngle = (float) (Math.atan2(c2[1] - c1[1], c2[0] - c1[0]) * 180 / Math.PI);
|
||||
|
@ -186,14 +186,14 @@ public class Slider {
|
|||
* Returns the x coordinate of the control point at index i.
|
||||
*/
|
||||
private float getX(int i) {
|
||||
return (i == 0) ? hitObject.x : hitObject.sliderX[i - 1];
|
||||
return (i == 0) ? hitObject.getX() : hitObject.getSliderX()[i - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the y coordinate of the control point at index i.
|
||||
*/
|
||||
private float getY(int i) {
|
||||
return (i == 0) ? hitObject.y : hitObject.sliderY[i - 1];
|
||||
return (i == 0) ? hitObject.getY() : hitObject.getSliderY()[i - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -341,7 +341,9 @@ public class Slider {
|
|||
* @param currentObject true if this is the current hit object
|
||||
*/
|
||||
public void draw(int trackPosition, boolean currentObject) {
|
||||
int timeDiff = hitObject.time - trackPosition;
|
||||
float x = hitObject.getX(), y = hitObject.getY();
|
||||
float[] sliderX = hitObject.getSliderX(), sliderY = hitObject.getSliderY();
|
||||
int timeDiff = hitObject.getTime() - trackPosition;
|
||||
|
||||
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||
|
@ -358,36 +360,35 @@ public class Slider {
|
|||
}
|
||||
|
||||
// end circle
|
||||
int lastIndex = hitObject.sliderX.length - 1;
|
||||
Utils.drawCentered(hitCircleOverlay, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], Color.white);
|
||||
Utils.drawCentered(hitCircle, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], color);
|
||||
int lastIndex = sliderX.length - 1;
|
||||
Utils.drawCentered(hitCircleOverlay, sliderX[lastIndex], sliderY[lastIndex], Color.white);
|
||||
Utils.drawCentered(hitCircle, sliderX[lastIndex], sliderY[lastIndex], color);
|
||||
|
||||
// start circle
|
||||
Utils.drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white);
|
||||
Utils.drawCentered(hitCircle, hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(hitCircleOverlay, x, y, Color.white);
|
||||
Utils.drawCentered(hitCircle, x, y, color);
|
||||
if (sliderClicked)
|
||||
; // don't draw current combo number if already clicked
|
||||
else
|
||||
score.drawSymbolNumber(hitObject.comboNumber, hitObject.x, hitObject.y,
|
||||
score.drawSymbolNumber(hitObject.getComboNumber(), x, y,
|
||||
hitCircle.getWidth() * 0.40f / score.getDefaultSymbolImage(0).getHeight());
|
||||
|
||||
// repeats
|
||||
if (hitObject.repeat - 1 > currentRepeats) {
|
||||
if (hitObject.getRepeatCount() - 1 > currentRepeats) {
|
||||
Image arrow = GameImage.REVERSEARROW.getImage();
|
||||
if (currentRepeats % 2 == 0) { // last circle
|
||||
arrow.setRotation(bezier.getEndAngle());
|
||||
arrow.drawCentered(hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex]);
|
||||
arrow.drawCentered(sliderX[lastIndex], sliderY[lastIndex]);
|
||||
} else { // first circle
|
||||
arrow.setRotation(bezier.getStartAngle());
|
||||
arrow.drawCentered(hitObject.x, hitObject.y);
|
||||
arrow.drawCentered(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeDiff >= 0) {
|
||||
// approach circle
|
||||
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
||||
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale),
|
||||
hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale), x, y, color);
|
||||
} else {
|
||||
float[] c = bezier.pointAt(getT(trackPosition, false));
|
||||
|
||||
|
@ -407,7 +408,7 @@ public class Slider {
|
|||
* @return the hit result (GameScore.HIT_* constants)
|
||||
*/
|
||||
public int hitResult() {
|
||||
int lastIndex = hitObject.sliderX.length - 1;
|
||||
int lastIndex = hitObject.getSliderX().length - 1;
|
||||
float tickRatio = (float) ticksHit / tickIntervals;
|
||||
|
||||
int result;
|
||||
|
@ -421,12 +422,12 @@ public class Slider {
|
|||
result = GameScore.HIT_MISS;
|
||||
|
||||
if (currentRepeats % 2 == 0) // last circle
|
||||
score.hitResult(hitObject.time + (int) sliderTimeTotal, result,
|
||||
hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex],
|
||||
color, comboEnd, hitObject.hitSound);
|
||||
score.hitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
|
||||
hitObject.getSliderX()[lastIndex], hitObject.getSliderY()[lastIndex],
|
||||
color, comboEnd, hitObject.getHitSoundType());
|
||||
else // first circle
|
||||
score.hitResult(hitObject.time + (int) sliderTimeTotal, result,
|
||||
hitObject.x, hitObject.y, color, comboEnd, hitObject.hitSound);
|
||||
score.hitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
|
||||
hitObject.getX(), hitObject.getY(), color, comboEnd, hitObject.getHitSoundType());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -442,11 +443,11 @@ public class Slider {
|
|||
if (sliderClicked) // first circle already processed
|
||||
return false;
|
||||
|
||||
double distance = Math.hypot(hitObject.x - x, hitObject.y - y);
|
||||
double distance = Math.hypot(hitObject.getX() - x, hitObject.getY() - y);
|
||||
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||
if (distance < circleRadius) {
|
||||
int trackPosition = MusicController.getPosition();
|
||||
int timeDiff = Math.abs(trackPosition - hitObject.time);
|
||||
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
|
||||
int result = -1;
|
||||
|
@ -459,8 +460,8 @@ public class Slider {
|
|||
|
||||
if (result > -1) {
|
||||
sliderClicked = true;
|
||||
score.sliderTickResult(hitObject.time, result,
|
||||
hitObject.x, hitObject.y, hitObject.hitSound);
|
||||
score.sliderTickResult(hitObject.getTime(), result,
|
||||
hitObject.getX(), hitObject.getY(), hitObject.getHitSoundType());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -476,15 +477,17 @@ public class Slider {
|
|||
* @return true if slider ended
|
||||
*/
|
||||
public boolean update(boolean overlap, int delta, int mouseX, int mouseY) {
|
||||
int repeatCount = hitObject.getRepeatCount();
|
||||
|
||||
// slider time and tick calculations
|
||||
if (sliderTimeTotal == 0f) {
|
||||
// slider time
|
||||
this.sliderTime = game.getBeatLength() * (hitObject.pixelLength / sliderMultiplier) / 100f;
|
||||
this.sliderTimeTotal = sliderTime * hitObject.repeat;
|
||||
this.sliderTime = game.getBeatLength() * (hitObject.getPixelLength() / sliderMultiplier) / 100f;
|
||||
this.sliderTimeTotal = sliderTime * repeatCount;
|
||||
|
||||
// ticks
|
||||
float tickLengthDiv = 100f * sliderMultiplier / sliderTickRate / game.getTimingPointMultiplier();
|
||||
int tickCount = (int) Math.ceil(hitObject.pixelLength / tickLengthDiv) - 1;
|
||||
int tickCount = (int) Math.ceil(hitObject.getPixelLength() / tickLengthDiv) - 1;
|
||||
if (tickCount > 0) {
|
||||
this.ticksT = new float[tickCount];
|
||||
float tickTOffset = 1f / (tickCount + 1);
|
||||
|
@ -494,37 +497,40 @@ public class Slider {
|
|||
}
|
||||
}
|
||||
|
||||
byte hitSound = hitObject.getHitSoundType();
|
||||
int trackPosition = MusicController.getPosition();
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
int lastIndex = hitObject.sliderX.length - 1;
|
||||
int lastIndex = hitObject.getSliderX().length - 1;
|
||||
boolean isAutoMod = GameMod.AUTO.isActive();
|
||||
|
||||
if (!sliderClicked) {
|
||||
int time = hitObject.getTime();
|
||||
|
||||
// start circle time passed
|
||||
if (trackPosition > hitObject.time + hitResultOffset[GameScore.HIT_50]) {
|
||||
if (trackPosition > time + hitResultOffset[GameScore.HIT_50]) {
|
||||
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, hitObject.hitSound);
|
||||
score.sliderTickResult(time, GameScore.HIT_SLIDER30,
|
||||
hitObject.getX(), hitObject.getY(), hitSound);
|
||||
} else
|
||||
score.sliderTickResult(hitObject.time, GameScore.HIT_MISS,
|
||||
hitObject.x, hitObject.y, hitObject.hitSound);
|
||||
score.sliderTickResult(time, GameScore.HIT_MISS,
|
||||
hitObject.getX(), hitObject.getY(), hitSound);
|
||||
}
|
||||
|
||||
// "auto" mod: send a perfect hit result
|
||||
else if (isAutoMod) {
|
||||
if (Math.abs(trackPosition - hitObject.time) < hitResultOffset[GameScore.HIT_300]) {
|
||||
if (Math.abs(trackPosition - time) < hitResultOffset[GameScore.HIT_300]) {
|
||||
ticksHit++;
|
||||
sliderClicked = true;
|
||||
score.sliderTickResult(hitObject.time, GameScore.HIT_SLIDER30,
|
||||
hitObject.x, hitObject.y, hitObject.hitSound);
|
||||
score.sliderTickResult(time, GameScore.HIT_SLIDER30,
|
||||
hitObject.getX(), hitObject.getY(), hitSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// end of slider
|
||||
if (overlap || trackPosition > hitObject.time + sliderTimeTotal) {
|
||||
if (overlap || trackPosition > hitObject.getTime() + sliderTimeTotal) {
|
||||
tickIntervals++;
|
||||
|
||||
// "auto" mod: send a perfect hit result
|
||||
|
@ -533,7 +539,7 @@ public class Slider {
|
|||
|
||||
// check if cursor pressed and within end circle
|
||||
else if (Utils.isGameKeyPressed()) {
|
||||
double distance = Math.hypot(hitObject.sliderX[lastIndex] - mouseX, hitObject.sliderY[lastIndex] - mouseY);
|
||||
double distance = Math.hypot(hitObject.getSliderX()[lastIndex] - mouseX, hitObject.getSliderY()[lastIndex] - mouseY);
|
||||
int followCircleRadius = GameImage.SLIDER_FOLLOWCIRCLE.getImage().getWidth() / 2;
|
||||
if (distance < followCircleRadius)
|
||||
ticksHit++;
|
||||
|
@ -546,7 +552,7 @@ public class Slider {
|
|||
|
||||
// repeats
|
||||
boolean isNewRepeat = false;
|
||||
if (hitObject.repeat - 1 > currentRepeats) {
|
||||
if (repeatCount - 1 > currentRepeats) {
|
||||
float t = getT(trackPosition, true);
|
||||
if (Math.floor(t) > currentRepeats) {
|
||||
currentRepeats++;
|
||||
|
@ -558,8 +564,8 @@ public class Slider {
|
|||
// ticks
|
||||
boolean isNewTick = false;
|
||||
if (ticksT != null &&
|
||||
tickIntervals < (ticksT.length * (currentRepeats + 1)) + hitObject.repeat &&
|
||||
tickIntervals < (ticksT.length * hitObject.repeat) + hitObject.repeat) {
|
||||
tickIntervals < (ticksT.length * (currentRepeats + 1)) + repeatCount &&
|
||||
tickIntervals < (ticksT.length * repeatCount) + repeatCount) {
|
||||
float t = getT(trackPosition, true);
|
||||
if (t - Math.floor(t) >= ticksT[tickIndex]) {
|
||||
tickIntervals++;
|
||||
|
@ -582,11 +588,10 @@ public class Slider {
|
|||
ticksHit++;
|
||||
if (currentRepeats % 2 > 0) // last circle
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30,
|
||||
hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex],
|
||||
hitObject.hitSound);
|
||||
hitObject.getSliderX()[lastIndex], hitObject.getSliderY()[lastIndex], hitSound);
|
||||
else // first circle
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_SLIDER30,
|
||||
c[0], c[1], hitObject.hitSound);
|
||||
c[0], c[1], hitSound);
|
||||
}
|
||||
|
||||
// held during new tick
|
||||
|
@ -599,7 +604,7 @@ public class Slider {
|
|||
followCircleActive = false;
|
||||
|
||||
if (isNewRepeat)
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, hitObject.hitSound);
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, hitSound);
|
||||
if (isNewTick)
|
||||
score.sliderTickResult(trackPosition, GameScore.HIT_MISS, 0, 0, (byte) -1);
|
||||
}
|
||||
|
@ -614,7 +619,7 @@ public class Slider {
|
|||
* @return the t value: raw [0, repeats] or looped [0, 1]
|
||||
*/
|
||||
public float getT(int trackPosition, boolean raw) {
|
||||
float t = (trackPosition - hitObject.time) / sliderTime;
|
||||
float t = (trackPosition - hitObject.getTime()) / sliderTime;
|
||||
if (raw)
|
||||
return t;
|
||||
else {
|
||||
|
|
|
@ -78,7 +78,8 @@ public class Spinner {
|
|||
|
||||
Image spinnerCircle = GameImage.SPINNER_CIRCLE.getImage();
|
||||
GameImage.SPINNER_CIRCLE.setImage(spinnerCircle.getScaledCopy(height * 9 / 10, height * 9 / 10));
|
||||
GameImage.SPINNER_APPROACHCIRCLE.setImage(GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(spinnerCircle.getWidth(), spinnerCircle.getHeight()));
|
||||
GameImage.SPINNER_APPROACHCIRCLE.setImage(GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(
|
||||
spinnerCircle.getWidth(), spinnerCircle.getHeight()));
|
||||
GameImage.SPINNER_METRE.setImage(GameImage.SPINNER_METRE.getImage().getScaledCopy(width, height));
|
||||
}
|
||||
|
||||
|
@ -94,7 +95,7 @@ public class Spinner {
|
|||
|
||||
// calculate rotations needed
|
||||
float spinsPerMinute = 100 + (score.getDifficulty() * 15);
|
||||
rotationsNeeded = spinsPerMinute * (hitObject.endTime - hitObject.time) / 60000f;
|
||||
rotationsNeeded = spinsPerMinute * (hitObject.getEndTime() - hitObject.getTime()) / 60000f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +104,7 @@ public class Spinner {
|
|||
* @param g the graphics context
|
||||
*/
|
||||
public void draw(int trackPosition, Graphics g) {
|
||||
int timeDiff = hitObject.time - trackPosition;
|
||||
int timeDiff = hitObject.getTime() - trackPosition;
|
||||
boolean spinnerComplete = (rotations >= rotationsNeeded);
|
||||
|
||||
// TODO: draw "OSU!" image after spinner ends
|
||||
|
@ -126,8 +127,9 @@ public class Spinner {
|
|||
spinnerMetreSub.draw(0, height - spinnerMetreSub.getHeight());
|
||||
|
||||
// main spinner elements
|
||||
float approachScale = 1 - ((float) timeDiff / (hitObject.getTime() - hitObject.getEndTime()));
|
||||
GameImage.SPINNER_CIRCLE.getImage().drawCentered(width / 2, height / 2);
|
||||
GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(1 - ((float) timeDiff / (hitObject.time - hitObject.endTime))).drawCentered(width / 2, height / 2);
|
||||
GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(width / 2, height / 2);
|
||||
GameImage.SPINNER_SPIN.getImage().drawCentered(width / 2, height * 3 / 4);
|
||||
|
||||
if (spinnerComplete) {
|
||||
|
@ -158,7 +160,7 @@ public class Spinner {
|
|||
else
|
||||
result = GameScore.HIT_MISS;
|
||||
|
||||
score.hitResult(hitObject.endTime, result, width / 2, height / 2,
|
||||
score.hitResult(hitObject.getEndTime(), result, width / 2, height / 2,
|
||||
Color.transparent, true, (byte) -1);
|
||||
return result;
|
||||
}
|
||||
|
@ -177,7 +179,7 @@ public class Spinner {
|
|||
return true;
|
||||
|
||||
// end of spinner
|
||||
if (trackPosition > hitObject.endTime) {
|
||||
if (trackPosition > hitObject.getEndTime()) {
|
||||
hitResult();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -316,8 +316,8 @@ public class Game extends BasicGameState {
|
|||
|
||||
// skip beginning
|
||||
if (objectIndex == 0 &&
|
||||
osu.objects[0].time - SKIP_OFFSET > 5000 &&
|
||||
trackPosition < osu.objects[0].time - SKIP_OFFSET)
|
||||
osu.objects[0].getTime() - SKIP_OFFSET > 5000 &&
|
||||
trackPosition < osu.objects[0].getTime() - SKIP_OFFSET)
|
||||
skipButton.draw();
|
||||
|
||||
if (isLeadIn())
|
||||
|
@ -325,7 +325,7 @@ public class Game extends BasicGameState {
|
|||
|
||||
// countdown
|
||||
if (osu.countdown > 0) { // TODO: implement half/double rate settings
|
||||
int timeDiff = osu.objects[0].time - trackPosition;
|
||||
int timeDiff = osu.objects[0].getTime() - trackPosition;
|
||||
if (timeDiff >= 500 && timeDiff < 3000) {
|
||||
if (timeDiff >= 1500) {
|
||||
GameImage.COUNTDOWN_READY.getImage().drawCentered(width / 2, height / 2);
|
||||
|
@ -368,18 +368,18 @@ public class Game extends BasicGameState {
|
|||
|
||||
// draw hit objects in reverse order, or else overlapping objects are unreadable
|
||||
Stack<Integer> stack = new Stack<Integer>();
|
||||
for (int i = objectIndex; i < osu.objects.length && osu.objects[i].time < trackPosition + approachTime; i++)
|
||||
for (int i = objectIndex; i < osu.objects.length && osu.objects[i].getTime() < trackPosition + approachTime; i++)
|
||||
stack.add(i);
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
int i = stack.pop();
|
||||
OsuHitObject hitObject = osu.objects[i];
|
||||
|
||||
if ((hitObject.type & OsuHitObject.TYPE_CIRCLE) > 0)
|
||||
if (hitObject.isCircle())
|
||||
circles.get(i).draw(trackPosition);
|
||||
else if ((hitObject.type & OsuHitObject.TYPE_SLIDER) > 0)
|
||||
else if (hitObject.isSlider())
|
||||
sliders.get(i).draw(trackPosition, stack.isEmpty());
|
||||
else if ((hitObject.type & OsuHitObject.TYPE_SPINNER) > 0) {
|
||||
else if (hitObject.isSpinner()) {
|
||||
if (stack.isEmpty()) // only draw spinner at objectIndex
|
||||
spinners.get(i).draw(trackPosition, g);
|
||||
else
|
||||
|
@ -487,7 +487,7 @@ public class Game extends BasicGameState {
|
|||
|
||||
// song beginning
|
||||
if (objectIndex == 0) {
|
||||
if (trackPosition < osu.objects[0].time)
|
||||
if (trackPosition < osu.objects[0].getTime())
|
||||
return; // nothing to do here
|
||||
}
|
||||
|
||||
|
@ -544,20 +544,20 @@ public class Game extends BasicGameState {
|
|||
}
|
||||
|
||||
// update objects (loop in unlikely event of any skipped indexes)
|
||||
while (objectIndex < osu.objects.length && trackPosition > osu.objects[objectIndex].time) {
|
||||
while (objectIndex < osu.objects.length && trackPosition > osu.objects[objectIndex].getTime()) {
|
||||
OsuHitObject hitObject = osu.objects[objectIndex];
|
||||
|
||||
// check if we've already passed the next object's start time
|
||||
boolean overlap = (objectIndex + 1 < osu.objects.length &&
|
||||
trackPosition > osu.objects[objectIndex + 1].time - hitResultOffset[GameScore.HIT_300]);
|
||||
trackPosition > osu.objects[objectIndex + 1].getTime() - hitResultOffset[GameScore.HIT_300]);
|
||||
|
||||
// check completion status of the hit object
|
||||
boolean done = false;
|
||||
if ((hitObject.type & OsuHitObject.TYPE_CIRCLE) > 0)
|
||||
if (hitObject.isCircle())
|
||||
done = circles.get(objectIndex).update(overlap);
|
||||
else if ((hitObject.type & OsuHitObject.TYPE_SLIDER) > 0)
|
||||
else if (hitObject.isSlider())
|
||||
done = sliders.get(objectIndex).update(overlap, delta, input.getMouseX(), input.getMouseY());
|
||||
else if ((hitObject.type & OsuHitObject.TYPE_SPINNER) > 0)
|
||||
else if (hitObject.isSpinner())
|
||||
done = spinners.get(objectIndex).update(overlap, delta, input.getMouseX(), input.getMouseY());
|
||||
|
||||
// increment object index?
|
||||
|
@ -586,7 +586,7 @@ public class Game extends BasicGameState {
|
|||
// pause game
|
||||
int trackPosition = MusicController.getPosition();
|
||||
if (pauseTime < 0 && breakTime <= 0 &&
|
||||
trackPosition >= osu.objects[0].time &&
|
||||
trackPosition >= osu.objects[0].getTime() &&
|
||||
!GameMod.AUTO.isActive()) {
|
||||
pausedMouseX = input.getMouseX();
|
||||
pausedMouseY = input.getMouseY();
|
||||
|
@ -642,7 +642,7 @@ public class Game extends BasicGameState {
|
|||
// skip to checkpoint
|
||||
MusicController.setPosition(checkpoint);
|
||||
while (objectIndex < osu.objects.length &&
|
||||
osu.objects[objectIndex++].time <= MusicController.getPosition())
|
||||
osu.objects[objectIndex++].getTime() <= MusicController.getPosition())
|
||||
;
|
||||
objectIndex--;
|
||||
} catch (SlickException e) {
|
||||
|
@ -692,14 +692,14 @@ public class Game extends BasicGameState {
|
|||
return;
|
||||
|
||||
// circles
|
||||
if ((hitObject.type & OsuHitObject.TYPE_CIRCLE) > 0) {
|
||||
if (hitObject.isCircle()) {
|
||||
boolean hit = circles.get(objectIndex).mousePressed(x, y);
|
||||
if (hit)
|
||||
objectIndex++;
|
||||
}
|
||||
|
||||
// sliders
|
||||
else if ((hitObject.type & OsuHitObject.TYPE_SLIDER) > 0)
|
||||
else if (hitObject.isSlider())
|
||||
sliders.get(objectIndex).mousePressed(x, y);
|
||||
}
|
||||
|
||||
|
@ -733,15 +733,15 @@ public class Game extends BasicGameState {
|
|||
|
||||
// is this the last note in the combo?
|
||||
boolean comboEnd = false;
|
||||
if (i + 1 < osu.objects.length &&
|
||||
(osu.objects[i + 1].type & OsuHitObject.TYPE_NEWCOMBO) > 0)
|
||||
if (i + 1 < osu.objects.length && osu.objects[i + 1].isNewCombo())
|
||||
comboEnd = true;
|
||||
|
||||
if ((hitObject.type & OsuHitObject.TYPE_CIRCLE) > 0) {
|
||||
circles.put(i, new Circle(hitObject, this, score, osu.combo[hitObject.comboIndex], comboEnd));
|
||||
} else if ((hitObject.type & OsuHitObject.TYPE_SLIDER) > 0) {
|
||||
sliders.put(i, new Slider(hitObject, this, score, osu.combo[hitObject.comboIndex], comboEnd));
|
||||
} else if ((hitObject.type & OsuHitObject.TYPE_SPINNER) > 0) {
|
||||
Color color = osu.combo[hitObject.getComboIndex()];
|
||||
if (hitObject.isCircle()) {
|
||||
circles.put(i, new Circle(hitObject, this, score, color, comboEnd));
|
||||
} else if (hitObject.isSlider()) {
|
||||
sliders.put(i, new Slider(hitObject, this, score, color, comboEnd));
|
||||
} else if (hitObject.isSpinner()) {
|
||||
spinners.put(i, new Spinner(hitObject, this, score));
|
||||
}
|
||||
}
|
||||
|
@ -794,15 +794,16 @@ public class Game extends BasicGameState {
|
|||
* @return true if skipped, false otherwise
|
||||
*/
|
||||
private boolean skipIntro() {
|
||||
int firstObjectTime = osu.objects[0].getTime();
|
||||
int trackPosition = MusicController.getPosition();
|
||||
if (objectIndex == 0 &&
|
||||
osu.objects[0].time - SKIP_OFFSET > 4000 &&
|
||||
trackPosition < osu.objects[0].time - SKIP_OFFSET) {
|
||||
firstObjectTime - SKIP_OFFSET > 4000 &&
|
||||
trackPosition < firstObjectTime - SKIP_OFFSET) {
|
||||
if (isLeadIn()) {
|
||||
leadInTime = 0;
|
||||
MusicController.resume();
|
||||
}
|
||||
MusicController.setPosition(osu.objects[0].time - SKIP_OFFSET);
|
||||
MusicController.setPosition(firstObjectTime - SKIP_OFFSET);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
return true;
|
||||
}
|
||||
|
@ -883,16 +884,6 @@ public class Game extends BasicGameState {
|
|||
float overallDifficulty = osu.overallDifficulty;
|
||||
float HPDrainRate = osu.HPDrainRate;
|
||||
|
||||
// fixed difficulty overrides
|
||||
if (Options.getFixedCS() > 0f)
|
||||
circleSize = Options.getFixedCS();
|
||||
if (Options.getFixedAR() > 0f)
|
||||
approachRate = Options.getFixedAR();
|
||||
if (Options.getFixedOD() > 0f)
|
||||
overallDifficulty = Options.getFixedOD();
|
||||
if (Options.getFixedHP() > 0f)
|
||||
HPDrainRate = Options.getFixedHP();
|
||||
|
||||
// "Hard Rock" modifiers
|
||||
if (GameMod.HARD_ROCK.isActive()) {
|
||||
circleSize = Math.min(circleSize * 1.4f, 10);
|
||||
|
@ -909,6 +900,16 @@ public class Game extends BasicGameState {
|
|||
HPDrainRate /= 2f;
|
||||
}
|
||||
|
||||
// fixed difficulty overrides
|
||||
if (Options.getFixedCS() > 0f)
|
||||
circleSize = Options.getFixedCS();
|
||||
if (Options.getFixedAR() > 0f)
|
||||
approachRate = Options.getFixedAR();
|
||||
if (Options.getFixedOD() > 0f)
|
||||
overallDifficulty = Options.getFixedOD();
|
||||
if (Options.getFixedHP() > 0f)
|
||||
HPDrainRate = Options.getFixedHP();
|
||||
|
||||
// initialize objects
|
||||
Circle.init(container, circleSize);
|
||||
Slider.init(container, circleSize, osu);
|
||||
|
|
Loading…
Reference in New Issue
Block a user