Merge branch 'rewrite/master' into pico-cutscene-tweaks

This commit is contained in:
Cameron Taylor
2024-09-12 20:04:02 -04:00
16 changed files with 187 additions and 69 deletions
+8 -1
View File
@@ -29,8 +29,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Implemented support for a new Instrumental Selector in Freeplay
- Beating a Pico remix lets you use that instrumental when playing as Boyfriend
- Added the first batch of Erect Stages! These graphical overhauls of the original stages will be used when playing Erect remixes and Pico remixes
- Week 1 Erect Stage
- Week 2 Erect Stage
- Week 3 Erect Stage
- Week 4 Erect Stage
- Week 5 Erect Stage
- Weekend 1 Erect Stage
- Implemented alternate animations and music for Pico in the results screen.
- These display on Pico remixes, as well as when playing Weekend 1.
- Implemented support for scripted Note Kinds. You can use HScript define a different note style to display for these notes as well as custom behavior. (community feature by lemz1)
- Implemented a new Strumline Background option, to display a darkened background behind the strumline with your choice of opacity.
- Implemented support for Numeric and Selector options in the Options menu. (community feature by FlooferLand)
## Changed
- Girlfriend and Nene now perform previously unused animations when you achieve a large combo, or drop a large combo.
+1 -1
Submodule art updated: 0bb988c497...0dee03f11a
+1 -1
Submodule assets updated: 350910d809...86a0a01e18
+1 -1
View File
@@ -194,7 +194,7 @@
"name": "polymod",
"type": "git",
"dir": null,
"ref": "96cfc5fa693b017e47f7cb13b765cc68698fa6b6",
"ref": "0fbdf27fe124549730accd540cec8a183f8652c0",
"url": "https://github.com/larsiusprime/polymod"
},
{
+3 -8
View File
@@ -67,14 +67,9 @@ class Main extends Sprite
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);
return id;
}");
// set this variable (which is a function) from the lime version at lime/_internal/backend/html5/HTML5Application.hx
// The framerate cap will more thoroughly initialize via Preferences in InitState.hx
funkin.Preferences.lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
if (hasEventListener(Event.ADDED_TO_STAGE))
+53
View File
@@ -128,6 +128,48 @@ class Preferences
return value;
}
public static var unlockedFramerate(get, set):Bool;
static function get_unlockedFramerate():Bool
{
return Save?.instance?.options?.unlockedFramerate;
}
static function set_unlockedFramerate(value:Bool):Bool
{
if (value != Save.instance.options.unlockedFramerate)
{
#if web
toggleFramerateCap(value);
#end
}
var save:Save = Save.instance;
save.options.unlockedFramerate = value;
save.flush();
return value;
}
#if web
// We create a haxe version of this just for readability.
// We use these to override `window.requestAnimationFrame` in Javascript to uncap the framerate / "animation" request rate
// Javascript is crazy since u can just do stuff like that lol
public static function unlockedFramerateFunction(callback, element)
{
var currTime = Date.now().getTime();
var timeToCall = 0;
var id = js.Browser.window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
return id;
}
// Lime already implements their own little framerate cap, so we can just use that
// This also gets set in the init function in Main.hx, since we need to definitely override it
public static var lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
/**
* Loads the user's preferences from the save data and apply them.
*/
@@ -137,6 +179,17 @@ class Preferences
FlxG.autoPause = Preferences.autoPause;
// Apply the debugDisplay setting (enables the FPS and RAM display).
toggleDebugDisplay(Preferences.debugDisplay);
#if web
toggleFramerateCap(Preferences.unlockedFramerate);
#end
}
static function toggleFramerateCap(unlocked:Bool):Void
{
#if web
var framerateFunction = unlocked ? unlockedFramerateFunction : lockedFramerateFunction;
untyped js.Syntax.code("window.requestAnimationFrame = framerateFunction;");
#end
}
static function toggleDebugDisplay(show:Bool):Void
+2
View File
@@ -340,6 +340,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
if (songMusicData != null)
{
Conductor.instance.mapTimeChanges(songMusicData.timeChanges);
if (songMusicData.looped != null && params.loop == null) params.loop = songMusicData.looped;
}
else
{
@@ -185,11 +185,12 @@ class FlxAtlasSprite extends FlxAnimate
// Move to the first frame of the animation.
// goToFrameLabel(id);
trace('Playing animation $id');
if (this.anim.symbolDictionary.exists(id) || (this.anim.getByName(id) != null))
if ((id == null || id == "") || this.anim.symbolDictionary.exists(id) || (this.anim.getByName(id) != null))
{
this.anim.play(id, restart, false, startFrame);
if (id == "Boyfriend DJ fist pump" || startFrame == 4) trace("PUMP COMMAND: " + anim.curFrame);
this.currentAnimation = anim.curSymbol.name;
fr = null;
}
// Only call goToFrameLabel if there is a frame label with that name. This prevents annoying warnings!
@@ -316,6 +317,10 @@ class FlxAtlasSprite extends FlxAnimate
{
onAnimationComplete.dispatch(currentAnimation);
}
else
{
onAnimationComplete.dispatch('');
}
}
var prevFrames:Map<Int, FlxFrame> = [];
+2 -4
View File
@@ -418,8 +418,7 @@ class ResultState extends MusicBeatSubState
{
startingVolume: 1.0,
overrideExisting: true,
restartTrack: true,
loop: rank.shouldMusicLoop()
restartTrack: true
});
});
}
@@ -429,8 +428,7 @@ class ResultState extends MusicBeatSubState
{
startingVolume: 1.0,
overrideExisting: true,
restartTrack: true,
loop: rank.shouldMusicLoop()
restartTrack: true
});
}
});
-13
View File
@@ -577,19 +577,6 @@ enum abstract ScoringRank(String)
}
}
public function shouldMusicLoop():Bool
{
switch (abstract)
{
case PERFECT_GOLD | PERFECT | EXCELLENT | GREAT | GOOD:
return true;
case SHIT:
return false;
default:
return false;
}
}
public function getHorTextAsset()
{
switch (abstract)
+18 -2
View File
@@ -97,6 +97,7 @@ class Save
autoPause: true,
inputOffset: 0,
audioVisualOffset: 0,
unlockedFramerate: false,
controls:
{
@@ -407,6 +408,9 @@ class Save
return data.unlocks.charactersSeen;
}
/**
* Marks whether the player has seen the spotlight animation, which should only display once per save file ever.
*/
public var oldChar(get, set):Bool;
function get_oldChar():Bool
@@ -416,7 +420,9 @@ class Save
function set_oldChar(value:Bool):Bool
{
return data.unlocks.oldChar = value;
data.unlocks.oldChar = value;
flush();
return data.unlocks.oldChar;
}
/**
@@ -425,7 +431,11 @@ class Save
*/
public function addCharacterSeen(character:String):Void
{
if (!data.unlocks.charactersSeen.contains(character)) data.unlocks.charactersSeen.push(character);
if (!data.unlocks.charactersSeen.contains(character))
{
data.unlocks.charactersSeen.push(character);
flush();
}
}
/**
@@ -1171,6 +1181,12 @@ typedef SaveDataOptions =
*/
var audioVisualOffset:Int;
/**
* If we want the framerate to be unlocked on HTML5.
* @default `false
*/
var unlockedFramerate:Bool;
var controls:
{
var p1:
@@ -71,12 +71,17 @@ class CharSelectSubState extends MusicBeatSubState
var availableChars:Map<Int, String> = new Map<Int, String>();
var pressedSelect:Bool = false;
var selectTimer:FlxTimer = new FlxTimer();
var selectSound:FunkinSound;
var unlockSound:FunkinSound;
var lockedSound:FunkinSound;
var introSound:FunkinSound;
var staticSound:FunkinSound;
var charSelectCam:FunkinCamera;
var selectedBizz:Array<BitmapFilter> = [
new DropShadowFilter(0, 0, 0xFFFFFF, 1, 2, 2, 21, 1, false, false, false),
new DropShadowFilter(0, 0, 0xFFFFFF, 1, 2, 2, 19, 1, false, false, false),
new DropShadowFilter(5, 45, 0x000000, 1, 2, 2, 1, 1, false, false, false)
];
@@ -125,7 +130,7 @@ class CharSelectSubState extends MusicBeatSubState
add(bg);
var crowd:FlxAtlasSprite = new FlxAtlasSprite(0, 0, Paths.animateAtlas("charSelect/crowd"));
crowd.anim.play("");
crowd.anim.play();
crowd.scrollFactor.set(0.3, 0.3);
add(crowd);
@@ -224,7 +229,7 @@ class CharSelectSubState extends MusicBeatSubState
// FlxG.debugger.track(bfChill, "bf chill");
// FlxG.debugger.track(playerChill, "player");
// FlxG.debugger.track(nametag, "nametag");
FlxG.debugger.track(selectSound, "selectSound");
// FlxG.debugger.track(selectSound, "selectSound");
// FlxG.debugger.track(chooseDipshit, "choose dipshit");
// FlxG.debugger.track(barthing, "barthing");
// FlxG.debugger.track(fgBlur, "fgBlur");
@@ -289,6 +294,26 @@ class CharSelectSubState extends MusicBeatSubState
FlxG.sound.defaultSoundGroup.add(unlockSound);
FlxG.sound.list.add(unlockSound);
lockedSound = new FunkinSound();
lockedSound.loadEmbedded(Paths.sound('CS_locked'));
lockedSound.pitch = 1;
lockedSound.volume = 1.;
FlxG.sound.defaultSoundGroup.add(lockedSound);
FlxG.sound.list.add(lockedSound);
staticSound = new FunkinSound();
staticSound.loadEmbedded(Paths.sound('static loop'));
staticSound.pitch = 1;
staticSound.looped = true;
staticSound.volume = 0.6;
FlxG.sound.defaultSoundGroup.add(staticSound);
FlxG.sound.list.add(staticSound);
// playing it here to preload it. not doing this makes a super awkward pause at the end of the intro
// TODO: probably make an intro thing for funkinSound itself that preloads the next audio?
FunkinSound.playMusic('stayFunky',
@@ -324,6 +349,9 @@ class CharSelectSubState extends MusicBeatSubState
// FlxG.camera.follow(camFollow, LOCKON, 0.01);
FlxG.camera.follow(camFollow, LOCKON);
var fadeShaderFilter:ShaderFilter = new ShaderFilter(fadeShader);
FlxG.camera.filters = [fadeShaderFilter];
var temp:FlxSprite = new FlxSprite();
temp.loadGraphic(Paths.image('charSelect/placement'));
add(temp);
@@ -356,10 +384,24 @@ class CharSelectSubState extends MusicBeatSubState
blackScreen.y = -(FlxG.height * 0.5);
add(blackScreen);
introSound = new FunkinSound();
introSound.loadEmbedded(Paths.sound('CS_Lights'));
introSound.pitch = 1;
introSound.volume = 0;
FlxG.sound.defaultSoundGroup.add(introSound);
FlxG.sound.list.add(introSound);
openSubState(new IntroSubState());
subStateClosed.addOnce((_) -> {
remove(blackScreen);
if (!Save.instance.oldChar) camera.flash();
if (!Save.instance.oldChar)
{
camera.flash();
introSound.volume = 1;
introSound.play(true);
}
checkNewChar();
Save.instance.oldChar = true;
@@ -368,7 +410,7 @@ class CharSelectSubState extends MusicBeatSubState
function checkNewChar():Void
{
if (nonLocks.length > 0) selectTimer.start(0.5, (_) -> {
if (nonLocks.length > 0) selectTimer.start(2, (_) -> {
unLock();
});
else
@@ -503,7 +545,7 @@ class CharSelectSubState extends MusicBeatSubState
updateIconPositions();
playerChillOut.onAnimationComplete.addOnce((_) -> if (_ == "death")
{
sync = false;
// sync = false;
playerChillOut.visible = false;
playerChillOut.switchChar(char);
});
@@ -513,6 +555,9 @@ class CharSelectSubState extends MusicBeatSubState
{
pressedSelect = false;
@:bypassAccessor curChar = char;
staticSound.stop();
FunkinSound.playMusic('stayFunky',
{
startingVolume: 1,
@@ -565,7 +610,7 @@ class CharSelectSubState extends MusicBeatSubState
function syncAudio(elapsed:Float):Void
{
@:privateAccess
if (sync && !unlockSound.paused)
if (sync && unlockSound.time > 0)
{
// if (playerChillOut.anim.framerate > 0)
// {
@@ -576,12 +621,12 @@ class CharSelectSubState extends MusicBeatSubState
playerChillOut.anim._tick = 0;
if (syncLock != null) syncLock.anim._tick = 0;
if ((unlockSound.time - audioBizz) >= (delay * 1000))
if ((unlockSound.time - audioBizz) >= ((delay) * 100))
{
if (syncLock != null) syncLock.anim._tick = delay;
playerChillOut.anim._tick = delay;
audioBizz += delay * 1000;
audioBizz += delay * 100;
}
}
}
@@ -728,8 +773,11 @@ class CharSelectSubState extends MusicBeatSubState
cursorY = -1;
}
if (availableChars.exists(getCurrentSelected()) && Save.instance.charactersSeen.contains(availableChars[getCurrentSelected()]))
if (autoFollow
&& availableChars.exists(getCurrentSelected())
&& Save.instance.charactersSeen.contains(availableChars[getCurrentSelected()]))
{
gfChill.visible = true;
curChar = availableChars.get(getCurrentSelected());
if (!pressedSelect && controls.ACCEPT)
@@ -746,7 +794,7 @@ class CharSelectSubState extends MusicBeatSubState
FlxTween.tween(FlxG.sound.music, {pitch: 0.1}, 1, {ease: FlxEase.quadInOut});
FlxTween.tween(FlxG.sound.music, {volume: 0.0}, 1.5, {ease: FlxEase.quadInOut});
playerChill.playAnimation("select");
gfChill.playAnimation("confirm");
gfChill.playAnimation("confirm", true, false, true);
pressedSelect = true;
selectTimer.start(1.5, (_) -> {
// pressedSelect = false;
@@ -774,17 +822,22 @@ class CharSelectSubState extends MusicBeatSubState
{
ease: FlxEase.quartInOut,
onComplete: (_) -> {
playerChill.playAnimation("idle", true, false, true);
gfChill.playAnimation("idle", true, false, true);
if (playerChill.getCurrentAnimation() == "deselect loop start" || playerChill.getCurrentAnimation() == "deselect")
{
playerChill.playAnimation("idle", true, false, true);
gfChill.playAnimation("idle", true, false, true);
}
}
});
selectTimer.cancel();
}
}
else
else if (autoFollow)
{
curChar = "locked";
gfChill.visible = false;
if (controls.ACCEPT)
{
cursorDenied.visible = true;
@@ -792,6 +845,9 @@ class CharSelectSubState extends MusicBeatSubState
cursorDenied.y = cursor.y - 4;
playerChill.playAnimation("cannot select Label", true);
lockedSound.play(true);
cursorDenied.animation.play("idle", true);
cursorDenied.animation.finishCallback = (_) -> {
cursorDenied.visible = false;
@@ -948,7 +1004,7 @@ class CharSelectSubState extends MusicBeatSubState
memb.scale.set(2.6, 2.6);
}
if (pressedSelect && memb.animation.curAnim.name == "idle") memb.animation.play("confirm");
if (!pressedSelect && memb.animation.curAnim.name != "idle")
if (autoFollow && !pressedSelect && memb.animation.curAnim.name != "idle")
{
memb.animation.play("confirm", false, true);
member.animation.finishCallback = (_) -> {
@@ -981,6 +1037,10 @@ class CharSelectSubState extends MusicBeatSubState
curChar = value;
if (value == "locked") staticSound.play();
else
staticSound.stop();
nametag.switchChar(value);
playerChill.visible = false;
playerChillOut.visible = true;
+4 -15
View File
@@ -17,8 +17,6 @@ class IntroSubState extends MusicBeatSubState
{
static final LIGHTS_VIDEO_PATH:String = Paths.stripLibrary(Paths.videos('introSelect'));
var introSound:FunkinSound = null;
public override function create():Void
{
if (Save.instance.oldChar)
@@ -43,19 +41,10 @@ class IntroSubState extends MusicBeatSubState
playVideoNative(LIGHTS_VIDEO_PATH);
#end
// Im TOO lazy to even care, so uh, yep
FlxG.camera.zoom = 0.66666666666666666666666666666667;
vid.x = -(FlxG.width - (FlxG.width * FlxG.camera.zoom));
vid.y = -((FlxG.height - (FlxG.height * FlxG.camera.zoom)) * 0.75);
introSound = new FunkinSound();
introSound.loadEmbedded(Paths.sound('CS_Lights'));
introSound.pitch = 1;
FlxG.sound.defaultSoundGroup.add(introSound);
FlxG.sound.list.add(introSound);
introSound.play(true);
// // Im TOO lazy to even care, so uh, yep
// FlxG.camera.zoom = 0.66666666666666666666666666666667;
// vid.x = -(FlxG.width - (FlxG.width * FlxG.camera.zoom));
// vid.y = -((FlxG.height - (FlxG.height * FlxG.camera.zoom)) * 0.75);
}
#if html5
+2 -5
View File
@@ -358,10 +358,6 @@ class FreeplayState extends MusicBeatSubState
if (availableDifficultiesForSong.length == 0) continue;
songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations));
for (difficulty in availableDifficultiesForSong)
{
diffIdsTotal.pushUnique(difficulty);
}
for (difficulty in unsuffixedDifficulties)
{
diffIdsTotal.pushUnique(difficulty);
@@ -1789,12 +1785,13 @@ class FreeplayState extends MusicBeatSubState
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(daSong.songId, suffixedDifficulty);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes);
rememberedDifficulty = currentDifficulty;
rememberedDifficulty = suffixedDifficulty;
}
else
{
intendedScore = 0;
intendedCompletion = 0.0;
rememberedDifficulty = currentDifficulty;
}
if (intendedCompletion == Math.POSITIVE_INFINITY || intendedCompletion == Math.NEGATIVE_INFINITY || Math.isNaN(intendedCompletion))
+4 -1
View File
@@ -437,7 +437,10 @@ class MainMenuState extends MusicBeatState
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.N)
{
@:privateAccess
funkin.save.Save.instance.data.unlocks.charactersSeen = ["bf"];
{
funkin.save.Save.instance.data.unlocks.charactersSeen = ["bf"];
funkin.save.Save.instance.data.unlocks.oldChar = false;
}
}
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.E)
@@ -72,6 +72,12 @@ class PreferencesMenu extends Page
createPrefItemCheckbox('Auto Pause', 'Automatically pause the game when it loses focus', function(value:Bool):Void {
Preferences.autoPause = value;
}, Preferences.autoPause);
#if web
createPrefItemCheckbox('Unlocked Framerate', 'Enable to unlock the framerate', function(value:Bool):Void {
Preferences.unlockedFramerate = value;
}, Preferences.unlockedFramerate);
#end
}
override function update(elapsed:Float):Void