Exemple #1
0
 @Override
 public float[] getPointAt(int trackPosition) {
   if (trackPosition <= hitObject.getTime()) return new float[] {x, y};
   else if (trackPosition >= hitObject.getTime() + sliderTimeTotal) {
     if (hitObject.getRepeatCount() % 2 == 0) return new float[] {x, y};
     else return curve.pointAt(1);
   } else return curve.pointAt(getT(trackPosition, false));
 }
Exemple #2
0
  /**
   * Calculates the slider hit result.
   *
   * @return the hit result (GameData.HIT_* constants)
   */
  private int hitResult() {
    /*
    	time     scoredelta score-hit-initial-tick= unaccounted
    	(1/4   - 1)		396 - 300 - 30	 		46
    	(1+1/4 - 2)		442 - 300 - 30 - 10
    	(2+1/4 - 3)		488 - 300 - 30 - 2*10	896 (408)5x
    	(3+1/4 - 4)		534 - 300 - 30 - 3*10
    	(4+1/4 - 5)		580 - 300 - 30 - 4*10
    	(5+1/4 - 6) 	626	- 300 - 30 - 5*10
    	(6+1/4 - 7)		672	- 300 - 30 - 6*10

    	difficultyMulti = 3	(+36 per combo)

    	score =
    	(t)ticks(10) * nticks +
    	(h)hitValue
    	(c)combo (hitValue/25 * difficultyMultiplier*(combo-1))
    	(i)initialHit (30) +
    	(f)finalHit(30) +

    	s     t       h          c     i     f
    	626 - 10*5 - 300  - 276(-216 - 30 - 30) (all)(7x)
    	240 - 10*5 - 100  - 90 (-60     <- 30>) (no final or initial)(6x)

    	218 - 10*4 - 100  - 78 (-36       - 30) (4 tick no initial)(5x)
    	196 - 10*3 - 100  - 66 (-24       - 30 ) (3 tick no initial)(4x)
    	112 - 10*2 - 50   - 42 (-12       - 30 ) (2 tick no initial)(3x)
    	96  - 10   - 50   - 36 ( -6       - 30 ) (1 tick no initial)(2x)

    	206 - 10*4 - 100  - 66 (-36       - 30 ) (4 tick no initial)(4x)
    	184 - 10*3 - 100  - 54 (-24       - 30 ) (3 tick no initial)(3x)
    	90  - 10   - 50   - 30 (          - 30 ) (1 tick no initial)(0x)

    	194 - 10*4 - 100  - 54 (-24       - 30 ) (4 tick no initial)(3x)

    	170 - 10*4 - 100  - 30 (     - 30      ) (4 tick no final)(0x)
    	160 - 10*3 - 100  - 30 (     - 30      ) (3 tick no final)(0x)
    	100 - 10*2 - 50   - 30 (     - 30      ) (2 tick no final)(0x)

    	198 - 10*5 - 100  - 48 (-36            ) (no initial and final)(5x)
    	110        - 50   -    (     - 30 - 30 ) (final and initial no tick)(0x)
    	80         - 50   -    (       <- 30>  ) (only final or initial)(0x)

    	140 - 10*4 - 100  - 0                    (4 ticks only)(0x)
    	80  - 10*3 - 50   - 0                    (3 tick only)(0x)
    	70  - 10*2 - 50   - 0                    (2 tick only)(0x)
    	60  - 10   - 50   - 0                    (1 tick only)(0x)
    */
    float tickRatio = (float) ticksHit / tickIntervals;

    int result;
    if (tickRatio >= 1.0f) result = GameData.HIT_300;
    else if (tickRatio >= 0.5f) result = GameData.HIT_100;
    else if (tickRatio > 0f) result = GameData.HIT_50;
    else result = GameData.HIT_MISS;

    float cx, cy;
    HitObjectType type;
    if (currentRepeats % 2 == 0) { // last circle
      float[] lastPos = curve.pointAt(1);
      cx = lastPos[0];
      cy = lastPos[1];
      type = HitObjectType.SLIDER_LAST;
    } else { // first circle
      cx = x;
      cy = y;
      type = HitObjectType.SLIDER_FIRST;
    }
    data.hitResult(
        hitObject.getTime() + (int) sliderTimeTotal,
        result,
        cx,
        cy,
        color,
        comboEnd,
        hitObject,
        type,
        sliderHeldToEnd,
        currentRepeats + 1,
        curve,
        sliderHeldToEnd);

    return result;
  }
Exemple #3
0
  @Override
  public boolean update(
      boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
    int repeatCount = hitObject.getRepeatCount();
    int[] hitResultOffset = game.getHitResultOffsets();
    boolean isAutoMod = GameMod.AUTO.isActive();

    if (!sliderClickedInitial) {
      int time = hitObject.getTime();

      // start circle time passed
      if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
        sliderClickedInitial = true;
        if (isAutoMod) { // "auto" mod: catch any missed notes due to lag
          ticksHit++;
          data.sliderTickResult(time, GameData.HIT_SLIDER30, x, y, hitObject, currentRepeats);
        } else data.sliderTickResult(time, GameData.HIT_MISS, x, y, hitObject, currentRepeats);
      }

      // "auto" mod: send a perfect hit result
      else if (isAutoMod) {
        if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) {
          ticksHit++;
          sliderClickedInitial = true;
          data.sliderTickResult(time, GameData.HIT_SLIDER30, x, y, hitObject, currentRepeats);
        }
      }

      // "relax" mod: click automatically
      else if (GameMod.RELAX.isActive() && trackPosition >= time)
        mousePressed(mouseX, mouseY, trackPosition);
    }

    // end of slider
    if (trackPosition > hitObject.getTime() + sliderTimeTotal) {
      tickIntervals++;

      // check if cursor pressed and within end circle
      if (keyPressed || GameMod.RELAX.isActive()) {
        float[] c = curve.pointAt(getT(trackPosition, false));
        double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
        if (distance < followRadius) sliderHeldToEnd = true;
      }

      // final circle hit
      if (sliderHeldToEnd) ticksHit++;

      // "auto" mod: always send a perfect hit result
      if (isAutoMod) ticksHit = tickIntervals;

      // calculate and send slider result
      hitResult();
      return true;
    }

    // repeats
    boolean isNewRepeat = false;
    if (repeatCount - 1 > currentRepeats) {
      float t = getT(trackPosition, true);
      if (Math.floor(t) > currentRepeats) {
        currentRepeats++;
        tickIntervals++;
        isNewRepeat = true;
      }
    }

    // ticks
    boolean isNewTick = false;
    if (ticksT != null
        && tickIntervals < (ticksT.length * (currentRepeats + 1)) + repeatCount
        && tickIntervals < (ticksT.length * repeatCount) + repeatCount) {
      float t = getT(trackPosition, true);
      if (t - Math.floor(t) >= ticksT[tickIndex]) {
        tickIntervals++;
        tickIndex = (tickIndex + 1) % ticksT.length;
        isNewTick = true;
      }
    }

    // holding slider...
    float[] c = curve.pointAt(getT(trackPosition, false));
    double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
    if (((keyPressed || GameMod.RELAX.isActive()) && distance < followRadius) || isAutoMod) {
      // mouse pressed and within follow circle
      followCircleActive = true;
      data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER);

      // held during new repeat
      if (isNewRepeat) {
        ticksHit++;
        if (currentRepeats % 2 > 0) { // last circle
          int lastIndex = hitObject.getSliderX().length;
          data.sliderTickResult(
              trackPosition,
              GameData.HIT_SLIDER30,
              curve.getX(lastIndex),
              curve.getY(lastIndex),
              hitObject,
              currentRepeats);
        } else // first circle
        data.sliderTickResult(
              trackPosition, GameData.HIT_SLIDER30, c[0], c[1], hitObject, currentRepeats);
      }

      // held during new tick
      if (isNewTick) {
        ticksHit++;
        data.sliderTickResult(
            trackPosition, GameData.HIT_SLIDER10, c[0], c[1], hitObject, currentRepeats);
      }

      // held near end of slider
      if (!sliderHeldToEnd
          && trackPosition
              > hitObject.getTime() + sliderTimeTotal - hitResultOffset[GameData.HIT_300])
        sliderHeldToEnd = true;
    } else {
      followCircleActive = false;

      if (isNewRepeat)
        data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, hitObject, currentRepeats);
      if (isNewTick)
        data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, hitObject, currentRepeats);
    }

    return false;
  }
Exemple #4
0
  @Override
  public void draw(Graphics g, int trackPosition) {
    int timeDiff = hitObject.getTime() - trackPosition;
    float scale = timeDiff / (float) game.getApproachTime();
    float fadeinScale = (timeDiff - game.getApproachTime() + FADE_IN_TIME) / (float) FADE_IN_TIME;
    float approachScale = 1 + scale * 3;
    float alpha = Utils.clamp(1 - fadeinScale, 0, 1);
    boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();

    float oldAlpha = Utils.COLOR_WHITE_FADE.a;
    Utils.COLOR_WHITE_FADE.a = color.a = alpha;
    Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
    Image hitCircle = GameImage.HITCIRCLE.getImage();
    float[] endPos = curve.pointAt(1);

    curve.draw(color);
    color.a = alpha;

    // end circle
    hitCircle.drawCentered(endPos[0], endPos[1], color);
    hitCircleOverlay.drawCentered(endPos[0], endPos[1], Utils.COLOR_WHITE_FADE);

    // start circle
    hitCircle.drawCentered(x, y, color);
    if (!overlayAboveNumber) hitCircleOverlay.drawCentered(x, y, Utils.COLOR_WHITE_FADE);

    // ticks
    if (ticksT != null) {
      Image tick = GameImage.SLIDER_TICK.getImage();
      for (int i = 0; i < ticksT.length; i++) {
        float[] c = curve.pointAt(ticksT[i]);
        tick.drawCentered(c[0], c[1], Utils.COLOR_WHITE_FADE);
      }
    }
    if (sliderClickedInitial) ; // don't draw current combo number if already clicked
    else
      data.drawSymbolNumber(
          hitObject.getComboNumber(),
          x,
          y,
          hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(),
          alpha);
    if (overlayAboveNumber) hitCircleOverlay.drawCentered(x, y, Utils.COLOR_WHITE_FADE);

    // repeats
    for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1; tcurRepeat++) {
      if (hitObject.getRepeatCount() - 1 > tcurRepeat) {
        Image arrow = GameImage.REVERSEARROW.getImage();
        if (tcurRepeat != currentRepeats) {
          if (sliderTime == 0) continue;
          float t = Math.max(getT(trackPosition, true), 0);
          arrow.setAlpha((float) (t - Math.floor(t)));
        } else arrow.setAlpha(1f);
        if (tcurRepeat % 2 == 0) {
          // last circle
          arrow.setRotation(curve.getEndAngle());
          arrow.drawCentered(endPos[0], endPos[1]);
        } else {
          // first circle
          arrow.setRotation(curve.getStartAngle());
          arrow.drawCentered(x, y);
        }
      }
    }

    if (timeDiff >= 0) {
      // approach circle
      GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
    } else {
      // Since update() might not have run before drawing during a replay, the
      // slider time may not have been calculated, which causes NAN numbers and flicker.
      if (sliderTime == 0) return;

      float[] c = curve.pointAt(getT(trackPosition, false));
      float[] c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);

      float t = getT(trackPosition, false);
      //			float dis = hitObject.getPixelLength() * HitObject.getXMultiplier() * (t - (int) t);
      //			Image sliderBallFrame = sliderBallImages[(int) (dis / (diameter * Math.PI) * 30) %
      // sliderBallImages.length];
      Image sliderBallFrame =
          sliderBallImages[(int) (t * sliderTime * 60 / 1000) % sliderBallImages.length];
      float angle = (float) (Math.atan2(c2[1] - c[1], c2[0] - c[0]) * 180 / Math.PI);
      sliderBallFrame.setRotation(angle);
      sliderBallFrame.drawCentered(c[0], c[1]);

      // follow circle
      if (followCircleActive) {
        GameImage.SLIDER_FOLLOWCIRCLE.getImage().drawCentered(c[0], c[1]);

        // "flashlight" mod: dim the screen
        if (GameMod.FLASHLIGHT.isActive()) {
          float oldAlphaBlack = Utils.COLOR_BLACK_ALPHA.a;
          Utils.COLOR_BLACK_ALPHA.a = 0.75f;
          g.setColor(Utils.COLOR_BLACK_ALPHA);
          g.fillRect(0, 0, containerWidth, containerHeight);
          Utils.COLOR_BLACK_ALPHA.a = oldAlphaBlack;
        }
      }
    }

    Utils.COLOR_WHITE_FADE.a = oldAlpha;
  }