2023-11-07 09:04:22 +00:00
|
|
|
package funkin.ui.mainmenu;
|
2020-11-01 01:11:14 +00:00
|
|
|
|
2024-04-05 05:24:03 +00:00
|
|
|
import funkin.graphics.FunkinSprite;
|
2024-03-17 02:20:22 +00:00
|
|
|
import flixel.addons.transition.FlxTransitionableState;
|
2023-06-15 04:29:54 +00:00
|
|
|
import funkin.ui.debug.DebugMenuSubState;
|
2020-11-01 01:11:14 +00:00
|
|
|
import flixel.FlxObject;
|
|
|
|
import flixel.FlxSprite;
|
2021-02-15 22:04:08 +00:00
|
|
|
import flixel.FlxState;
|
2021-02-12 06:20:20 +00:00
|
|
|
import flixel.addons.transition.FlxTransitionableState;
|
2020-11-01 01:11:14 +00:00
|
|
|
import flixel.effects.FlxFlicker;
|
|
|
|
import flixel.graphics.frames.FlxAtlasFrames;
|
2024-02-06 00:46:11 +00:00
|
|
|
import flixel.util.typeLimit.NextState;
|
2020-11-01 01:11:14 +00:00
|
|
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
2021-08-23 22:52:38 +00:00
|
|
|
import flixel.input.touch.FlxTouch;
|
2020-11-07 02:17:27 +00:00
|
|
|
import flixel.text.FlxText;
|
2024-03-12 03:42:32 +00:00
|
|
|
import funkin.data.song.SongData.SongMusicData;
|
2020-11-01 01:11:14 +00:00
|
|
|
import flixel.tweens.FlxEase;
|
2024-02-13 06:38:11 +00:00
|
|
|
import funkin.graphics.FunkinCamera;
|
2024-03-12 03:42:32 +00:00
|
|
|
import funkin.audio.FunkinSound;
|
2020-11-01 01:11:14 +00:00
|
|
|
import flixel.tweens.FlxTween;
|
2023-11-07 09:04:22 +00:00
|
|
|
import funkin.ui.MusicBeatState;
|
2021-02-15 22:04:08 +00:00
|
|
|
import flixel.util.FlxTimer;
|
2022-03-08 08:13:53 +00:00
|
|
|
import funkin.ui.AtlasMenuList;
|
2023-11-07 09:04:22 +00:00
|
|
|
import funkin.ui.freeplay.FreeplayState;
|
2022-03-08 08:13:53 +00:00
|
|
|
import funkin.ui.MenuList;
|
2023-08-08 19:41:25 +00:00
|
|
|
import funkin.ui.title.TitleState;
|
2023-05-17 20:42:58 +00:00
|
|
|
import funkin.ui.story.StoryMenuState;
|
2022-03-08 08:13:53 +00:00
|
|
|
import funkin.ui.Prompt;
|
2022-03-27 02:18:26 +00:00
|
|
|
import funkin.util.WindowUtil;
|
2021-03-30 04:05:21 +00:00
|
|
|
#if discord_rpc
|
2021-03-23 04:05:46 +00:00
|
|
|
import Discord.DiscordClient;
|
|
|
|
#end
|
2021-02-20 04:10:16 +00:00
|
|
|
#if newgrounds
|
2022-03-08 08:13:53 +00:00
|
|
|
import funkin.ui.NgPrompt;
|
2022-04-15 21:11:01 +00:00
|
|
|
import io.newgrounds.NG;
|
2021-02-20 04:10:16 +00:00
|
|
|
#end
|
|
|
|
|
2020-11-01 01:11:14 +00:00
|
|
|
class MainMenuState extends MusicBeatState
|
|
|
|
{
|
2023-01-23 03:25:45 +00:00
|
|
|
var menuItems:MenuTypedList<AtlasMenuItem>;
|
|
|
|
|
|
|
|
var magenta:FlxSprite;
|
|
|
|
var camFollow:FlxObject;
|
|
|
|
|
|
|
|
override function create()
|
|
|
|
{
|
|
|
|
#if discord_rpc
|
|
|
|
// Updating Discord Rich Presence
|
|
|
|
DiscordClient.changePresence("In the Menus", null);
|
|
|
|
#end
|
|
|
|
|
|
|
|
transIn = FlxTransitionableState.defaultTransIn;
|
|
|
|
transOut = FlxTransitionableState.defaultTransOut;
|
|
|
|
|
2024-03-28 06:57:51 +00:00
|
|
|
playMenuMusic();
|
2023-01-23 03:25:45 +00:00
|
|
|
|
2024-03-29 02:33:50 +00:00
|
|
|
persistentUpdate = false;
|
|
|
|
persistentDraw = true;
|
2023-01-23 03:25:45 +00:00
|
|
|
|
2024-04-05 05:24:03 +00:00
|
|
|
var bg = FunkinSprite.create('menuDesat');
|
2024-04-15 23:21:55 +00:00
|
|
|
|
2024-04-05 05:24:03 +00:00
|
|
|
bg.color = 0xFFFDE871;
|
2024-04-15 23:21:55 +00:00
|
|
|
// This line accounts for the fact that the base color of menuDesat is #EFEFEF.
|
|
|
|
flixel.util.FlxColorTransformUtil.setOffsets(bg.colorTransform, 30, 27, 13, 0.0);
|
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
bg.scrollFactor.x = 0;
|
|
|
|
bg.scrollFactor.y = 0.17;
|
|
|
|
bg.setGraphicSize(Std.int(bg.width * 1.2));
|
|
|
|
bg.updateHitbox();
|
|
|
|
bg.screenCenter();
|
|
|
|
add(bg);
|
|
|
|
|
|
|
|
camFollow = new FlxObject(0, 0, 1, 1);
|
|
|
|
add(camFollow);
|
|
|
|
|
|
|
|
magenta = new FlxSprite(Paths.image('menuDesat'));
|
|
|
|
magenta.scrollFactor.x = bg.scrollFactor.x;
|
|
|
|
magenta.scrollFactor.y = bg.scrollFactor.y;
|
|
|
|
magenta.setGraphicSize(Std.int(bg.width));
|
|
|
|
magenta.updateHitbox();
|
|
|
|
magenta.x = bg.x;
|
|
|
|
magenta.y = bg.y;
|
|
|
|
magenta.visible = false;
|
|
|
|
magenta.color = 0xFFfd719b;
|
2023-10-17 04:38:28 +00:00
|
|
|
|
|
|
|
// TODO: Why doesn't this line compile I'm going fucking feral
|
|
|
|
|
|
|
|
if (Preferences.flashingLights) add(magenta);
|
2023-01-23 03:25:45 +00:00
|
|
|
|
|
|
|
menuItems = new MenuTypedList<AtlasMenuItem>();
|
|
|
|
add(menuItems);
|
|
|
|
menuItems.onChange.add(onMenuItemChange);
|
2023-03-16 04:55:25 +00:00
|
|
|
menuItems.onAcceptPress.add(function(_) {
|
2023-01-23 03:25:45 +00:00
|
|
|
if (_.name == 'freeplay')
|
|
|
|
{
|
|
|
|
magenta.visible = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FlxFlicker.flicker(magenta, 1.1, 0.15, false, true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
menuItems.enabled = true; // can move on intro
|
2024-02-06 00:46:11 +00:00
|
|
|
createMenuItem('storymode', 'mainmenu/storymode', function() startExitState(() -> new StoryMenuState()));
|
2023-03-16 04:55:25 +00:00
|
|
|
createMenuItem('freeplay', 'mainmenu/freeplay', function() {
|
2023-01-23 03:25:45 +00:00
|
|
|
persistentDraw = true;
|
|
|
|
persistentUpdate = false;
|
2023-08-02 15:00:23 +00:00
|
|
|
// Freeplay has its own custom transition
|
2024-03-17 02:20:22 +00:00
|
|
|
FlxTransitionableState.skipNextTransIn = true;
|
|
|
|
FlxTransitionableState.skipNextTransOut = true;
|
2023-01-23 03:25:45 +00:00
|
|
|
openSubState(new FreeplayState());
|
|
|
|
});
|
|
|
|
|
|
|
|
#if CAN_OPEN_LINKS
|
2024-03-28 06:57:51 +00:00
|
|
|
// In order to prevent popup blockers from triggering,
|
|
|
|
// we need to open the link as an immediate result of a keypress event,
|
|
|
|
// so we can't wait for the flicker animation to complete.
|
2023-01-23 03:25:45 +00:00
|
|
|
var hasPopupBlocker = #if web true #else false #end;
|
2024-03-28 06:57:51 +00:00
|
|
|
createMenuItem('merch', 'mainmenu/merch', selectMerch, hasPopupBlocker);
|
2023-01-23 03:25:45 +00:00
|
|
|
#end
|
|
|
|
|
2023-03-16 04:55:25 +00:00
|
|
|
createMenuItem('options', 'mainmenu/options', function() {
|
2024-02-06 00:46:11 +00:00
|
|
|
startExitState(() -> new funkin.ui.options.OptionsState());
|
2023-01-23 03:25:45 +00:00
|
|
|
});
|
|
|
|
|
2024-03-28 06:57:51 +00:00
|
|
|
createMenuItem('credits', 'mainmenu/credits', function() {
|
2024-03-26 16:33:54 +00:00
|
|
|
startExitState(() -> new funkin.ui.credits.CreditsState());
|
|
|
|
});
|
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
// Reset position of menu items.
|
|
|
|
var spacing = 160;
|
|
|
|
var top = (FlxG.height - (spacing * (menuItems.length - 1))) / 2;
|
|
|
|
for (i in 0...menuItems.length)
|
|
|
|
{
|
|
|
|
var menuItem = menuItems.members[i];
|
|
|
|
menuItem.x = FlxG.width / 2;
|
|
|
|
menuItem.y = top + spacing * i;
|
2024-03-26 16:33:54 +00:00
|
|
|
menuItem.scrollFactor.x = 0.0;
|
|
|
|
// This one affects how much the menu items move when you scroll between them.
|
|
|
|
menuItem.scrollFactor.y = 0.4;
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
|
|
|
|
2023-03-16 04:55:25 +00:00
|
|
|
resetCamStuff();
|
|
|
|
|
|
|
|
subStateClosed.add(_ -> {
|
|
|
|
resetCamStuff();
|
|
|
|
});
|
|
|
|
|
|
|
|
subStateOpened.add(sub -> {
|
|
|
|
if (Type.getClass(sub) == FreeplayState)
|
|
|
|
{
|
|
|
|
new FlxTimer().start(0.5, _ -> {
|
|
|
|
magenta.visible = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
// FlxG.camera.setScrollBounds(bg.x, bg.x + bg.width, bg.y, bg.y + bg.height * 1.2);
|
|
|
|
|
|
|
|
super.create();
|
|
|
|
|
|
|
|
// This has to come AFTER!
|
|
|
|
this.leftWatermarkText.text = Constants.VERSION;
|
|
|
|
// this.rightWatermarkText.text = "blablabla test";
|
|
|
|
|
|
|
|
// NG.core.calls.event.logEvent('swag').send();
|
|
|
|
}
|
|
|
|
|
2024-03-12 03:42:32 +00:00
|
|
|
function playMenuMusic():Void
|
|
|
|
{
|
2024-03-23 21:50:48 +00:00
|
|
|
FunkinSound.playMusic('freakyMenu',
|
|
|
|
{
|
|
|
|
overrideExisting: true,
|
|
|
|
restartTrack: false
|
|
|
|
});
|
2024-03-12 03:42:32 +00:00
|
|
|
}
|
|
|
|
|
2023-03-16 04:55:25 +00:00
|
|
|
function resetCamStuff()
|
|
|
|
{
|
2024-02-13 06:38:11 +00:00
|
|
|
FlxG.cameras.reset(new FunkinCamera());
|
2023-03-16 04:55:25 +00:00
|
|
|
FlxG.camera.follow(camFollow, null, 0.06);
|
2024-04-09 19:10:58 +00:00
|
|
|
FlxG.camera.snapToTarget();
|
2023-03-16 04:55:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
function createMenuItem(name:String, atlas:String, callback:Void->Void, fireInstantly:Bool = false):Void
|
|
|
|
{
|
|
|
|
var item = new AtlasMenuItem(name, Paths.getSparrowAtlas(atlas), callback);
|
|
|
|
item.fireInstantly = fireInstantly;
|
|
|
|
item.ID = menuItems.length;
|
|
|
|
|
|
|
|
item.scrollFactor.set();
|
|
|
|
|
|
|
|
// Set the offset of the item so the sprite is centered on the origin.
|
|
|
|
item.centered = true;
|
|
|
|
item.changeAnim('idle');
|
|
|
|
|
|
|
|
menuItems.addItem(name, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
override function closeSubState()
|
|
|
|
{
|
|
|
|
magenta.visible = false;
|
|
|
|
|
|
|
|
super.closeSubState();
|
|
|
|
}
|
|
|
|
|
|
|
|
override function finishTransIn()
|
|
|
|
{
|
|
|
|
super.finishTransIn();
|
|
|
|
|
|
|
|
// menuItems.enabled = true;
|
|
|
|
|
|
|
|
// #if newgrounds
|
|
|
|
// if (NGio.savedSessionFailed)
|
|
|
|
// showSavedSessionFailed();
|
|
|
|
// #end
|
|
|
|
}
|
|
|
|
|
2023-11-07 09:04:22 +00:00
|
|
|
function onMenuItemChange(selected:MenuListItem)
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
|
|
|
camFollow.setPosition(selected.getGraphicMidpoint().x, selected.getGraphicMidpoint().y);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if CAN_OPEN_LINKS
|
|
|
|
function selectDonate()
|
|
|
|
{
|
|
|
|
WindowUtil.openURL(Constants.URL_ITCH);
|
|
|
|
}
|
2024-03-28 06:57:51 +00:00
|
|
|
|
|
|
|
function selectMerch()
|
|
|
|
{
|
|
|
|
WindowUtil.openURL(Constants.URL_MERCH);
|
|
|
|
}
|
2023-01-23 03:25:45 +00:00
|
|
|
#end
|
|
|
|
|
|
|
|
#if newgrounds
|
|
|
|
function selectLogin()
|
|
|
|
{
|
|
|
|
openNgPrompt(NgPrompt.showLogin());
|
|
|
|
}
|
|
|
|
|
|
|
|
function selectLogout()
|
|
|
|
{
|
|
|
|
openNgPrompt(NgPrompt.showLogout());
|
|
|
|
}
|
|
|
|
|
|
|
|
function showSavedSessionFailed()
|
|
|
|
{
|
|
|
|
openNgPrompt(NgPrompt.showSavedSessionFailed());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls openPrompt and redraws the login/logout button
|
2023-06-08 20:30:45 +00:00
|
|
|
* @param prompt
|
|
|
|
* @param onClose
|
2023-01-23 03:25:45 +00:00
|
|
|
*/
|
|
|
|
public function openNgPrompt(prompt:Prompt, ?onClose:Void->Void)
|
|
|
|
{
|
|
|
|
var onPromptClose = checkLoginStatus;
|
|
|
|
if (onClose != null)
|
|
|
|
{
|
2023-03-16 04:55:25 +00:00
|
|
|
onPromptClose = function() {
|
2023-01-23 03:25:45 +00:00
|
|
|
checkLoginStatus();
|
|
|
|
onClose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
openPrompt(prompt, onPromptClose);
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkLoginStatus()
|
|
|
|
{
|
|
|
|
var prevLoggedIn = menuItems.has("logout");
|
|
|
|
if (prevLoggedIn && !NGio.isLoggedIn) menuItems.resetItem("login", "logout", selectLogout);
|
|
|
|
else if (!prevLoggedIn && NGio.isLoggedIn) menuItems.resetItem("logout", "login", selectLogin);
|
|
|
|
}
|
|
|
|
#end
|
|
|
|
|
|
|
|
public function openPrompt(prompt:Prompt, onClose:Void->Void)
|
|
|
|
{
|
|
|
|
menuItems.enabled = false;
|
2023-03-16 04:55:25 +00:00
|
|
|
prompt.closeCallback = function() {
|
2023-01-23 03:25:45 +00:00
|
|
|
menuItems.enabled = true;
|
|
|
|
if (onClose != null) onClose();
|
|
|
|
}
|
|
|
|
|
|
|
|
openSubState(prompt);
|
|
|
|
}
|
|
|
|
|
2024-02-06 00:46:11 +00:00
|
|
|
function startExitState(state:NextState)
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
|
|
|
menuItems.enabled = false; // disable for exit
|
|
|
|
var duration = 0.4;
|
2023-03-16 04:55:25 +00:00
|
|
|
menuItems.forEach(function(item) {
|
2023-01-23 03:25:45 +00:00
|
|
|
if (menuItems.selectedIndex != item.ID)
|
|
|
|
{
|
|
|
|
FlxTween.tween(item, {alpha: 0}, duration, {ease: FlxEase.quadOut});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item.visible = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
new FlxTimer().start(duration, function(_) FlxG.switchState(state));
|
|
|
|
}
|
|
|
|
|
|
|
|
override function update(elapsed:Float)
|
|
|
|
{
|
|
|
|
super.update(elapsed);
|
|
|
|
|
|
|
|
if (FlxG.onMobile)
|
|
|
|
{
|
|
|
|
var touch:FlxTouch = FlxG.touches.getFirst();
|
|
|
|
|
|
|
|
if (touch != null)
|
|
|
|
{
|
|
|
|
for (item in menuItems)
|
|
|
|
{
|
|
|
|
if (touch.overlaps(item))
|
|
|
|
{
|
|
|
|
if (menuItems.selectedIndex == item.ID && touch.justPressed) menuItems.accept();
|
|
|
|
else
|
|
|
|
menuItems.selectItem(item.ID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-16 05:02:42 +00:00
|
|
|
// Open the debug menu, defaults to ` / ~
|
|
|
|
if (controls.DEBUG_MENU)
|
2023-06-15 04:29:54 +00:00
|
|
|
{
|
|
|
|
FlxG.state.openSubState(new DebugMenuSubState());
|
|
|
|
}
|
2023-01-23 03:25:45 +00:00
|
|
|
|
|
|
|
if (FlxG.sound.music.volume < 0.8)
|
|
|
|
{
|
|
|
|
FlxG.sound.music.volume += 0.5 * elapsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_exiting) menuItems.enabled = false;
|
|
|
|
|
|
|
|
if (controls.BACK && menuItems.enabled && !menuItems.busy)
|
|
|
|
{
|
2024-03-23 21:50:48 +00:00
|
|
|
FunkinSound.playOnce(Paths.sound('cancelMenu'));
|
2024-02-06 00:46:11 +00:00
|
|
|
FlxG.switchState(() -> new TitleState());
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-01 01:11:14 +00:00
|
|
|
}
|