1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2025-11-29 15:56:06 +00:00

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

This commit is contained in:
Cameron Taylor 2024-09-12 20:04:02 -04:00
commit e2a51def65
16 changed files with 187 additions and 69 deletions

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.

2
art

@ -1 +1 @@
Subproject commit 0bb988c49788fd25a230b56dd9e4448838bc79c9
Subproject commit 0dee03f11afc01c2883da223fa10405f7011dd33

2
assets

@ -1 +1 @@
Subproject commit 350910d8094853d11deb2ee27cacbe3ada27af32
Subproject commit 86a0a01e188a80a51b88a0a4188609f2db452bab

View file

@ -194,7 +194,7 @@
"name": "polymod",
"type": "git",
"dir": null,
"ref": "96cfc5fa693b017e47f7cb13b765cc68698fa6b6",
"ref": "0fbdf27fe124549730accd540cec8a183f8652c0",
"url": "https://github.com/larsiusprime/polymod"
},
{

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))

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

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
{

View file

@ -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> = [];

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
});
}
});

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)

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:

View file

@ -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;

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

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))

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)

View file

@ -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