From 35769b31c77ff97e2b77631a6f504e0671ca6d3e Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 21 Dec 2017 22:43:42 +0100 Subject: [PATCH] attempt to keep track of scoring for each player --- src/awlex/ospu/FakeGameObject.java | 10 ++ src/itdelatrisu/opsu/GameData.java | 4 +- src/itdelatrisu/opsu/objects/Circle.java | 5 + src/itdelatrisu/opsu/objects/DummyObject.java | 8 +- src/itdelatrisu/opsu/objects/GameObject.java | 3 + src/itdelatrisu/opsu/objects/Slider.java | 5 + src/itdelatrisu/opsu/objects/Spinner.java | 5 + src/itdelatrisu/opsu/states/Game.java | 10 +- src/yugecin/opsudance/ReplayPlayback.java | 123 +++++++++++++++++- 9 files changed, 167 insertions(+), 6 deletions(-) diff --git a/src/awlex/ospu/FakeGameObject.java b/src/awlex/ospu/FakeGameObject.java index 9781285d..0ce5c963 100644 --- a/src/awlex/ospu/FakeGameObject.java +++ b/src/awlex/ospu/FakeGameObject.java @@ -4,6 +4,7 @@ package awlex.ospu; * Created by Awlex on 10.10.2016. */ +import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.objects.GameObject; import itdelatrisu.opsu.objects.curves.Vec2f; import org.newdawn.slick.Color; @@ -35,6 +36,15 @@ public class FakeGameObject extends GameObject { this.start.y = this.end.y = (start.end.y + end.start.y) / 2; } + @Override + public GameObject clone(GameData a) { + FakeGameObject o = new FakeGameObject(); + o.halfTime = this.halfTime; + o.start = this.start; + o.end = this.end; + return o; + } + @Override public void draw(Graphics g, int trackPosition, boolean mirrored) { diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 5e72fdd5..96e35cd6 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -170,7 +170,7 @@ public class GameData { HIT_ANIMATION_RESULT = 12; // not a hit result /** Hit result-related images (indexed by HIT_* constants to HIT_MAX). */ - private Image[] hitResults; + protected Image[] hitResults; /** Counts of each hit result so far (indexed by HIT_* constants to HIT_MAX). */ private int[] hitResultCount; @@ -1409,7 +1409,7 @@ public class GameData { * @param noIncrementCombo if the combo should not be incremented by this result * @return the actual hit result (HIT_* constants) */ - private int handleHitResult(int time, int result, float x, float y, Color color, boolean end, + protected int handleHitResult(int time, int result, float x, float y, Color color, boolean end, HitObject hitObject, HitObjectType hitResultType, int repeat, boolean noIncrementCombo) { // update health, score, and combo streak based on hit result int hitValue = 0; diff --git a/src/itdelatrisu/opsu/objects/Circle.java b/src/itdelatrisu/opsu/objects/Circle.java index 729e095c..57333094 100644 --- a/src/itdelatrisu/opsu/objects/Circle.java +++ b/src/itdelatrisu/opsu/objects/Circle.java @@ -83,6 +83,11 @@ public class Circle extends GameObject { super.updateStartEndPositions(time); } + @Override + public GameObject clone(GameData data) { + return new Circle(hitObject, game, data, comboColorIndex, comboEnd); + } + @Override public void draw(Graphics g, int trackPosition, boolean mirror) { Color orig = color; diff --git a/src/itdelatrisu/opsu/objects/DummyObject.java b/src/itdelatrisu/opsu/objects/DummyObject.java index ce5adebd..9f247e15 100644 --- a/src/itdelatrisu/opsu/objects/DummyObject.java +++ b/src/itdelatrisu/opsu/objects/DummyObject.java @@ -18,6 +18,7 @@ package itdelatrisu.opsu.objects; +import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.beatmap.HitObject; import itdelatrisu.opsu.objects.curves.Vec2f; @@ -29,7 +30,7 @@ import org.newdawn.slick.Graphics; */ public class DummyObject extends GameObject { /** The associated HitObject. */ - private HitObject hitObject; + public final HitObject hitObject; /** The scaled starting x, y coordinates. */ private float x, y; @@ -49,6 +50,11 @@ public class DummyObject extends GameObject { updateStartEndPositions(0); } + @Override + public GameObject clone(GameData a) { + return new DummyObject(this.hitObject); + } + @Override public void draw(Graphics g, int trackPosition, boolean mirror) {} diff --git a/src/itdelatrisu/opsu/objects/GameObject.java b/src/itdelatrisu/opsu/objects/GameObject.java index 039e8a3c..6c75f221 100644 --- a/src/itdelatrisu/opsu/objects/GameObject.java +++ b/src/itdelatrisu/opsu/objects/GameObject.java @@ -18,6 +18,7 @@ package itdelatrisu.opsu.objects; +import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.objects.curves.Vec2f; import org.newdawn.slick.Color; @@ -114,4 +115,6 @@ public abstract class GameObject { return hue; } + public abstract GameObject clone(GameData data); + } diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index eca527e4..3b08298f 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -189,6 +189,11 @@ public class Slider extends GameObject { repeats = hitObject.getRepeatCount(); } + @Override + public GameObject clone(GameData data) { + return new Slider(hitObject, game, data, comboColorIndex, comboEnd); + } + @Override public void draw(Graphics g, int trackPosition, boolean mirror) { if (trackPosition > getEndTime()) { diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index a5a0bb46..1975b086 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -173,6 +173,11 @@ public class Spinner extends GameObject { rotationsNeeded = spinsPerMinute * (hitObject.getEndTime() - hitObject.getTime()) / 60000f; } + @Override + public GameObject clone(GameData data) { + return new Spinner(hitObject, game, data); + } + @Override public void draw(Graphics g, int trackPosition, boolean mirror) { if (mirror) { diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index f54f2532..64ad2a2a 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -726,7 +726,7 @@ public class Game extends ComplexOpsuState { g.setColor(Color.black); g.fillRect(ReplayPlayback.SQSIZE * 2, 0, ReplayPlayback.SQSIZE * 2, displayContainer.height); for (ReplayPlayback replayPlayback : replays) { - replayPlayback.render(displayContainer.renderDelta, g, i++, trackPosition); + replayPlayback.render(beatmap, hitResultOffset, displayContainer.renderDelta, g, i++, trackPosition); } super.render(g); @@ -1718,6 +1718,14 @@ public class Game extends ComplexOpsuState { } } + for (ReplayPlayback replayPlayback : replays) { + GameObject[] objs = new GameObject[gameObjects.length]; + for (int i = 0; i < objs.length; i++) { + objs[i] = gameObjects[i].clone(replayPlayback.new GData()); + } + replayPlayback.setGameObjects(objs); + } + Dancer.instance.setGameObjects(gameObjects); storyboardOverlay.setGameObjects(gameObjects); if (!skippedToCheckpoint) { diff --git a/src/yugecin/opsudance/ReplayPlayback.java b/src/yugecin/opsudance/ReplayPlayback.java index 58f12526..86ac9d7f 100644 --- a/src/yugecin/opsudance/ReplayPlayback.java +++ b/src/yugecin/opsudance/ReplayPlayback.java @@ -17,12 +17,18 @@ */ package yugecin.opsudance; +import itdelatrisu.opsu.GameData; +import itdelatrisu.opsu.beatmap.Beatmap; +import itdelatrisu.opsu.beatmap.HitObject; +import itdelatrisu.opsu.objects.GameObject; +import itdelatrisu.opsu.objects.curves.Curve; import itdelatrisu.opsu.replay.Replay; import itdelatrisu.opsu.replay.ReplayFrame; import itdelatrisu.opsu.ui.Cursor; import itdelatrisu.opsu.ui.Fonts; import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; +import org.newdawn.slick.Image; import yugecin.opsudance.core.DisplayContainer; public class ReplayPlayback { @@ -39,6 +45,12 @@ public class ReplayPlayback { private boolean hr; private String player; + private GameObject[] gameObjects; + private int objectIndex = 0; + private int lastkeys = 0; + private Image hitImage; + private int hitImageTimer = 0; + public ReplayPlayback(DisplayContainer container, Replay replay, Color color) { this.container = container; this.replay = replay; @@ -89,16 +101,61 @@ public class ReplayPlayback { this.player = replay.playerName + this.player; } + public void setGameObjects(GameObject[] gameObjects) { + this.gameObjects = gameObjects; + } + public void resetFrameIndex() { frameIndex = 0; currentFrame = replay.frames[frameIndex++]; nextFrame = replay.frames[frameIndex]; } - public void render(int renderdelta, Graphics g, int ypos, int time) { + private void sendKeys(Beatmap beatmap, int trackPosition) { + if (objectIndex >= gameObjects.length) // nothing to do here + return; + + int deltakeys = (currentFrame.getKeys() & ~this.lastkeys); + if (deltakeys == ReplayFrame.KEY_NONE) { + return; + } + this.lastkeys = currentFrame.getKeys(); + + HitObject hitObject = beatmap.objects[objectIndex]; + + // circles + if (hitObject.isCircle() && gameObjects[objectIndex].mousePressed(currentFrame.getScaledX(), currentFrame.getScaledY(), trackPosition)) + objectIndex++; // circle hit + + // sliders + else if (hitObject.isSlider()) + gameObjects[objectIndex].mousePressed(currentFrame.getScaledX(), currentFrame.getScaledY(), trackPosition); + } + + private void update(int trackPosition, Beatmap beatmap, int[] hitResultOffset, int delta) { + boolean keyPressed = currentFrame.getKeys() != ReplayFrame.KEY_NONE; + while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) { + // check if we've already passed the next object's start time + boolean overlap = (objectIndex + 1 < gameObjects.length && + trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]); + + // update hit object and check completion status + if (gameObjects[objectIndex].update(overlap, delta, currentFrame.getScaledX(), currentFrame.getScaledY(), keyPressed, trackPosition)) { + objectIndex++; // done, so increment object index + } else + break; + } + } + + public void render(Beatmap beatmap, int[] hitResultOffset, int renderdelta, Graphics g, int ypos, int time) { + if (objectIndex >= gameObjects.length) { + return; + } + while (nextFrame != null && nextFrame.getTime() < time) { currentFrame = nextFrame; processKeys(); + sendKeys(beatmap, time); frameIndex++; if (frameIndex >= replay.frames.length) { nextFrame = null; @@ -107,6 +164,8 @@ public class ReplayPlayback { nextFrame = replay.frames[frameIndex]; } processKeys(); + sendKeys(beatmap, time); + update(time, beatmap, hitResultOffset, renderdelta); g.setColor(color); ypos *= (SQSIZE + 5); for (int i = 0; i < 4; i++) { @@ -115,7 +174,11 @@ public class ReplayPlayback { } keydelay[i] -= renderdelta; } - Fonts.SMALLBOLD.drawString(SQSIZE * 5, ypos, this.player, color); + Fonts.SMALLBOLD.drawString(SQSIZE * 5, ypos, this.player + " " + this.objectIndex, color); + int namewidth = Fonts.SMALLBOLD.getWidth(this.player); + if (hitImage != null) { + hitImage.draw(SQSIZE * 5 + namewidth + SQSIZE * 2, ypos + SQSIZE / 2); + } int y = currentFrame.getScaledY(); if (hr) { y = container.height - y; @@ -141,4 +204,60 @@ public class ReplayPlayback { } } + private GData _data; + public class GData extends GameData { + + public GData() { + super(); + this.loadImages(); + _data = this; + } + + @Override + public void sendSliderRepeatResult(int time, float x, float y, Color color, Curve curve, HitObjectType type) { + // ? + } + + @Override + public void sendSliderStartResult(int time, float x, float y, Color color, Color mirrorColor, boolean expand) { + // ? + } + + @Override + public void sendSliderTickResult(int time, int result, float x, float y, HitObject hitObject, int repeat) { + if (result == HIT_MISS) { + + } + } + + @Override + public void sendHitResult(int time, int result, float x, float y, Color color, boolean end, HitObject hitObject, HitObjectType hitResultType, boolean expand, int repeat, Curve curve, boolean sliderHeldToEnd) { + sendHitResult(time, result, x, y, color, end, hitObject, hitResultType, expand, repeat, curve, sliderHeldToEnd, true); + } + + @Override + public void sendHitResult(int time, int result, float x, float y, Color color, boolean end, HitObject hitObject, HitObjectType hitResultType, boolean expand, int repeat, Curve curve, boolean sliderHeldToEnd, boolean handleResult) { + int hitResult = HIT_300; + + if (handleResult) { + hitResult = handleHitResult(time, result, x, y, color, end, hitObject, + hitResultType, repeat, (curve != null && !sliderHeldToEnd)); + } + + if ((hitResult == HIT_300 || hitResult == HIT_300G || hitResult == HIT_300K)) { + return; + } + + if (hitResult < hitResults.length) { + hitImageTimer = 0; + hitImage = hitResults[hitResult].getScaledCopy(SQSIZE, SQSIZE); + } + } + + @Override + public void addHitError(int time, int x, int y, int timeDiff) { + //? + } + } + }