mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-11-25 13:45:49 +00:00
Merge branch 'rewrite/master' into feature/char-unlock-merging
This commit is contained in:
commit
22b1a5d9c0
3
.github/actions/setup-haxe/action.yml
vendored
3
.github/actions/setup-haxe/action.yml
vendored
|
|
@ -82,7 +82,8 @@ runs:
|
||||||
with:
|
with:
|
||||||
run: |
|
run: |
|
||||||
git config --global --name-only --get-regexp 'url\.https\:\/\/x-access-token:.+@github\.com\/\.insteadOf' \
|
git config --global --name-only --get-regexp 'url\.https\:\/\/x-access-token:.+@github\.com\/\.insteadOf' \
|
||||||
| xargs git config --global --unset
|
| xargs -I {} git config --global --unset {}
|
||||||
|
|
||||||
git config -l --show-scope --show-origin
|
git config -l --show-scope --show-origin
|
||||||
git config --global 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf' https://github.com/
|
git config --global 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf' https://github.com/
|
||||||
post: git config --global --unset 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf'
|
post: git config --global --unset 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf'
|
||||||
|
|
|
||||||
2
assets
2
assets
|
|
@ -1 +1 @@
|
||||||
Subproject commit 49e375616e0c4f3fc66874ebe4262ac389d8c746
|
Subproject commit 638a44fdd7635814db89e96bdfdc9a9be54b39c9
|
||||||
15
hmm.json
15
hmm.json
|
|
@ -18,7 +18,7 @@
|
||||||
"name": "flixel",
|
"name": "flixel",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "599f38eeb502a8ba6439784036c2cfdc7b485260",
|
"ref": "f2b090d6c608471e730b051c8ee22b8b378964b1",
|
||||||
"url": "https://github.com/FunkinCrew/flixel"
|
"url": "https://github.com/FunkinCrew/flixel"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
"name": "flxanimate",
|
"name": "flxanimate",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "280d1a46ac60021d08bb18181631cbd6d061782c",
|
"ref": "0654797e5eb7cd7de0c1b2dbaa1efe5a1e1d9412",
|
||||||
"url": "https://github.com/Dot-Stuff/flxanimate"
|
"url": "https://github.com/Dot-Stuff/flxanimate"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -115,6 +115,13 @@
|
||||||
"ref": "147294123f983e35f50a966741474438069a7a8f",
|
"ref": "147294123f983e35f50a966741474438069a7a8f",
|
||||||
"url": "https://github.com/FunkinCrew/hxcpp-debugger"
|
"url": "https://github.com/FunkinCrew/hxcpp-debugger"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "hxjsonast",
|
||||||
|
"type": "git",
|
||||||
|
"dir": null,
|
||||||
|
"ref": "20e72cc68c823496359775ac1f06500e67f189d5",
|
||||||
|
"url": "https://github.com/nadako/hxjsonast/"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "hxp",
|
"name": "hxp",
|
||||||
"type": "haxelib",
|
"type": "haxelib",
|
||||||
|
|
@ -145,7 +152,7 @@
|
||||||
"name": "lime",
|
"name": "lime",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "e0b2339e02fff91168789dbd1a0dd019ea3dda39",
|
"ref": "fe3368f611a84a19afc03011353945ae4da8fffd",
|
||||||
"url": "https://github.com/FunkinCrew/lime"
|
"url": "https://github.com/FunkinCrew/lime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -205,4 +212,4 @@
|
||||||
"url": "https://github.com/fponticelli/thx.semver"
|
"url": "https://github.com/fponticelli/thx.semver"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -469,7 +469,7 @@ class Project extends HXProject {
|
||||||
// Should be true only on web builds.
|
// Should be true only on web builds.
|
||||||
// Enabling embedding and preloading is required to preload assets properly.
|
// Enabling embedding and preloading is required to preload assets properly.
|
||||||
EMBED_ASSETS.apply(this, isWeb());
|
EMBED_ASSETS.apply(this, isWeb());
|
||||||
PRELOAD_ALL.apply(this, true);
|
PRELOAD_ALL.apply(this, !isWeb());
|
||||||
|
|
||||||
// Should be true except on MacOS.
|
// Should be true except on MacOS.
|
||||||
// File drop doesn't work there.
|
// File drop doesn't work there.
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,18 @@ class Main extends Sprite
|
||||||
|
|
||||||
function init(?event:Event):Void
|
function init(?event:Event):Void
|
||||||
{
|
{
|
||||||
|
#if web
|
||||||
|
untyped js.Syntax.code("
|
||||||
|
window.requestAnimationFrame = function(callback, element) {
|
||||||
|
var currTime = new Date().getTime();
|
||||||
|
var timeToCall = 0;
|
||||||
|
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
|
||||||
|
timeToCall);
|
||||||
|
lastTime = currTime + timeToCall;
|
||||||
|
return id;
|
||||||
|
}");
|
||||||
|
#end
|
||||||
|
|
||||||
if (hasEventListener(Event.ADDED_TO_STAGE))
|
if (hasEventListener(Event.ADDED_TO_STAGE))
|
||||||
{
|
{
|
||||||
removeEventListener(Event.ADDED_TO_STAGE, init);
|
removeEventListener(Event.ADDED_TO_STAGE, init);
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ class InitState extends FlxState
|
||||||
// -DRESULTS
|
// -DRESULTS
|
||||||
FlxG.switchState(() -> new funkin.play.ResultState(
|
FlxG.switchState(() -> new funkin.play.ResultState(
|
||||||
{
|
{
|
||||||
storyMode: false,
|
storyMode: true,
|
||||||
title: "Cum Song Erect by Kawai Sprite",
|
title: "Cum Song Erect by Kawai Sprite",
|
||||||
songId: "cum",
|
songId: "cum",
|
||||||
characterId: "pico-playable",
|
characterId: "pico-playable",
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData>
|
||||||
|
|
||||||
public function hasNewCharacter():Bool
|
public function hasNewCharacter():Bool
|
||||||
{
|
{
|
||||||
var characters = Save.instance.charactersSeen.clone();
|
var charactersSeen = Save.instance.charactersSeen.clone();
|
||||||
|
|
||||||
for (charId in listEntryIds())
|
for (charId in listEntryIds())
|
||||||
{
|
{
|
||||||
|
|
@ -79,7 +79,7 @@ class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData>
|
||||||
if (player == null) continue;
|
if (player == null) continue;
|
||||||
|
|
||||||
if (!player.isUnlocked()) continue;
|
if (!player.isUnlocked()) continue;
|
||||||
if (characters.contains(charId)) continue;
|
if (charactersSeen.contains(charId)) continue;
|
||||||
|
|
||||||
// This character is unlocked but we haven't seen them in Freeplay yet.
|
// This character is unlocked but we haven't seen them in Freeplay yet.
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -89,6 +89,26 @@ class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function listNewCharacters():Array<String>
|
||||||
|
{
|
||||||
|
var charactersSeen = Save.instance.charactersSeen.clone();
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
for (charId in listEntryIds())
|
||||||
|
{
|
||||||
|
var player = fetchEntry(charId);
|
||||||
|
if (player == null) continue;
|
||||||
|
|
||||||
|
if (!player.isUnlocked()) continue;
|
||||||
|
if (charactersSeen.contains(charId)) continue;
|
||||||
|
|
||||||
|
// This character is unlocked but we haven't seen them in Freeplay yet.
|
||||||
|
result.push(charId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the playable character associated with a given stage character.
|
* Get the playable character associated with a given stage character.
|
||||||
* @param characterId The stage character ID.
|
* @param characterId The stage character ID.
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,8 @@ class StageRegistry extends BaseRegistry<Stage, StageData>
|
||||||
public function listBaseGameStageIds():Array<String>
|
public function listBaseGameStageIds():Array<String>
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"mainStage", "mainStageErect", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "limoRideErect", "mallXmas", "mallEvil", "school",
|
"mainStage", "mainStageErect", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "limoRideErect", "mallXmas", "mallXmasErect", "mallEvil",
|
||||||
"schoolEvil", "tankmanBattlefield", "phillyStreets", "phillyStreetsErect", "phillyBlazin",
|
"school", "schoolEvil", "tankmanBattlefield", "phillyStreets", "phillyStreetsErect", "phillyBlazin",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
48
source/funkin/graphics/shaders/TextureSwap.hx
Normal file
48
source/funkin/graphics/shaders/TextureSwap.hx
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package funkin.graphics.shaders;
|
||||||
|
|
||||||
|
import flixel.system.FlxAssets.FlxShader;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
|
||||||
|
class TextureSwap extends FlxShader
|
||||||
|
{
|
||||||
|
public var swappedImage(default, set):BitmapData;
|
||||||
|
public var amount(default, set):Float;
|
||||||
|
|
||||||
|
function set_swappedImage(_bitmapData:BitmapData):BitmapData
|
||||||
|
{
|
||||||
|
image.input = _bitmapData;
|
||||||
|
|
||||||
|
return _bitmapData;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_amount(val:Float):Float
|
||||||
|
{
|
||||||
|
fadeAmount.value = [val];
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:glFragmentSource('
|
||||||
|
#pragma header
|
||||||
|
|
||||||
|
uniform sampler2D image;
|
||||||
|
uniform float fadeAmount;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 tex = flixel_texture2D(bitmap, openfl_TextureCoordv);
|
||||||
|
vec4 tex2 = flixel_texture2D(image, openfl_TextureCoordv);
|
||||||
|
|
||||||
|
vec4 finalColor = mix(tex, vec4(tex2.rgb, tex.a), fadeAmount);
|
||||||
|
|
||||||
|
gl_FragColor = finalColor;
|
||||||
|
}
|
||||||
|
')
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.amount = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ import funkin.ui.story.StoryMenuState;
|
||||||
import funkin.util.MathUtil;
|
import funkin.util.MathUtil;
|
||||||
import openfl.utils.Assets;
|
import openfl.utils.Assets;
|
||||||
import funkin.effects.RetroCameraFade;
|
import funkin.effects.RetroCameraFade;
|
||||||
|
import flixel.math.FlxPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A substate which renders over the PlayState when the player dies.
|
* A substate which renders over the PlayState when the player dies.
|
||||||
|
|
@ -168,8 +169,8 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
// Assign a camera follow point to the boyfriend's position.
|
// Assign a camera follow point to the boyfriend's position.
|
||||||
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
|
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
|
||||||
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
|
cameraFollowPoint.x = getMidPointOld(boyfriend).x;
|
||||||
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
|
cameraFollowPoint.y = getMidPointOld(boyfriend).y;
|
||||||
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
|
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
|
||||||
cameraFollowPoint.x += offsets[0];
|
cameraFollowPoint.x += offsets[0];
|
||||||
cameraFollowPoint.y += offsets[1];
|
cameraFollowPoint.y += offsets[1];
|
||||||
|
|
@ -180,6 +181,21 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
targetCameraZoom = (PlayState?.instance?.currentStage?.camZoom ?? 1.0) * boyfriend.getDeathCameraZoom();
|
targetCameraZoom = (PlayState?.instance?.currentStage?.camZoom ?? 1.0) * boyfriend.getDeathCameraZoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FlxSprite.getMidpoint(); calculations changed in this git commit
|
||||||
|
* https://github.com/HaxeFlixel/flixel/commit/1553b5af0871462fcefedc091b7885437d6c36d2
|
||||||
|
* https://github.com/HaxeFlixel/flixel/pull/3125
|
||||||
|
*
|
||||||
|
* So we use this to do the old math that gets the midpoint of our graphics
|
||||||
|
* Luckily, we don't use getGraphicMidpoint() much in the code, so it's fine being in GameoverSubState here.
|
||||||
|
* @return FlxPoint
|
||||||
|
*/
|
||||||
|
function getMidPointOld(spr:FlxSprite, ?point:FlxPoint):FlxPoint
|
||||||
|
{
|
||||||
|
if (point == null) point = FlxPoint.get();
|
||||||
|
return point.set(spr.x + spr.frameWidth * 0.5 * spr.scale.x, spr.y + spr.frameHeight * 0.5 * spr.scale.y);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forcibly reset the camera zoom level to that of the current stage.
|
* Forcibly reset the camera zoom level to that of the current stage.
|
||||||
* This prevents camera zoom events from adversely affecting the game over state.
|
* This prevents camera zoom events from adversely affecting the game over state.
|
||||||
|
|
|
||||||
|
|
@ -503,6 +503,12 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
public var camGame:FlxCamera;
|
public var camGame:FlxCamera;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple helper debug variable, to be able to move the camera around for debug purposes
|
||||||
|
* without worrying about the camera tweening back to the follow point.
|
||||||
|
*/
|
||||||
|
public var debugUnbindCameraZoom:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The camera which contains, and controls visibility of, a video cutscene, dialogue, pause menu and sticker transition.
|
* The camera which contains, and controls visibility of, a video cutscene, dialogue, pause menu and sticker transition.
|
||||||
*/
|
*/
|
||||||
|
|
@ -992,7 +998,7 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
cameraBopMultiplier = FlxMath.lerp(1.0, cameraBopMultiplier, 0.95); // Lerp bop multiplier back to 1.0x
|
cameraBopMultiplier = FlxMath.lerp(1.0, cameraBopMultiplier, 0.95); // Lerp bop multiplier back to 1.0x
|
||||||
var zoomPlusBop = currentCameraZoom * cameraBopMultiplier; // Apply camera bop multiplier.
|
var zoomPlusBop = currentCameraZoom * cameraBopMultiplier; // Apply camera bop multiplier.
|
||||||
FlxG.camera.zoom = zoomPlusBop; // Actually apply the zoom to the camera.
|
if (!debugUnbindCameraZoom) FlxG.camera.zoom = zoomPlusBop; // Actually apply the zoom to the camera.
|
||||||
|
|
||||||
camHUD.zoom = FlxMath.lerp(defaultHUDCameraZoom, camHUD.zoom, 0.95);
|
camHUD.zoom = FlxMath.lerp(defaultHUDCameraZoom, camHUD.zoom, 0.95);
|
||||||
}
|
}
|
||||||
|
|
@ -1458,6 +1464,13 @@ class PlayState extends MusicBeatSubState
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function initConsoleHelpers():Void
|
||||||
|
{
|
||||||
|
FlxG.console.registerFunction("debugUnbindCameraZoom", () -> {
|
||||||
|
debugUnbindCameraZoom = !debugUnbindCameraZoom;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the game and HUD cameras.
|
* Initializes the game and HUD cameras.
|
||||||
*/
|
*/
|
||||||
|
|
@ -2224,10 +2237,10 @@ class PlayState extends MusicBeatSubState
|
||||||
// Skip handling the miss in botplay!
|
// Skip handling the miss in botplay!
|
||||||
if (!isBotPlayMode)
|
if (!isBotPlayMode)
|
||||||
{
|
{
|
||||||
// Judge the miss.
|
// Judge the miss.
|
||||||
// NOTE: This is what handles the scoring.
|
// NOTE: This is what handles the scoring.
|
||||||
trace('Missed note! ${note.noteData}');
|
trace('Missed note! ${note.noteData}');
|
||||||
onNoteMiss(note, event.playSound, event.healthChange);
|
onNoteMiss(note, event.playSound, event.healthChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
note.handledMiss = true;
|
note.handledMiss = true;
|
||||||
|
|
@ -2344,31 +2357,31 @@ class PlayState extends MusicBeatSubState
|
||||||
playerStrumline.playPress(input.noteDirection);
|
playerStrumline.playPress(input.noteDirection);
|
||||||
trace('PENALTY Score: ${songScore}');
|
trace('PENALTY Score: ${songScore}');
|
||||||
}
|
}
|
||||||
else if (notesInDirection.length == 0)
|
else if (notesInDirection.length == 0)
|
||||||
{
|
{
|
||||||
// Press a key with no penalty.
|
// Press a key with no penalty.
|
||||||
|
|
||||||
// Play the strumline animation.
|
// Play the strumline animation.
|
||||||
playerStrumline.playPress(input.noteDirection);
|
playerStrumline.playPress(input.noteDirection);
|
||||||
trace('NO PENALTY Score: ${songScore}');
|
trace('NO PENALTY Score: ${songScore}');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Choose the first note, deprioritizing low priority notes.
|
// Choose the first note, deprioritizing low priority notes.
|
||||||
var targetNote:Null<NoteSprite> = notesInDirection.find((note) -> !note.lowPriority);
|
var targetNote:Null<NoteSprite> = notesInDirection.find((note) -> !note.lowPriority);
|
||||||
if (targetNote == null) targetNote = notesInDirection[0];
|
if (targetNote == null) targetNote = notesInDirection[0];
|
||||||
if (targetNote == null) continue;
|
if (targetNote == null) continue;
|
||||||
|
|
||||||
// Judge and hit the note.
|
// Judge and hit the note.
|
||||||
trace('Hit note! ${targetNote.noteData}');
|
trace('Hit note! ${targetNote.noteData}');
|
||||||
goodNoteHit(targetNote, input);
|
goodNoteHit(targetNote, input);
|
||||||
trace('Score: ${songScore}');
|
trace('Score: ${songScore}');
|
||||||
|
|
||||||
notesInDirection.remove(targetNote);
|
notesInDirection.remove(targetNote);
|
||||||
|
|
||||||
// Play the strumline animation.
|
// Play the strumline animation.
|
||||||
playerStrumline.playConfirm(input.noteDirection);
|
playerStrumline.playConfirm(input.noteDirection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (inputReleaseQueue.length > 0)
|
while (inputReleaseQueue.length > 0)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import funkin.util.MathUtil;
|
||||||
import funkin.ui.story.StoryMenuState;
|
import funkin.ui.story.StoryMenuState;
|
||||||
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
|
import flixel.FlxState;
|
||||||
|
import flixel.FlxSubState;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.effects.FlxFlicker;
|
import flixel.effects.FlxFlicker;
|
||||||
import flixel.graphics.frames.FlxBitmapFont;
|
import flixel.graphics.frames.FlxBitmapFont;
|
||||||
|
|
@ -731,54 +733,93 @@ class ResultState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determining the target state(s) to go to.
|
||||||
|
// Default to main menu because that's better than `null`.
|
||||||
|
var targetState:flixel.FlxState = new funkin.ui.mainmenu.MainMenuState();
|
||||||
|
var shouldTween = false;
|
||||||
|
var shouldUseSubstate = false;
|
||||||
|
|
||||||
if (params.storyMode)
|
if (params.storyMode)
|
||||||
{
|
{
|
||||||
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker)));
|
if (PlayerRegistry.instance.hasNewCharacter())
|
||||||
|
{
|
||||||
|
// New character, display the notif.
|
||||||
|
targetState = new StoryMenuState(null);
|
||||||
|
|
||||||
|
var newCharacters = PlayerRegistry.instance.listNewCharacters();
|
||||||
|
|
||||||
|
for (charId in newCharacters)
|
||||||
|
{
|
||||||
|
shouldTween = true;
|
||||||
|
// This works recursively, ehe!
|
||||||
|
targetState = new funkin.ui.charSelect.CharacterUnlockState(charId, targetState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No new characters.
|
||||||
|
shouldTween = false;
|
||||||
|
shouldUseSubstate = true;
|
||||||
|
targetState = new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var rigged:Bool = true;
|
if (rank > Scoring.calculateRank(params?.prevScoreData))
|
||||||
if (rank > Scoring.calculateRank(params?.prevScoreData)) // if (rigged)
|
|
||||||
{
|
{
|
||||||
trace('THE RANK IS Higher.....');
|
trace('THE RANK IS Higher.....');
|
||||||
|
|
||||||
FlxTween.tween(rankBg, {alpha: 1}, 0.5,
|
shouldTween = true;
|
||||||
|
targetState = FreeplayState.build(
|
||||||
{
|
{
|
||||||
ease: FlxEase.expoOut,
|
{
|
||||||
onComplete: function(_) {
|
character: playerCharacterId ?? "bf",
|
||||||
FlxG.switchState(FreeplayState.build(
|
fromResults:
|
||||||
{
|
{
|
||||||
{
|
oldRank: Scoring.calculateRank(params?.prevScoreData),
|
||||||
character: playerCharacterId ?? "bf",
|
newRank: rank,
|
||||||
fromResults:
|
songId: params.songId,
|
||||||
{
|
difficultyId: params.difficultyId,
|
||||||
oldRank: Scoring.calculateRank(params?.prevScoreData),
|
playRankAnim: true
|
||||||
newRank: rank,
|
}
|
||||||
songId: params.songId,
|
|
||||||
difficultyId: params.difficultyId,
|
|
||||||
playRankAnim: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace('rank is lower...... and/or equal');
|
shouldTween = false;
|
||||||
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(
|
shouldUseSubstate = true;
|
||||||
{
|
targetState = new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(null, sticker));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldTween)
|
||||||
|
{
|
||||||
|
FlxTween.tween(rankBg, {alpha: 1}, 0.5,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onComplete: function(_) {
|
||||||
|
if (shouldUseSubstate && targetState is FlxSubState)
|
||||||
{
|
{
|
||||||
fromResults:
|
openSubState(cast targetState);
|
||||||
{
|
|
||||||
oldRank: null,
|
|
||||||
playRankAnim: false,
|
|
||||||
newRank: rank,
|
|
||||||
songId: params.songId,
|
|
||||||
difficultyId: params.difficultyId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, sticker)));
|
else
|
||||||
|
{
|
||||||
|
FlxG.switchState(targetState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shouldUseSubstate && targetState is FlxSubState)
|
||||||
|
{
|
||||||
|
openSubState(cast targetState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.switchState(targetState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,7 @@ class BaseCharacter extends Bopper
|
||||||
{
|
{
|
||||||
if (isAnimationFinished())
|
if (isAnimationFinished())
|
||||||
{
|
{
|
||||||
trace('Not playing hold (${getCurrentAnimation()}) (${isAnimationFinished()}, ${getCurrentAnimation().endsWith(Constants.ANIMATION_HOLD_SUFFIX)}, ${hasAnimation(getCurrentAnimation() + Constants.ANIMATION_HOLD_SUFFIX)})');
|
// trace('Not playing hold (${getCurrentAnimation()}) (${isAnimationFinished()}, ${getCurrentAnimation().endsWith(Constants.ANIMATION_HOLD_SUFFIX)}, ${hasAnimation(getCurrentAnimation() + Constants.ANIMATION_HOLD_SUFFIX)})');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class HealthIcon extends FunkinSprite
|
||||||
* this value allows you to set a relative scale for the icon.
|
* this value allows you to set a relative scale for the icon.
|
||||||
* @default 1x scale = 150px width and height.
|
* @default 1x scale = 150px width and height.
|
||||||
*/
|
*/
|
||||||
public var size:FlxPoint = new FlxPoint(1, 1);
|
public var size:FlxPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the "bop" animation once every X steps.
|
* Apply the "bop" animation once every X steps.
|
||||||
|
|
@ -120,11 +120,15 @@ class HealthIcon extends FunkinSprite
|
||||||
{
|
{
|
||||||
super(0, 0);
|
super(0, 0);
|
||||||
this.playerId = playerId;
|
this.playerId = playerId;
|
||||||
|
this.size = new FlxCallbackPoint(onSetSize);
|
||||||
this.scrollFactor.set();
|
this.scrollFactor.set();
|
||||||
|
size.set(1.0, 1.0);
|
||||||
this.characterId = char;
|
this.characterId = char;
|
||||||
|
}
|
||||||
|
|
||||||
initTargetSize();
|
function onSetSize(value:FlxPoint):Void
|
||||||
|
{
|
||||||
|
snapToTargetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_characterId(value:Null<String>):Null<String>
|
function set_characterId(value:Null<String>):Null<String>
|
||||||
|
|
@ -243,6 +247,22 @@ class HealthIcon extends FunkinSprite
|
||||||
this.updateHitbox();
|
this.updateHitbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Immediately snap the health icon to its target size without lerping.
|
||||||
|
*/
|
||||||
|
public function snapToTargetSize():Void
|
||||||
|
{
|
||||||
|
if (this.width > this.height)
|
||||||
|
{
|
||||||
|
setGraphicSize(Std.int(HEALTH_ICON_SIZE * this.size.x), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setGraphicSize(0, Std.int(HEALTH_ICON_SIZE * this.size.y));
|
||||||
|
}
|
||||||
|
updateHitbox();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the position (and status) of the health icon.
|
* Update the position (and status) of the health icon.
|
||||||
*/
|
*/
|
||||||
|
|
@ -301,12 +321,6 @@ class HealthIcon extends FunkinSprite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function initTargetSize():Void
|
|
||||||
{
|
|
||||||
setGraphicSize(HEALTH_ICON_SIZE);
|
|
||||||
updateHitbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateHealthIcon(health:Float):Void
|
function updateHealthIcon(health:Float):Void
|
||||||
{
|
{
|
||||||
// We want to efficiently handle animation playback
|
// We want to efficiently handle animation playback
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
|
|
||||||
Conductor.beatHit.add(this.beatHit);
|
Conductor.beatHit.add(this.beatHit);
|
||||||
Conductor.stepHit.add(this.stepHit);
|
Conductor.stepHit.add(this.stepHit);
|
||||||
|
|
||||||
|
initConsoleHelpers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function destroy():Void
|
public override function destroy():Void
|
||||||
|
|
@ -79,6 +81,8 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
dispatchEvent(new UpdateScriptEvent(elapsed));
|
dispatchEvent(new UpdateScriptEvent(elapsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function initConsoleHelpers():Void {}
|
||||||
|
|
||||||
function reloadAssets()
|
function reloadAssets()
|
||||||
{
|
{
|
||||||
PolymodHandler.forceReloadAssets();
|
PolymodHandler.forceReloadAssets();
|
||||||
|
|
|
||||||
128
source/funkin/ui/charSelect/CharacterUnlockState.hx
Normal file
128
source/funkin/ui/charSelect/CharacterUnlockState.hx
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
package funkin.ui.charSelect;
|
||||||
|
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.FlxState;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import funkin.play.character.CharacterData;
|
||||||
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
|
import funkin.play.components.HealthIcon;
|
||||||
|
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
||||||
|
import funkin.data.freeplay.player.PlayerData;
|
||||||
|
import funkin.data.freeplay.player.PlayerRegistry;
|
||||||
|
import funkin.ui.mainmenu.MainMenuState;
|
||||||
|
|
||||||
|
using flixel.util.FlxSpriteUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you want the player to unlock a character, call `CharacterUnlockState.unlock(characterName)`.
|
||||||
|
* It handles both the act of unlocking the character and displaying the dialog.
|
||||||
|
*/
|
||||||
|
class CharacterUnlockState extends MusicBeatState
|
||||||
|
{
|
||||||
|
public var targetCharacterId:String = "";
|
||||||
|
public var targetCharacterData:Null<PlayableCharacter>;
|
||||||
|
|
||||||
|
var nextState:FlxState;
|
||||||
|
|
||||||
|
static final DIALOG_BG_COLOR:FlxColor = 0xFF000000; // Iconic
|
||||||
|
static final DIALOG_COLOR:FlxColor = 0xFF4344F6; // Iconic
|
||||||
|
static final DIALOG_FONT_COLOR:FlxColor = 0xFFFFFFFF; // Iconic
|
||||||
|
|
||||||
|
var busy:Bool = false;
|
||||||
|
|
||||||
|
public function new(targetPlayableCharacter:String, ?nextState:FlxState)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.targetCharacterId = targetPlayableCharacter;
|
||||||
|
this.targetCharacterData = PlayerRegistry.instance.fetchEntry(targetCharacterId);
|
||||||
|
this.nextState = nextState == null ? new MainMenuState() : nextState;
|
||||||
|
}
|
||||||
|
|
||||||
|
override function create():Void
|
||||||
|
{
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
handleMusic();
|
||||||
|
|
||||||
|
bgColor = DIALOG_BG_COLOR;
|
||||||
|
|
||||||
|
var dialogContainer:FlxSpriteGroup = new FlxSpriteGroup();
|
||||||
|
add(dialogContainer);
|
||||||
|
|
||||||
|
// Build the graphic for the text...
|
||||||
|
var charName:String = targetCharacterData != null ? targetCharacterData.getName() : targetCharacterId.toTitleCase();
|
||||||
|
// var dialogText:FlxText = new FlxText(0, 0, 0, 'You can now play as $charName.\n\nCheck it out in Freeplay!');
|
||||||
|
var dialogText:FlxText = new FlxText(0, 0, 0, 'You can now play as $charName.');
|
||||||
|
dialogText.setFormat("VCR OSD Mono", 32, DIALOG_FONT_COLOR, LEFT);
|
||||||
|
|
||||||
|
// THEN we can size the dialog to match...
|
||||||
|
var dialogBG:FlxSprite = new FlxSprite(0, 0);
|
||||||
|
dialogBG.makeGraphic(Std.int(dialogText.width + 32), Std.int(dialogText.height + 32), FlxColor.TRANSPARENT);
|
||||||
|
dialogBG.drawRoundRect(0, 0, dialogBG.width, dialogBG.height, 16, 16, DIALOG_COLOR);
|
||||||
|
dialogContainer.add(dialogBG);
|
||||||
|
|
||||||
|
dialogBG.screenCenter(XY);
|
||||||
|
|
||||||
|
// THEN we can position the text inside that.
|
||||||
|
dialogText.x = dialogBG.x + 16;
|
||||||
|
dialogText.y = dialogBG.y + 16;
|
||||||
|
dialogContainer.add(dialogText);
|
||||||
|
|
||||||
|
// HealthIcon handles getting the right frames for us,
|
||||||
|
// but it has a bunch of overhead in it that makes it gross to work with outside the health bar.
|
||||||
|
var healthIconCharacterId = targetCharacterData.getOwnedCharacterIds()[0];
|
||||||
|
var baseCharacter = CharacterDataParser.fetchCharacter(healthIconCharacterId);
|
||||||
|
var healthIcon:HealthIcon = new HealthIcon(healthIconCharacterId);
|
||||||
|
@:privateAccess
|
||||||
|
healthIcon.configure(baseCharacter._data.healthIcon);
|
||||||
|
healthIcon.autoUpdate = false;
|
||||||
|
healthIcon.bopEvery = 0; // You can increase this number later once the animation is done.
|
||||||
|
healthIcon.size.set(0.5, 0.5);
|
||||||
|
healthIcon.x = dialogBG.x + 390;
|
||||||
|
healthIcon.y = dialogBG.y + 6;
|
||||||
|
healthIcon.flipX = true;
|
||||||
|
healthIcon.snapToTargetSize();
|
||||||
|
dialogContainer.add(healthIcon);
|
||||||
|
|
||||||
|
dialogContainer.scale.set(0, 0);
|
||||||
|
FlxTween.num(0.0, 1.0, 0.75,
|
||||||
|
{
|
||||||
|
ease: FlxEase.elasticOut,
|
||||||
|
}, function(curScale) {
|
||||||
|
dialogContainer.scale.set(curScale, curScale);
|
||||||
|
healthIcon.size.set(0.5 * curScale, 0.5 * curScale);
|
||||||
|
});
|
||||||
|
|
||||||
|
// performUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMusic():Void
|
||||||
|
{
|
||||||
|
FlxG.sound.music?.stop();
|
||||||
|
FlxG.sound.play(Paths.sound('confirmMenu'));
|
||||||
|
}
|
||||||
|
|
||||||
|
override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (controls.ACCEPT || controls.BACK && !busy)
|
||||||
|
{
|
||||||
|
busy = true;
|
||||||
|
startClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startClose():Void
|
||||||
|
{
|
||||||
|
// Fade to black, then switch state.
|
||||||
|
FlxG.camera.fade(FlxColor.BLACK, 0.75, false, () -> {
|
||||||
|
FlxG.switchState(nextState);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5707,7 +5707,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
PlayStatePlaylist.campaignId = 'week3';
|
PlayStatePlaylist.campaignId = 'week3';
|
||||||
case 'limoRide' | 'limoRideErect':
|
case 'limoRide' | 'limoRideErect':
|
||||||
PlayStatePlaylist.campaignId = 'week4';
|
PlayStatePlaylist.campaignId = 'week4';
|
||||||
case 'mallXmas' | 'mallEvil':
|
case 'mallXmas' | 'mallXmasErect' | 'mallEvil':
|
||||||
PlayStatePlaylist.campaignId = 'week5';
|
PlayStatePlaylist.campaignId = 'week5';
|
||||||
case 'school' | 'schoolEvil':
|
case 'school' | 'schoolEvil':
|
||||||
PlayStatePlaylist.campaignId = 'week6';
|
PlayStatePlaylist.campaignId = 'week6';
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,8 @@ class FreeplayState extends MusicBeatSubState
|
||||||
|
|
||||||
switch (currentCharacterId)
|
switch (currentCharacterId)
|
||||||
{
|
{
|
||||||
|
case(PlayerRegistry.instance.hasNewCharacter()) => true:
|
||||||
|
backingCard = new NewCharacterCard(currentCharacter);
|
||||||
case 'bf':
|
case 'bf':
|
||||||
backingCard = new BoyfriendCard(currentCharacter);
|
backingCard = new BoyfriendCard(currentCharacter);
|
||||||
case 'pico':
|
case 'pico':
|
||||||
|
|
@ -347,6 +349,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
var displayedVariations = song.getVariationsByCharacter(currentCharacter);
|
var displayedVariations = song.getVariationsByCharacter(currentCharacter);
|
||||||
trace('Displayed Variations (${songId}): $displayedVariations');
|
trace('Displayed Variations (${songId}): $displayedVariations');
|
||||||
var availableDifficultiesForSong:Array<String> = song.listSuffixedDifficulties(displayedVariations, false, false);
|
var availableDifficultiesForSong:Array<String> = song.listSuffixedDifficulties(displayedVariations, false, false);
|
||||||
|
var unsuffixedDifficulties = song.listDifficulties(displayedVariations, false, false);
|
||||||
trace('Available Difficulties: $availableDifficultiesForSong');
|
trace('Available Difficulties: $availableDifficultiesForSong');
|
||||||
if (availableDifficultiesForSong.length == 0) continue;
|
if (availableDifficultiesForSong.length == 0) continue;
|
||||||
|
|
||||||
|
|
@ -355,6 +358,10 @@ class FreeplayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
diffIdsTotal.pushUnique(difficulty);
|
diffIdsTotal.pushUnique(difficulty);
|
||||||
}
|
}
|
||||||
|
for (difficulty in unsuffixedDifficulties)
|
||||||
|
{
|
||||||
|
diffIdsTotal.pushUnique(difficulty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1985,22 +1992,12 @@ class FreeplayState extends MusicBeatSubState
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseInstrumentalId:String = targetSong?.getBaseInstrumentalId(targetDifficultyId, targetDifficulty.variation ?? Constants.DEFAULT_VARIATION) ?? '';
|
if (targetInstId == null)
|
||||||
var altInstrumentalIds:Array<String> = targetSong?.listAltInstrumentalIds(targetDifficultyId,
|
|
||||||
targetDifficulty.variation ?? Constants.DEFAULT_VARIATION) ?? [];
|
|
||||||
|
|
||||||
var targetInstId:String = baseInstrumentalId;
|
|
||||||
|
|
||||||
// TODO: Make this a UI element.
|
|
||||||
#if FEATURE_DEBUG_FUNCTIONS
|
|
||||||
if (altInstrumentalIds.length > 0 && FlxG.keys.pressed.CONTROL)
|
|
||||||
{
|
{
|
||||||
targetInstId = altInstrumentalIds[0];
|
var baseInstrumentalId:String = targetSong?.getBaseInstrumentalId(targetDifficultyId, targetDifficulty.variation ?? Constants.DEFAULT_VARIATION) ?? '';
|
||||||
|
targetInstId = baseInstrumentalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetInstId == null) targetInstId = baseInstrumentalId;
|
|
||||||
#end
|
|
||||||
|
|
||||||
// Visual and audio effects.
|
// Visual and audio effects.
|
||||||
FunkinSound.playOnce(Paths.sound('confirmMenu'));
|
FunkinSound.playOnce(Paths.sound('confirmMenu'));
|
||||||
if (dj != null) dj.confirm();
|
if (dj != null) dj.confirm();
|
||||||
|
|
@ -2380,7 +2377,7 @@ class FreeplaySongData
|
||||||
|
|
||||||
this.scoringRank = Save.instance.getSongRank(songId, suffixedDifficulty);
|
this.scoringRank = Save.instance.getSongRank(songId, suffixedDifficulty);
|
||||||
|
|
||||||
this.isNew = song.isSongNew(currentDifficulty);
|
this.isNew = song.isSongNew(suffixedDifficulty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2422,7 +2419,11 @@ class DifficultySprite extends FlxSprite
|
||||||
// Remove the last suffix of the difficulty id until we find an asset or there are no more suffixes.
|
// Remove the last suffix of the difficulty id until we find an asset or there are no more suffixes.
|
||||||
var assetDiffIdParts:Array<String> = assetDiffId.split('-');
|
var assetDiffIdParts:Array<String> = assetDiffId.split('-');
|
||||||
assetDiffIdParts.pop();
|
assetDiffIdParts.pop();
|
||||||
if (assetDiffIdParts.length == 0) break;
|
if (assetDiffIdParts.length == 0)
|
||||||
|
{
|
||||||
|
trace('Could not find difficulty asset: freeplay/freeplay${diffId} (from ${diffId})');
|
||||||
|
return;
|
||||||
|
};
|
||||||
assetDiffId = assetDiffIdParts.join('-');
|
assetDiffId = assetDiffIdParts.join('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2436,6 +2437,7 @@ class DifficultySprite extends FlxSprite
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.loadGraphic(Paths.image('freeplay/freeplay' + assetDiffId));
|
this.loadGraphic(Paths.image('freeplay/freeplay' + assetDiffId));
|
||||||
|
trace('Loaded difficulty asset: freeplay/freeplay${assetDiffId} (from ${diffId})');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,8 +344,8 @@ class MainMenuState extends MusicBeatState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FEATURE_DEBUG_FUNCTIONS
|
|
||||||
// Open the debug menu, defaults to ` / ~
|
// Open the debug menu, defaults to ` / ~
|
||||||
|
// This includes stuff like the Chart Editor, so it should be present on all builds.
|
||||||
if (controls.DEBUG_MENU)
|
if (controls.DEBUG_MENU)
|
||||||
{
|
{
|
||||||
persistentUpdate = false;
|
persistentUpdate = false;
|
||||||
|
|
@ -353,6 +353,18 @@ class MainMenuState extends MusicBeatState
|
||||||
FlxG.state.openSubState(new DebugMenuSubState());
|
FlxG.state.openSubState(new DebugMenuSubState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FEATURE_DEBUG_FUNCTIONS
|
||||||
|
// Ctrl+Alt+Shift+P = Character Unlock screen
|
||||||
|
// Ctrl+Alt+Shift+W = Meet requirements for Pico Unlock
|
||||||
|
// Ctrl+Alt+Shift+L = Revoke requirements for Pico Unlock
|
||||||
|
// Ctrl+Alt+Shift+R = Score/Rank conflict test
|
||||||
|
// Ctrl+Alt+Shift+E = Dump save data
|
||||||
|
|
||||||
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.P)
|
||||||
|
{
|
||||||
|
FlxG.switchState(() -> new funkin.ui.charSelect.CharacterUnlockState('pico'));
|
||||||
|
}
|
||||||
|
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.W)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.W)
|
||||||
{
|
{
|
||||||
FunkinSound.playOnce(Paths.sound('confirmMenu'));
|
FunkinSound.playOnce(Paths.sound('confirmMenu'));
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ class FunkinSoundTray extends FlxSoundTray
|
||||||
lerpYPos = 10;
|
lerpYPos = 10;
|
||||||
visible = true;
|
visible = true;
|
||||||
active = true;
|
active = true;
|
||||||
var globalVolume:Int = Math.round(FlxG.sound.volume * 10);
|
var globalVolume:Int = Math.round(FlxG.sound.logToLinear(FlxG.sound.volume) * 10);
|
||||||
|
|
||||||
if (FlxG.sound.muted)
|
if (FlxG.sound.muted)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
22
source/funkin/util/FlxColorUtil.hx
Normal file
22
source/funkin/util/FlxColorUtil.hx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package funkin.util;
|
||||||
|
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non inline FlxColor functions for use in hscript files
|
||||||
|
*/
|
||||||
|
class FlxColorUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get an interpolated color based on two different colors.
|
||||||
|
*
|
||||||
|
* @param Color1 The first color
|
||||||
|
* @param Color2 The second color
|
||||||
|
* @param Factor Value from 0 to 1 representing how much to shift Color1 toward Color2
|
||||||
|
* @return The interpolated color
|
||||||
|
*/
|
||||||
|
public static function interpolate(Color1:FlxColor, Color2:FlxColor, Factor:Float = 0.5):FlxColor
|
||||||
|
{
|
||||||
|
return FlxColor.interpolate(Color1, Color2, Factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue