|
|
|
@@ -288,6 +288,11 @@ class PlayState extends MusicBeatState
|
|
|
|
|
* Opponent's icon
|
|
|
|
|
*/
|
|
|
|
|
public var iconP2:HealthIcon;
|
|
|
|
|
/**
|
|
|
|
|
* Every active icon that will be updated during gameplay (defaults to `iconP1` and `iconP1` between `create` and `postCreate` in scripts)
|
|
|
|
|
*/
|
|
|
|
|
public var iconArray:Array<HealthIcon> = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Camera for the HUD (notes, misses).
|
|
|
|
|
*/
|
|
|
|
@@ -540,10 +545,10 @@ class PlayState extends MusicBeatState
|
|
|
|
|
*/
|
|
|
|
|
public function updateRating() {
|
|
|
|
|
var rating = null;
|
|
|
|
|
var acc = get_accuracy();
|
|
|
|
|
var acc = accuracy; // caching since it has a getter with an operation - Nex
|
|
|
|
|
|
|
|
|
|
for(e in comboRatings)
|
|
|
|
|
if (e.percent <= acc && (rating == null || rating.percent < e.percent))
|
|
|
|
|
if (comboRatings != null && comboRatings.length > 0) for (e in comboRatings)
|
|
|
|
|
if ((e.percent <= acc && e.maxMisses >= misses) && (rating == null || (rating.percent < e.percent && e.maxMisses >= misses)))
|
|
|
|
|
rating = e;
|
|
|
|
|
|
|
|
|
|
var event = gameAndCharsEvent("onRatingUpdate", EventManager.get(RatingUpdateEvent).recycle(rating, curRating));
|
|
|
|
@@ -790,9 +795,9 @@ class PlayState extends MusicBeatState
|
|
|
|
|
if (Flags.DEFAULT_HEALTH != null) health = Flags.DEFAULT_HEALTH;
|
|
|
|
|
else health = maxHealth / 2;
|
|
|
|
|
|
|
|
|
|
iconP1 = new HealthIcon(boyfriend != null ? boyfriend.getIcon() : Flags.DEFAULT_HEALTH_ICON, true);
|
|
|
|
|
iconP2 = new HealthIcon(dad != null ? dad.getIcon() : Flags.DEFAULT_HEALTH_ICON, false);
|
|
|
|
|
for(icon in [iconP1, iconP2]) {
|
|
|
|
|
iconArray.push(iconP1 = new HealthIcon(boyfriend != null ? boyfriend.getIcon() : Flags.DEFAULT_HEALTH_ICON, true));
|
|
|
|
|
iconArray.push(iconP2 = new HealthIcon(dad != null ? dad.getIcon() : Flags.DEFAULT_HEALTH_ICON, false));
|
|
|
|
|
for (icon in iconArray) {
|
|
|
|
|
icon.y = healthBar.y - (icon.height / 2);
|
|
|
|
|
add(icon);
|
|
|
|
|
}
|
|
|
|
@@ -809,7 +814,8 @@ class PlayState extends MusicBeatState
|
|
|
|
|
scoreTxt.alignment = RIGHT;
|
|
|
|
|
missesTxt.alignment = CENTER;
|
|
|
|
|
accuracyTxt.alignment = LEFT;
|
|
|
|
|
updateRatingStuff();
|
|
|
|
|
if (updateRatingStuff != null)
|
|
|
|
|
updateRatingStuff();
|
|
|
|
|
|
|
|
|
|
for(e in [healthBar, healthBarBG, iconP1, iconP2, scoreTxt, missesTxt, accuracyTxt])
|
|
|
|
|
e.cameras = [camHUD];
|
|
|
|
@@ -1283,7 +1289,7 @@ class PlayState extends MusicBeatState
|
|
|
|
|
iconP2.health = 1 - (healthBarPercent / 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateRatingStuff() {
|
|
|
|
|
dynamic function updateRatingStuff() {
|
|
|
|
|
scoreTxt.text = 'Score:$songScore';
|
|
|
|
|
missesTxt.text = '${comboBreaks ? "Combo Breaks" : "Misses"}:$misses';
|
|
|
|
|
|
|
|
|
@@ -1313,7 +1319,8 @@ class PlayState extends MusicBeatState
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateRatingStuff();
|
|
|
|
|
if (updateRatingStuff != null)
|
|
|
|
|
updateRatingStuff();
|
|
|
|
|
|
|
|
|
|
if (canAccessDebugMenus) {
|
|
|
|
|
if (chartingMode && FlxG.keys.justPressed.SEVEN) {
|
|
|
|
@@ -1327,24 +1334,30 @@ class PlayState extends MusicBeatState
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doIconBop)
|
|
|
|
|
for (icon in [iconP1, iconP2])
|
|
|
|
|
for (icon in iconArray)
|
|
|
|
|
if (icon.updateBump != null)
|
|
|
|
|
icon.updateBump();
|
|
|
|
|
|
|
|
|
|
if (updateIconPositions != null)
|
|
|
|
|
updateIconPositions();
|
|
|
|
|
|
|
|
|
|
if (startingSong)
|
|
|
|
|
{
|
|
|
|
|
if (startedCountdown)
|
|
|
|
|
{
|
|
|
|
|
if (startingSong) {
|
|
|
|
|
if (startedCountdown) {
|
|
|
|
|
Conductor.songPosition += Conductor.songOffset + elapsed * 1000;
|
|
|
|
|
if (Conductor.songPosition >= 0)
|
|
|
|
|
startSong();
|
|
|
|
|
}
|
|
|
|
|
} else if (FlxG.sound.music != null) {
|
|
|
|
|
var instTime = FlxG.sound.music.time;
|
|
|
|
|
var isOffsync = vocals.time != instTime || [for(strumLine in strumLines.members) strumLine.vocals.time != instTime].contains(true);
|
|
|
|
|
var isOffsync:Bool = vocals.time != instTime;
|
|
|
|
|
if(!isOffsync) {
|
|
|
|
|
for(strumLine in strumLines.members) {
|
|
|
|
|
if(strumLine.vocals.time != instTime) {
|
|
|
|
|
isOffsync = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
__vocalOffsetViolation = Math.max(0, __vocalOffsetViolation + (isOffsync ? elapsed : -elapsed / 2));
|
|
|
|
|
if (__vocalOffsetViolation > Flags.VOCAL_OFFSET_VIOLATION_THRESHOLD) {
|
|
|
|
|
resyncVocals();
|
|
|
|
@@ -1358,11 +1371,17 @@ class PlayState extends MusicBeatState
|
|
|
|
|
if (controls.PAUSE && startedCountdown && canPause)
|
|
|
|
|
pauseGame();
|
|
|
|
|
|
|
|
|
|
if (generatedMusic)
|
|
|
|
|
moveCamera();
|
|
|
|
|
if (generatedMusic && strumLines.members[curCameraTarget] != null) {
|
|
|
|
|
var data:CamPosData = getStrumlineCamPos(curCameraTarget);
|
|
|
|
|
if (data.amount > 0) {
|
|
|
|
|
var event = scripts.event("onCameraMove", EventManager.get(CamMoveEvent).recycle(data.pos, strumLines.members[curCameraTarget], data.amount));
|
|
|
|
|
if (!event.cancelled)
|
|
|
|
|
camFollow.setPosition(event.position.x, event.position.y);
|
|
|
|
|
}
|
|
|
|
|
data.put();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (camZooming)
|
|
|
|
|
{
|
|
|
|
|
if (camZooming) {
|
|
|
|
|
FlxG.camera.zoom = lerp(FlxG.camera.zoom, defaultCamZoom, camGameZoomLerp);
|
|
|
|
|
camHUD.zoom = lerp(camHUD.zoom, defaultHudZoom, camHUDZoomLerp);
|
|
|
|
|
}
|
|
|
|
@@ -1396,41 +1415,41 @@ class PlayState extends MusicBeatState
|
|
|
|
|
scripts.event("postDraw", e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function moveCamera() if (strumLines.members[curCameraTarget] != null) {
|
|
|
|
|
var pos = FlxPoint.weak();
|
|
|
|
|
var amount = calculateCamPos(strumLines.members[curCameraTarget].characters, pos);
|
|
|
|
|
|
|
|
|
|
if (amount > 0) {
|
|
|
|
|
var event = gameAndCharsEvent("onCameraMove", EventManager.get(CamMoveEvent).recycle(pos, strumLines.members[curCameraTarget], amount));
|
|
|
|
|
if (!event.cancelled)
|
|
|
|
|
camFollow.setPosition(pos.x, pos.y);
|
|
|
|
|
}
|
|
|
|
|
pos.put();
|
|
|
|
|
/**
|
|
|
|
|
* Returns the camera position of the specified strumline.
|
|
|
|
|
* @param strumLine The strumline to get the camera position of.
|
|
|
|
|
* @param pos The position to put the camera position in. If `null`, a new FlxPoint will be created.
|
|
|
|
|
* @param ignoreInvisible Whenever invisible characters should be ignored.
|
|
|
|
|
**/
|
|
|
|
|
public inline function getStrumlineCamPos(strumLine:Int, ?pos:FlxPoint = null, ?ignoreInvisible:Bool = true):CamPosData {
|
|
|
|
|
return getCharactersCamPos(strumLines.members[strumLine].characters, pos, ignoreInvisible);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function used to calculate the camera position based on the characters.
|
|
|
|
|
*
|
|
|
|
|
* This function is dynamic, which means you can do `calculateCamPos = function(chars:Array<Character>, pos:FlxPoint) {}` in scripts.
|
|
|
|
|
*/
|
|
|
|
|
public dynamic function calculateCamPos(chars:Array<Character>, pos:FlxPoint):Int {
|
|
|
|
|
var r:Int = 0;
|
|
|
|
|
for (c in chars) {
|
|
|
|
|
if (c == null || !c.visible) continue;
|
|
|
|
|
* Returns the camera position of the specified characters.
|
|
|
|
|
* @param chars The characters to get the camera position of.
|
|
|
|
|
* @param pos The position to put the camera position in. If `null`, a new FlxPoint will be created.
|
|
|
|
|
* @param ignoreInvisible Whenever invisible characters should be ignored.
|
|
|
|
|
**/
|
|
|
|
|
public function getCharactersCamPos(chars:Array<Character>, ?pos:FlxPoint = null, ?ignoreInvisible:Bool = true):CamPosData {
|
|
|
|
|
if (pos == null) pos = FlxPoint.get();
|
|
|
|
|
var amount = 0;
|
|
|
|
|
for(c in chars) {
|
|
|
|
|
if (c == null || (ignoreInvisible && !c.visible)) continue;
|
|
|
|
|
var cpos = c.getCameraPosition();
|
|
|
|
|
pos.x += cpos.x;
|
|
|
|
|
pos.y += cpos.y;
|
|
|
|
|
r++;
|
|
|
|
|
amount++;
|
|
|
|
|
//cpos.put(); // not actually in the pool, so no need
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r > 0) {
|
|
|
|
|
pos.x /= r;
|
|
|
|
|
pos.y /= r;
|
|
|
|
|
if (amount > 0) {
|
|
|
|
|
pos.x /= amount;
|
|
|
|
|
pos.y /= amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
return new CamPosData(pos, amount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public var eventsTween:Map<String, FlxTween> = [];
|
|
|
|
|
|
|
|
|
|
public function executeEvent(event:ChartEvent) @:privateAccess {
|
|
|
|
@@ -1988,7 +2007,7 @@ class PlayState extends MusicBeatState
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doIconBop)
|
|
|
|
|
for (icon in [iconP1, iconP2])
|
|
|
|
|
for (icon in iconArray)
|
|
|
|
|
if (icon.bump != null)
|
|
|
|
|
icon.bump();
|
|
|
|
|
|
|
|
|
@@ -2127,8 +2146,10 @@ final class ComboRating {
|
|
|
|
|
public var percent:Float;
|
|
|
|
|
public var rating:String;
|
|
|
|
|
public var color:FlxColor;
|
|
|
|
|
public var maxMisses:Float; // Float since it could be Math.POSITIVE_INFINITY - Nex
|
|
|
|
|
|
|
|
|
|
public function new(percent:Float, rating:String, color:FlxColor) {
|
|
|
|
|
public function new(?percent:Float, ?rating:String, ?color:FlxColor, ?misses:Float) {
|
|
|
|
|
maxMisses = misses == null || Math.isNaN(misses) ? Math.POSITIVE_INFINITY : misses;
|
|
|
|
|
this.percent = percent;
|
|
|
|
|
this.rating = rating;
|
|
|
|
|
this.color = color;
|
|
|
|
@@ -2143,3 +2164,28 @@ typedef PlayStateTransitionData = {
|
|
|
|
|
var camFollowY:Float;
|
|
|
|
|
var camZoom:Float;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CamPosData {
|
|
|
|
|
/**
|
|
|
|
|
* The camera position.
|
|
|
|
|
**/
|
|
|
|
|
public var pos:FlxPoint;
|
|
|
|
|
/**
|
|
|
|
|
* The amount of characters that was involved in the calculation.
|
|
|
|
|
**/
|
|
|
|
|
public var amount:Int;
|
|
|
|
|
|
|
|
|
|
public function new(pos:FlxPoint, amount:Int) {
|
|
|
|
|
this.pos = pos;
|
|
|
|
|
this.amount = amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Puts the position back into the pool, making it reusable.
|
|
|
|
|
**/
|
|
|
|
|
public function put() {
|
|
|
|
|
if(pos == null) return;
|
|
|
|
|
pos.put();
|
|
|
|
|
pos = null;
|
|
|
|
|
}
|
|
|
|
|
}
|