Add files via upload

This commit is contained in:
Zyflx 2023-05-14 14:20:35 -04:00 committed by GitHub
parent 0e5fe03b78
commit f919a81e18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 15978 additions and 0 deletions

73
source/CoolUtil.hx Normal file
View File

@ -0,0 +1,73 @@
package;
import flixel.FlxG;
import flixel.graphics.FlxGraphic;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.system.FlxAssets.FlxGraphicAsset;
import haxe.Json;
import lime.math.Rectangle;
import lime.utils.Assets;
import game.state.*;
using StringTools;
class CoolUtil
{
public static var difficultyArray:Array<String> = ['EASY', "NORMAL", "HARD"];
public static function difficultyString():String
{
return difficultyArray[PlayState.storyDifficulty];
}
public static function coolTextFile(path:String):Array<String>
{
var daList:Array<String> = Assets.getText(path).trim().split('\n');
for (i in 0...daList.length)
{
daList[i] = daList[i].trim();
}
return daList;
}
public static function numberArray(max:Int, ?min = 0):Array<Int>
{
var dumbArray:Array<Int> = [];
for (i in min...max)
{
dumbArray.push(i);
}
return dumbArray;
}
// Robbed From Psych lmfao
inline public static function boundTo(value:Float, min:Float, max:Float):Float {
return Math.max(min, Math.min(max, value));
}
/**
Lerps camera, but accountsfor framerate shit?
Right now it's simply for use to change the followLerp variable of a camera during update
TODO LATER MAYBE:
Actually make and modify the scroll and lerp shit in it's own function
instead of solely relying on changing the lerp on the fly
*/
public static function camLerpShit(lerp:Float):Float
{
return lerp * (FlxG.elapsed / (1 / 60));
}
/*
* just lerp that does camLerpShit for u so u dont have to do it every time
*/
public static function coolLerp(a:Float, b:Float, ratio:Float):Float
{
return FlxMath.lerp(a, b, camLerpShit(ratio));
}
}

143
source/Main.hx Normal file
View File

@ -0,0 +1,143 @@
package;
import flixel.FlxGame;
import flixel.FlxState;
import openfl.Assets;
import openfl.Lib;
import openfl.display.FPS;
import openfl.display.Sprite;
import openfl.events.AsyncErrorEvent;
import openfl.events.Event;
import openfl.events.MouseEvent;
import openfl.events.NetStatusEvent;
import openfl.media.Video;
import openfl.net.NetConnection;
import openfl.net.NetStream;
import game.state.menus.*;
class Main extends Sprite
{
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
var initialState:Class<FlxState> = TitleState; // The FlxState the game starts with.
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
#if web
var framerate:Int = 60; // How many frames per second the game should run at.
#else
var framerate:Int = 120; // How many frames per second the game should run at.
#end
var skipSplash:Bool = true; // Whether to skip the flixel splash screen that appears in release mode.
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
// You can pretty much ignore everything from here on - your code should go in your states.
public static function main():Void
{
Lib.current.addChild(new Main());
}
public function new()
{
super();
if (stage != null)
{
init();
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(?E:Event):Void
{
if (hasEventListener(Event.ADDED_TO_STAGE))
{
removeEventListener(Event.ADDED_TO_STAGE, init);
}
setupGame();
}
var video:Video;
var netStream:NetStream;
private var overlay:Sprite;
public static var fpsCounter:FPS;
private function setupGame():Void
{
var stageWidth:Int = Lib.current.stage.stageWidth;
var stageHeight:Int = Lib.current.stage.stageHeight;
if (zoom == -1)
{
var ratioX:Float = stageWidth / gameWidth;
var ratioY:Float = stageHeight / gameHeight;
zoom = Math.min(ratioX, ratioY);
gameWidth = Math.ceil(stageWidth / zoom);
gameHeight = Math.ceil(stageHeight / zoom);
}
#if !debug
initialState = TitleState;
#end
addChild(new FlxGame(gameWidth, gameHeight, initialState, #if (flixel < "5.0.0") zoom, #end framerate, framerate, skipSplash, startFullscreen));
#if !mobile
fpsCounter = new FPS(10, 3, 0xFFFFFF);
addChild(fpsCounter);
#end
/*
video = new Video();
addChild(video);
var netConnection = new NetConnection();
netConnection.connect(null);
netStream = new NetStream(netConnection);
netStream.client = {onMetaData: client_onMetaData};
netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, netStream_onAsyncError);
#if (js && html5)
overlay = new Sprite();
overlay.graphics.beginFill(0, 0.5);
overlay.graphics.drawRect(0, 0, 560, 320);
overlay.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown);
overlay.buttonMode = true;
addChild(overlay);
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus);
#else
netStream.play("assets/preload/music/dredd.mp4");
#end
*/
}
/*
private function client_onMetaData(metaData:Dynamic)
{
video.attachNetStream(netStream);
video.width = video.videoWidth;
video.height = video.videoHeight;
}
private function netStream_onAsyncError(event:AsyncErrorEvent):Void
{
trace("Error loading video");
}
private function netConnection_onNetStatus(event:NetStatusEvent):Void
{
}
private function overlay_onMouseDown(event:MouseEvent):Void
{
netStream.play("assets/preload/music/dredd.mp4");
}
*/
}

117
source/Paths.hx Normal file
View File

@ -0,0 +1,117 @@
package;
import flixel.FlxG;
import flixel.graphics.frames.FlxAtlasFrames;
import openfl.utils.AssetType;
import openfl.utils.Assets as OpenFlAssets;
class Paths
{
inline public static var SOUND_EXT = #if web "mp3" #else "ogg" #end;
static var currentLevel:String;
static public function setCurrentLevel(name:String)
{
currentLevel = name.toLowerCase();
}
static function getPath(file:String, type:AssetType, library:Null<String>)
{
if (library != null)
return getLibraryPath(file, library);
if (currentLevel != null)
{
var levelPath = getLibraryPathForce(file, currentLevel);
if (OpenFlAssets.exists(levelPath, type))
return levelPath;
levelPath = getLibraryPathForce(file, "shared");
if (OpenFlAssets.exists(levelPath, type))
return levelPath;
}
return getPreloadPath(file);
}
static public function getLibraryPath(file:String, library = "preload")
{
return if (library == "preload" || library == "default") getPreloadPath(file); else getLibraryPathForce(file, library);
}
inline static function getLibraryPathForce(file:String, library:String)
{
return '$library:assets/$library/$file';
}
inline static function getPreloadPath(file:String)
{
return 'assets/$file';
}
inline static public function file(file:String, type:AssetType = TEXT, ?library:String)
{
return getPath(file, type, library);
}
inline static public function txt(key:String, ?library:String)
{
return getPath('data/$key.txt', TEXT, library);
}
inline static public function xml(key:String, ?library:String)
{
return getPath('data/$key.xml', TEXT, library);
}
inline static public function json(key:String, ?library:String)
{
return getPath('data/$key.json', TEXT, library);
}
static public function sound(key:String, ?library:String)
{
return getPath('sounds/$key.$SOUND_EXT', SOUND, library);
}
inline static public function soundRandom(key:String, min:Int, max:Int, ?library:String)
{
return sound(key + FlxG.random.int(min, max), library);
}
inline static public function music(key:String, ?library:String)
{
return getPath('music/$key.$SOUND_EXT', MUSIC, library);
}
inline static public function voices(song:String)
{
return 'songs:assets/songs/${song.toLowerCase()}/Voices.$SOUND_EXT';
}
inline static public function inst(song:String)
{
return 'songs:assets/songs/${song.toLowerCase()}/Inst.$SOUND_EXT';
}
inline static public function image(key:String, ?library:String)
{
return getPath('images/$key.png', IMAGE, library);
}
inline static public function font(key:String)
{
return 'assets/fonts/$key';
}
inline static public function getSparrowAtlas(key:String, ?library:String)
{
return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library));
}
inline static public function getPackerAtlas(key:String, ?library:String)
{
return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library));
}
}

View File

@ -0,0 +1,149 @@
package animate;
// import animateAtlasPlayer.assets.AssetManager;
// import animateAtlasPlayer.core.Animation;
import animate.FlxSymbol.Parsed;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.FlxGraphic;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.system.FlxAssets.FlxGraphicAsset;
import haxe.Json;
import openfl.Assets;
import openfl.display.BitmapData;
import openfl.geom.Rectangle;
class FlxAnimate extends FlxSymbol
{
// var myAnim:Animation;
// var animBitmap:BitmapData;
var loadedQueue:Bool = false;
var swagFrames:Array<BitmapData> = [];
public function new(x:Float, y:Float)
{
var folder:String = 'tightBars';
coolParse = cast Json.parse(Assets.getText(Paths.file('images/' + folder + '/Animation.json')));
coolParse.AN.TL.L.reverse();
super(x, y, coolParse);
frames = FlxAnimate.fromAnimate(Paths.file('images/' + folder + '/spritemap1.png'), Paths.file('images/' + folder + '/spritemap1.json'));
// frames
}
override function draw()
{
super.draw();
renderFrame(coolParse.AN.TL, coolParse, true);
if (FlxG.keys.justPressed.E)
{
for (shit in FlxSymbol.nestedShit.keys())
{
for (spr in FlxSymbol.nestedShit.get(shit))
{
spr.draw();
}
}
FlxSymbol.nestedShit.clear();
}
}
var curFrame:Int = 0;
// notes to self
// account for different layers
var playingAnim:Bool = false;
var frameTickTypeShit:Float = 0;
var animFrameRate:Int = 24;
override function update(elapsed:Float)
{
super.update(elapsed);
if (FlxG.keys.justPressed.SPACE)
playingAnim = !playingAnim;
if (playingAnim)
{
frameTickTypeShit += elapsed;
// prob fix this framerate thing for higher framerates?
if (frameTickTypeShit >= 1 / 24)
{
changeFrame(1);
frameTickTypeShit = 0;
}
}
if (FlxG.keys.justPressed.RIGHT)
changeFrame(1);
if (FlxG.keys.justPressed.LEFT)
changeFrame(-1);
}
// This stuff is u
public static function fromAnimate(Source:FlxGraphicAsset, Description:String):FlxAtlasFrames
{
var graphic:FlxGraphic = FlxG.bitmap.add(Source);
if (graphic == null)
return null;
var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic);
if (frames != null)
return frames;
if (graphic == null || Description == null)
return null;
frames = new FlxAtlasFrames(graphic);
var data:AnimateObject;
var json:String = Description;
trace(json);
if (Assets.exists(json))
json = Assets.getText(json);
data = cast Json.parse(json).ATLAS;
for (sprite in data.SPRITES)
{
// probably nicer way to do this? Oh well
var swagSprite:AnimateSprite = sprite.SPRITE;
var rect = FlxRect.get(swagSprite.x, swagSprite.y, swagSprite.w, swagSprite.h);
var size = new Rectangle(0, 0, rect.width, rect.height);
var offset = FlxPoint.get(-size.left, -size.top);
var sourceSize = FlxPoint.get(size.width, size.height);
frames.addAtlasFrame(rect, sourceSize, offset, swagSprite.name);
}
return frames;
}
}
typedef AnimateObject =
{
SPRITES:Array<Dynamic>
}
typedef AnimateSprite =
{
var name:String;
var x:Int;
var y:Int;
var w:Int;
var h:Int;
var rotated:Bool;
}

324
source/animate/FlxSymbol.hx Normal file
View File

@ -0,0 +1,324 @@
package animate;
import flixel.FlxCamera;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxFrame.FlxFrameAngle;
import flixel.math.FlxAngle;
import flixel.math.FlxMatrix;
import flixel.math.FlxPoint;
import openfl.geom.Matrix;
class FlxSymbol extends FlxSprite
{
public var coolParse:Parsed;
public var oldMatrix:Array<Float> = [];
private var hasFrameByPass:Bool = false;
public function new(x:Float, y:Float, coolParsed:Parsed)
{
super(x, y);
this.coolParse = coolParsed;
var hasSymbolDictionary:Bool = Reflect.hasField(coolParse, "SD");
if (hasSymbolDictionary)
symbolAtlasShit = parseSymbolDictionary(coolParse);
}
var symbolAtlasShit:Map<String, String> = new Map();
override function draw()
{
super.draw();
}
public static var nestedShit:Map<Int, Array<FlxSymbol>> = new Map();
var symbolMap:Map<String, Animation> = new Map();
var drawQueue:Array<FlxSymbol> = [];
public var daFrame:Int = 0;
public var nestDepth:Int = 0;
public var transformMatrix:Matrix = new Matrix();
function renderFrame(TL:Timeline, coolParsed:Parsed, ?isMainLoop:Bool = false)
{
drawQueue = [];
for (layer in TL.L)
{
// layer.FR.reverse();
// var frame = layer.FR[0]
for (frame in layer.FR)
{
if (daFrame >= frame.I && daFrame < frame.I + frame.DU)
{
for (element in frame.E)
{
if (Reflect.hasField(element, 'ASI'))
{
var m3d = element.ASI.M3D;
var dumbassMatrix:Matrix = new Matrix(m3d[0], m3d[1], m3d[4], m3d[5], m3d[12], m3d[13]);
var spr:FlxSymbol = new FlxSymbol(0, 0, coolParsed);
matrixExposed = true;
spr.frames = frames;
spr.frame = spr.frames.getByName(element.ASI.N);
// dumbassMatrix.translate(origin.x, origin.y);
dumbassMatrix.concat(_matrix);
spr.matrixExposed = true;
spr.transformMatrix.concat(dumbassMatrix);
// spr._matrix.concat(spr.transformMatrix);
spr.origin.set();
spr.origin.x += origin.x;
spr.origin.y += origin.y;
spr.antialiasing = true;
spr.draw();
}
else
{
var nestedSymbol = symbolMap.get(element.SI.SN);
var nestedShit:FlxSymbol = new FlxSymbol(0, 0, coolParse);
nestedShit.frames = frames;
var swagMatrix:FlxMatrix = new FlxMatrix(element.SI.M3D[0], element.SI.M3D[1], element.SI.M3D[4], element.SI.M3D[5],
element.SI.M3D[12], element.SI.M3D[13]);
swagMatrix.concat(_matrix);
nestedShit._matrix.concat(swagMatrix);
nestedShit.origin.set(element.SI.TRP.x, element.SI.TRP.y);
// nestedShit.angle += ((180 / Math.PI) * Math.atan2(swagMatrix.b, swagMatrix.a));
// nestedShit.angle += angle;
if (symbolAtlasShit.exists(nestedSymbol.SN))
{
// nestedShit.frames.getByName(symbolAtlasShit.get(nestedSymbol.SN));
// nestedShit.draw();
}
// scale.y = Math.sqrt(_matrix.c * _matrix.c + _matrix.d * _matrix.d);
// scale.x = Math.sqrt(_matrix.a * _matrix.a + _matrix.b * _matrix.b);
// nestedShit.oldMatrix = element.SI.M3D;
nestedShit.hasFrameByPass = true;
nestedShit.nestDepth = nestDepth + 1;
nestedShit.renderFrame(nestedSymbol.TL, coolParsed);
// renderFrame(nestedSymbol.TL, coolParsed);
}
}
}
}
}
// drawQueue.reverse();
//
// for (thing in drawQueue)
// thing.draw();
}
function setDaMap(spr:FlxSymbol):Void
{
if (!nestedShit.exists(nestDepth))
nestedShit.set(nestDepth, [spr]);
else
nestedShit.get(nestDepth).push(spr);
}
function changeFrame(frameChange:Int = 0):Void
{
daFrame += frameChange;
}
function parseSymbolDictionary(coolParsed:Parsed):Map<String, String>
{
var awesomeMap:Map<String, String> = new Map();
for (symbol in coolParsed.SD.S)
{
symbolMap.set(symbol.SN, symbol);
var symbolName = symbol.SN;
for (layer in symbol.TL.L)
{
for (frame in layer.FR)
{
for (element in frame.E)
{
if (Reflect.hasField(element, 'ASI'))
{
awesomeMap.set(symbolName, element.ASI.N);
}
}
}
}
}
return awesomeMap;
}
override function drawComplex(camera:FlxCamera):Void
{
_frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, checkFlipX(), checkFlipY());
_matrix.translate(-origin.x, -origin.y);
_matrix.scale(scale.x, scale.y);
if (matrixExposed)
{
_matrix.concat(transformMatrix);
}
else
{
if (bakedRotationAngle <= 0)
{
updateTrig();
if (angle != 0)
_matrix.rotateWithTrig(_cosAngle, _sinAngle);
}
// updateSkewMatrix();
_matrix.concat(_skewMatrix);
}
_point.addPoint(origin);
if (isPixelPerfectRender(camera))
_point.floor();
_matrix.translate(_point.x, _point.y);
camera.drawPixels(_frame, framePixels, _matrix, colorTransform, blend, antialiasing);
}
var _skewMatrix:Matrix = new Matrix();
// public var transformMatrix(default, null):Matrix = new Matrix();
/**
* Bool flag showing whether transformMatrix is used for rendering or not.
* False by default, which means that transformMatrix isn't used for rendering
*/
public var matrixExposed:Bool = false;
public var skew(default, null):FlxPoint = FlxPoint.get();
function updateSkewMatrix():Void
{
_skewMatrix.identity();
if (skew.x != 0 || skew.y != 0)
{
_skewMatrix.b = Math.tan(skew.y * FlxAngle.TO_RAD);
_skewMatrix.c = Math.tan(skew.x * FlxAngle.TO_RAD);
}
}
}
// TYPEDEFS FOR ANIMATION.JSON PARSING
typedef Parsed =
{
var MD:Metadata;
var AN:Animation;
var SD:SymbolDictionary; // Doesn't always have symbol dictionary!!
}
typedef Metadata =
{
/** Framerate */
var FRT:Int;
}
/** Basically treated like one big symbol*/
typedef Animation =
{
/** symbolName */
var SN:String;
var TL:Timeline;
/** IDK what STI stands for, Symbole Type Instance?
Anyways, it is NOT used in SYMBOLS, only the main AN animation
*/
var STI:Dynamic;
}
/** DISCLAIMER, MAY NOT ACTUALLY BE CALLED
SYMBOL TYPE ISNTANCE, IM JUST MAKING ASSUMPTION!! */
typedef SymbolTypeInstance =
{
// var TL:Timeline;
// var SN:String;
}
typedef SymbolDictionary =
{
var S:Array<Animation>;
}
typedef Timeline =
{
/** Layers */
var L:Array<Layer>;
}
// Singular layer, not to be confused with LAYERS
typedef Layer =
{
var LN:String;
/** Frames */
var FR:Array<Frame>;
}
typedef Frame =
{
var I:Int;
/** Duration, in frames*/
var DU:Int;
/** Elements*/
var E:Array<Element>;
}
typedef Element =
{
var SI:SymbolInstance;
var ASI:AtlasSymbolInstance;
}
/**
Symbol instance, for SYMBOLS and refers to SYMBOLS
*/
typedef SymbolInstance =
{
var SN:String;
/** SymbolType (Graphic, Movieclip, Button)*/
var ST:String;
var TRP:TransformationPoint;
var M3D:Array<Float>;
}
typedef AtlasSymbolInstance =
{
var N:String;
var M3D:Array<Float>;
}
typedef TransformationPoint =
{
var x:Float;
var y:Float;
}

View File

@ -0,0 +1,253 @@
package game.data;
import game.state.menus.options.controls.Controls;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.input.actions.FlxActionInput;
import flixel.input.gamepad.FlxGamepad;
import flixel.util.FlxSignal;
// import ui.DeviceManager;
// import props.Player;
class PlayerSettings
{
static public var numPlayers(default, null) = 0;
static public var numAvatars(default, null) = 0;
static public var player1(default, null):PlayerSettings;
static public var player2(default, null):PlayerSettings;
static public var onAvatarAdd(default, null) = new FlxTypedSignal<PlayerSettings->Void>();
static public var onAvatarRemove(default, null) = new FlxTypedSignal<PlayerSettings->Void>();
public var id(default, null):Int;
public var controls(default, null):Controls;
// public var avatar:Player;
// public var camera(get, never):PlayCamera;
function new(id)
{
this.id = id;
this.controls = new Controls('player$id', None);
#if CLEAR_INPUT_SAVE
FlxG.save.data.controls = null;
FlxG.save.flush();
#end
var useDefault = true;
var controlData = FlxG.save.data.controls;
if (controlData != null)
{
var keyData:Dynamic = null;
if (id == 0 && controlData.p1 != null && controlData.p1.keys != null)
keyData = controlData.p1.keys;
else if (id == 1 && controlData.p2 != null && controlData.p2.keys != null)
keyData = controlData.p2.keys;
if (keyData != null)
{
useDefault = false;
trace("loaded key data: " + haxe.Json.stringify(keyData));
controls.fromSaveData(keyData, Keys);
}
}
if (useDefault)
controls.setKeyboardScheme(Solo);
}
function addGamepad(gamepad:FlxGamepad)
{
var useDefault = true;
var controlData = FlxG.save.data.controls;
if (controlData != null)
{
var padData:Dynamic = null;
if (id == 0 && controlData.p1 != null && controlData.p1.pad != null)
padData = controlData.p1.pad;
else if (id == 1 && controlData.p2 != null && controlData.p2.pad != null)
padData = controlData.p2.pad;
if (padData != null)
{
useDefault = false;
trace("loaded pad data: " + haxe.Json.stringify(padData));
controls.addGamepadWithSaveData(gamepad.id, padData);
}
}
if (useDefault)
controls.addDefaultGamepad(gamepad.id);
}
public function saveControls()
{
if (FlxG.save.data.controls == null)
FlxG.save.data.controls = {};
var playerData:{ ?keys:Dynamic, ?pad:Dynamic }
if (id == 0)
{
if (FlxG.save.data.controls.p1 == null)
FlxG.save.data.controls.p1 = {};
playerData = FlxG.save.data.controls.p1;
}
else
{
if (FlxG.save.data.controls.p2 == null)
FlxG.save.data.controls.p2 = {};
playerData = FlxG.save.data.controls.p2;
}
var keyData = controls.createSaveData(Keys);
if (keyData != null)
{
playerData.keys = keyData;
trace("saving key data: " + haxe.Json.stringify(keyData));
}
if (controls.gamepadsAdded.length > 0)
{
var padData = controls.createSaveData(Gamepad(controls.gamepadsAdded[0]));
if (padData != null)
{
trace("saving pad data: " + haxe.Json.stringify(padData));
playerData.pad = padData;
}
}
FlxG.save.flush();
}
static public function init():Void
{
if (player1 == null)
{
player1 = new PlayerSettings(0);
++numPlayers;
}
FlxG.gamepads.deviceConnected.add(onGamepadAdded);
var numGamepads = FlxG.gamepads.numActiveGamepads;
for (i in 0...numGamepads)
{
var gamepad = FlxG.gamepads.getByID(i);
if (gamepad != null)
onGamepadAdded(gamepad);
}
// player1.controls.addDefaultGamepad(0);
// }
// if (numGamepads > 1)
// {
// if (player2 == null)
// {
// player2 = new PlayerSettings(1, None);
// ++numPlayers;
// }
// var gamepad = FlxG.gamepads.getByID(1);
// if (gamepad == null)
// throw 'Unexpected null gamepad. id:0';
// player2.controls.addDefaultGamepad(1);
// }
// DeviceManager.init();
}
static function onGamepadAdded(gamepad:FlxGamepad)
{
player1.addGamepad(gamepad);
}
/*
public function setKeyboardScheme(scheme)
{
controls.setKeyboardScheme(scheme);
}
static public function addAvatar(avatar:Player):PlayerSettings
{
var settings:PlayerSettings;
if (player1 == null)
{
player1 = new PlayerSettings(0, Solo);
++numPlayers;
}
if (player1.avatar == null)
settings = player1;
else
{
if (player2 == null)
{
if (player1.controls.keyboardScheme.match(Duo(true)))
player2 = new PlayerSettings(1, Duo(false));
else
player2 = new PlayerSettings(1, None);
++numPlayers;
}
if (player2.avatar == null)
settings = player2;
else
throw throw 'Invalid number of players: ${numPlayers + 1}';
}
++numAvatars;
settings.avatar = avatar;
avatar.settings = settings;
splitCameras();
onAvatarAdd.dispatch(settings);
return settings;
}
static public function removeAvatar(avatar:Player):Void
{
var settings:PlayerSettings;
if (player1 != null && player1.avatar == avatar)
settings = player1;
else if (player2 != null && player2.avatar == avatar)
{
settings = player2;
if (player1.controls.keyboardScheme.match(Duo(_)))
player1.setKeyboardScheme(Solo);
}
else
throw "Cannot remove avatar that is not for a player";
settings.avatar = null;
while (settings.controls.gamepadsAdded.length > 0)
{
final id = settings.controls.gamepadsAdded.shift();
settings.controls.removeGamepad(id);
DeviceManager.releaseGamepad(FlxG.gamepads.getByID(id));
}
--numAvatars;
splitCameras();
onAvatarRemove.dispatch(avatar.settings);
}
*/
static public function reset()
{
player1 = null;
player2 = null;
numPlayers = 0;
}
}

View File

@ -0,0 +1,89 @@
package game.data.backend;
import game.data.backend.*;
import game.data.backend.Song.SwagSong;
/**
* ...
* @author
*/
typedef BPMChangeEvent =
{
var stepTime:Int;
var songTime:Float;
var bpm:Float;
}
class Conductor
{
public static var bpm:Float = 100;
public static var crochet:Float = ((60 / bpm) * 1000); // beats in milliseconds
public static var stepCrochet:Float = crochet / 4; // steps in milliseconds
public static var songPosition:Float;
public static var lastSongPos:Float;
public static var offset:Float = 0;
public static var safeFrames:Int = 10;
public static var safeZoneOffset:Float = (safeFrames / 60) * 1000; // is calculated in create(), is safeFrames in milliseconds
public static var bpmChangeMap:Array<BPMChangeEvent> = [];
public function new()
{
}
public static function findRating(diff:Float)
{
var ratingData:Array<Dynamic> = [['sick', 45], ['good', 90], ['bad', 135]];
for (i in 0...ratingData.length)
{
if (diff <= ratingData[i][1])
{
return ratingData[i][0];
}
}
return 'shit';
}
public static function getRatingScore(diff:Float)
{
return (findRating(diff) == 'sick' ? 350 : findRating(diff) == 'good' ? 200 :
findRating(diff) == 'bad' ? 100 : findRating(diff) == 'shit' ? 50 : 0);
}
public static function mapBPMChanges(song:SwagSong)
{
bpmChangeMap = [];
var curBPM:Float = song.bpm;
var totalSteps:Int = 0;
var totalPos:Float = 0;
for (i in 0...song.notes.length)
{
if(song.notes[i].changeBPM && song.notes[i].bpm != curBPM)
{
curBPM = song.notes[i].bpm;
var event:BPMChangeEvent = {
stepTime: totalSteps,
songTime: totalPos,
bpm: curBPM
};
bpmChangeMap.push(event);
}
var deltaSteps:Int = song.notes[i].lengthInSteps;
totalSteps += deltaSteps;
totalPos += ((60 / curBPM) * 1000 / 4) * deltaSteps;
}
trace("new BPM map BUDDY " + bpmChangeMap);
}
public static function changeBPM(newBpm:Float)
{
bpm = newBpm;
crochet = ((60 / bpm) * 1000);
stepCrochet = crochet / 4;
}
}

View File

@ -0,0 +1,92 @@
package;
import Sys.sleep;
using StringTools;
#if discord_rpc
import discord_rpc.DiscordRpc;
#end
class DiscordClient
{
#if discord_rpc
public function new()
{
trace("Discord Client starting...");
DiscordRpc.start({
clientID: "814588678700924999",
onReady: onReady,
onError: onError,
onDisconnected: onDisconnected
});
trace("Discord Client started.");
while (true)
{
DiscordRpc.process();
sleep(2);
// trace("Discord Client Update");
}
DiscordRpc.shutdown();
}
public static function shutdown()
{
DiscordRpc.shutdown();
}
static function onReady()
{
DiscordRpc.presence({
details: "In the Menus",
state: null,
largeImageKey: 'icon',
largeImageText: "Friday Night Funkin'"
});
}
static function onError(_code:Int, _message:String)
{
trace('Error! $_code : $_message');
}
static function onDisconnected(_code:Int, _message:String)
{
trace('Disconnected! $_code : $_message');
}
public static function initialize()
{
var DiscordDaemon = sys.thread.Thread.create(() ->
{
new DiscordClient();
});
trace("Discord Client initialized");
}
public static function changePresence(details:String, state:Null<String>, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
{
var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
if (endTimestamp > 0)
{
endTimestamp = startTimestamp + endTimestamp;
}
DiscordRpc.presence({
details: details,
state: state,
largeImageKey: 'icon',
largeImageText: "Friday Night Funkin'",
smallImageKey: smallImageKey,
// Obtained times are in milliseconds so they are divided so Discord can use it
startTimestamp: Std.int(startTimestamp / 1000),
endTimestamp: Std.int(endTimestamp / 1000)
});
// trace('Discord RPC Updated. Arguments: $details, $state, $smallImageKey, $hasStartTimestamp, $endTimestamp');
}
#end
}

View File

@ -0,0 +1,102 @@
package game.data.backend;
import flixel.FlxG;
class Highscore
{
#if (haxe >= "4.0.0")
public static var songScores:Map<String, Int> = new Map();
#else
public static var songScores:Map<String, Int> = new Map<String, Int>();
#end
public static function saveScore(song:String, score:Int = 0, ?diff:Int = 0):Void
{
var formattedSong:String = formatSong(song, diff);
#if newgrounds
// NGio.postScore(score, song);
#end
if (songScores.exists(formattedSong))
{
if (songScores.get(formattedSong) < score)
setScore(formattedSong, score);
}
else
setScore(formattedSong, score);
}
public static function saveWeekScore(week:Int = 1, score:Int = 0, ?diff:Int = 0):Void
{
#if newgrounds
// NGio.postScore(score, "Week " + week);
#end
var formattedSong:String = formatSong('week' + week, diff);
if (songScores.exists(formattedSong))
{
if (songScores.get(formattedSong) < score)
setScore(formattedSong, score);
}
else
setScore(formattedSong, score);
}
/**
* YOU SHOULD FORMAT SONG WITH formatSong() BEFORE TOSSING IN SONG VARIABLE
*/
static function setScore(formattedSong:String, score:Int):Void
{
/** GeoKureli
* References to Highscore were wrapped in `#if !switch` blocks. I wasn't sure if this
* is because switch doesn't use NGio, or because switch has a different saving method.
* I moved the compiler flag here, rather than using it everywhere else.
*/
#if !switch
// Reminder that I don't need to format this song, it should come formatted!
songScores.set(formattedSong, score);
FlxG.save.data.songScores = songScores;
FlxG.save.flush();
#end
}
public static function formatSong(song:String, diff:Int):String
{
var daSong:String = song;
if (diff == 0)
daSong += '-easy';
else if (diff == 2)
daSong += '-hard';
return daSong;
}
public static function getScore(song:String, diff:Int):Int
{
if (!songScores.exists(formatSong(song, diff)))
setScore(formatSong(song, diff), 0);
return songScores.get(formatSong(song, diff));
}
public static function getWeekScore(week:Int, diff:Int):Int
{
if (!songScores.exists(formatSong('week' + week, diff)))
setScore(formatSong('week' + week, diff), 0);
return songScores.get(formatSong('week' + week, diff));
}
public static function load():Void
{
if (FlxG.save.data.songScores != null)
{
songScores = FlxG.save.data.songScores;
}
}
}

View File

@ -0,0 +1,31 @@
package game.data.backend;
typedef SwagSection =
{
var sectionNotes:Array<Dynamic>;
var lengthInSteps:Int;
var typeOfSection:Int;
var mustHitSection:Bool;
var bpm:Float;
var changeBPM:Bool;
var altAnim:Bool;
}
class Section
{
public var sectionNotes:Array<Dynamic> = [];
public var lengthInSteps:Int = 16;
public var typeOfSection:Int = 0;
public var mustHitSection:Bool = true;
/**
* Copies the first section into the second section!
*/
public static var COPYCAT:Int = 0;
public function new(lengthInSteps:Int = 16)
{
this.lengthInSteps = lengthInSteps;
}
}

View File

@ -0,0 +1,76 @@
package game.data.backend;
import game.data.backend.Section.SwagSection;
import haxe.Json;
import haxe.format.JsonParser;
import lime.utils.Assets;
using StringTools;
typedef SwagSong =
{
var song:String;
var notes:Array<SwagSection>;
var bpm:Float;
var needsVoices:Bool;
var speed:Float;
var player1:String;
var player2:String;
var validScore:Bool;
}
class Song
{
public var song:String;
public var notes:Array<SwagSection>;
public var bpm:Float;
public var needsVoices:Bool = true;
public var speed:Float = 1;
public var player1:String = 'bf';
public var player2:String = 'dad';
public function new(song, notes, bpm)
{
this.song = song;
this.notes = notes;
this.bpm = bpm;
}
public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong
{
var rawJson = Assets.getText(Paths.json(folder.toLowerCase() + '/' + jsonInput.toLowerCase())).trim();
while (!rawJson.endsWith("}"))
{
rawJson = rawJson.substr(0, rawJson.length - 1);
// LOL GOING THROUGH THE BULLSHIT TO CLEAN IDK WHATS STRANGE
}
// FIX THE CASTING ON WINDOWS/NATIVE
// Windows???
// trace(songData);
// trace('LOADED FROM JSON: ' + songData.notes);
/*
for (i in 0...songData.notes.length)
{
trace('LOADED FROM JSON: ' + songData.notes[i].sectionNotes);
// songData.notes[i].sectionNotes = songData.notes[i].sectionNotes
}
daNotes = songData.notes;
daSong = songData.song;
daBpm = songData.bpm; */
return parseJSONshit(rawJson);
}
public static function parseJSONshit(rawJson:String):SwagSong
{
var swagShit:SwagSong = cast Json.parse(rawJson).song;
swagShit.validScore = true;
return swagShit;
}
}

View File

@ -0,0 +1,101 @@
package game.data.backend;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.math.FlxPoint;
class SwagCamera extends FlxCamera
{
/**
* properly follow framerate
* most of this just copied from FlxCamera,
* only lines 96 and 97 are changed
*/
override public function updateFollow():Void
{
// Either follow the object closely,
// or double check our deadzone and update accordingly.
if (deadzone == null)
{
target.getMidpoint(_point);
_point.addPoint(targetOffset);
focusOn(_point);
}
else
{
var edge:Float;
var targetX:Float = target.x + targetOffset.x;
var targetY:Float = target.y + targetOffset.y;
if (style == SCREEN_BY_SCREEN)
{
if (targetX >= (scroll.x + width))
{
_scrollTarget.x += width;
}
else if (targetX < scroll.x)
{
_scrollTarget.x -= width;
}
if (targetY >= (scroll.y + height))
{
_scrollTarget.y += height;
}
else if (targetY < scroll.y)
{
_scrollTarget.y -= height;
}
}
else
{
edge = targetX - deadzone.x;
if (_scrollTarget.x > edge)
{
_scrollTarget.x = edge;
}
edge = targetX + target.width - deadzone.x - deadzone.width;
if (_scrollTarget.x < edge)
{
_scrollTarget.x = edge;
}
edge = targetY - deadzone.y;
if (_scrollTarget.y > edge)
{
_scrollTarget.y = edge;
}
edge = targetY + target.height - deadzone.y - deadzone.height;
if (_scrollTarget.y < edge)
{
_scrollTarget.y = edge;
}
}
if ((target is FlxSprite))
{
if (_lastTargetPosition == null)
{
_lastTargetPosition = FlxPoint.get(target.x, target.y); // Creates this point.
}
_scrollTarget.x += (target.x - _lastTargetPosition.x) * followLead.x;
_scrollTarget.y += (target.y - _lastTargetPosition.y) * followLead.y;
_lastTargetPosition.x = target.x;
_lastTargetPosition.y = target.y;
}
if (followLerp >= 60 / FlxG.updateFramerate)
{
scroll.copyFrom(_scrollTarget); // no easing
}
else
{
// THIS THE PART THAT ACTUALLY MATTERS LOL
scroll.x += (_scrollTarget.x - scroll.x) * CoolUtil.camLerpShit(followLerp);
scroll.y += (_scrollTarget.y - scroll.y) * CoolUtil.camLerpShit(followLerp);
}
}
}
}

View File

@ -0,0 +1,261 @@
package game.data.debug;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.addons.display.FlxGridOverlay;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import openfl.events.Event;
import openfl.events.IOErrorEvent;
import openfl.net.FileReference;
import game.objects.*;
using StringTools;
/**
*DEBUG MODE
*/
class AnimationDebug extends FlxState
{
var bf:Boyfriend;
var dad:Character;
var char:Character;
var textAnim:FlxText;
var dumbTexts:FlxTypedGroup<FlxText>;
var animList:Array<String> = [];
var curAnim:Int = 0;
var isDad:Bool = true;
var daAnim:String = 'spooky';
var camFollow:FlxObject;
public function new(daAnim:String = 'spooky')
{
super();
this.daAnim = daAnim;
}
override function create()
{
FlxG.sound.music.stop();
var gridBG:FlxSprite = FlxGridOverlay.create(10, 10);
gridBG.scrollFactor.set(0.5, 0.5);
add(gridBG);
if (daAnim == 'bf')
isDad = false;
if (isDad)
{
dad = new Character(0, 0, daAnim);
dad.screenCenter();
dad.debugMode = true;
add(dad);
char = dad;
dad.flipX = false;
}
else
{
bf = new Boyfriend(0, 0);
bf.screenCenter();
bf.debugMode = true;
add(bf);
char = bf;
bf.flipX = false;
}
dumbTexts = new FlxTypedGroup<FlxText>();
add(dumbTexts);
textAnim = new FlxText(300, 16);
textAnim.size = 26;
textAnim.scrollFactor.set();
add(textAnim);
genBoyOffsets();
camFollow = new FlxObject(0, 0, 2, 2);
camFollow.screenCenter();
add(camFollow);
FlxG.camera.follow(camFollow);
super.create();
}
function genBoyOffsets(pushList:Bool = true):Void
{
var daLoop:Int = 0;
for (anim => offsets in char.animOffsets)
{
var text:FlxText = new FlxText(10, 20 + (18 * daLoop), 0, anim + ": " + offsets, 15);
text.scrollFactor.set();
text.color = FlxColor.BLUE;
dumbTexts.add(text);
if (pushList)
animList.push(anim);
daLoop++;
}
}
function updateTexts():Void
{
dumbTexts.forEach(function(text:FlxText)
{
text.kill();
dumbTexts.remove(text, true);
});
}
override function update(elapsed:Float)
{
textAnim.text = char.animation.curAnim.name;
if (FlxG.keys.justPressed.E)
FlxG.camera.zoom += 0.25;
if (FlxG.keys.justPressed.Q)
FlxG.camera.zoom -= 0.25;
if (FlxG.keys.pressed.I || FlxG.keys.pressed.J || FlxG.keys.pressed.K || FlxG.keys.pressed.L)
{
if (FlxG.keys.pressed.I)
camFollow.velocity.y = -90;
else if (FlxG.keys.pressed.K)
camFollow.velocity.y = 90;
else
camFollow.velocity.y = 0;
if (FlxG.keys.pressed.J)
camFollow.velocity.x = -90;
else if (FlxG.keys.pressed.L)
camFollow.velocity.x = 90;
else
camFollow.velocity.x = 0;
}
else
{
camFollow.velocity.set();
}
if (FlxG.keys.justPressed.W)
{
curAnim -= 1;
}
if (FlxG.keys.justPressed.S)
{
curAnim += 1;
}
if (curAnim < 0)
curAnim = animList.length - 1;
if (curAnim >= animList.length)
curAnim = 0;
if (FlxG.keys.justPressed.S || FlxG.keys.justPressed.W || FlxG.keys.justPressed.SPACE)
{
char.playAnim(animList[curAnim]);
updateTexts();
genBoyOffsets(false);
}
var upP = FlxG.keys.anyJustPressed([UP]);
var rightP = FlxG.keys.anyJustPressed([RIGHT]);
var downP = FlxG.keys.anyJustPressed([DOWN]);
var leftP = FlxG.keys.anyJustPressed([LEFT]);
var holdShift = FlxG.keys.pressed.SHIFT;
var multiplier = 1;
if (holdShift)
multiplier = 10;
if (upP || rightP || downP || leftP)
{
updateTexts();
if (upP)
char.animOffsets.get(animList[curAnim])[1] += 1 * multiplier;
if (downP)
char.animOffsets.get(animList[curAnim])[1] -= 1 * multiplier;
if (leftP)
char.animOffsets.get(animList[curAnim])[0] += 1 * multiplier;
if (rightP)
char.animOffsets.get(animList[curAnim])[0] -= 1 * multiplier;
updateTexts();
genBoyOffsets(false);
char.playAnim(animList[curAnim]);
}
if (FlxG.keys.justPressed.ESCAPE)
{
var outputString:String = "";
for (swagAnim in animList)
{
outputString += swagAnim + " " + char.animOffsets.get(swagAnim)[0] + " " + char.animOffsets.get(swagAnim)[1] + "\n";
}
outputString.trim();
saveOffsets(outputString);
}
super.update(elapsed);
}
var _file:FileReference;
private function saveOffsets(saveString:String)
{
if ((saveString != null) && (saveString.length > 0))
{
_file = new FileReference();
_file.addEventListener(Event.COMPLETE, onSaveComplete);
_file.addEventListener(Event.CANCEL, onSaveCancel);
_file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file.save(saveString, daAnim + "Offsets.txt");
}
}
function onSaveComplete(_):Void
{
_file.removeEventListener(Event.COMPLETE, onSaveComplete);
_file.removeEventListener(Event.CANCEL, onSaveCancel);
_file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file = null;
FlxG.log.notice("Successfully saved LEVEL DATA.");
}
/**
* Called when the save file dialog is cancelled.
*/
function onSaveCancel(_):Void
{
_file.removeEventListener(Event.COMPLETE, onSaveComplete);
_file.removeEventListener(Event.CANCEL, onSaveCancel);
_file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file = null;
}
/**
* Called if there is an error while saving the gameplay recording.
*/
function onSaveError(_):Void
{
_file.removeEventListener(Event.COMPLETE, onSaveComplete);
_file.removeEventListener(Event.CANCEL, onSaveCancel);
_file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file = null;
FlxG.log.error("Problem saving Level data");
}
}

View File

@ -0,0 +1,35 @@
package;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
import openfl.Assets;
import sys.io.File;
class DebugBoundingState extends FlxState
{
override function create()
{
var bf:FlxSprite = new FlxSprite().loadGraphic(Paths.image('characters/temp'));
add(bf);
FlxG.stage.window.onDropFile.add(function(path:String)
{
trace("DROPPED FILE FROM: " + Std.string(path));
var newPath = "./" + Paths.image('characters/temp');
File.copy(path, newPath);
var swag = Paths.image('characters/temp');
if (bf != null)
remove(bf);
FlxG.bitmap.removeByKey(Paths.image('characters/temp'));
Assets.cache.clear();
bf.loadGraphic(Paths.image('characters/temp'));
add(bf);
});
super.create();
}
}

View File

@ -0,0 +1,221 @@
package game.data.format;
import game.state.menus.options.controls.Controls;
import game.state.menus.options.controls.Controls.Device;
import flixel.FlxG;
import flixel.input.gamepad.FlxGamepad;
import flixel.input.gamepad.FlxGamepadInputID;
import flixel.input.keyboard.FlxKey;
using flixel.util.FlxStringUtil;
class InputFormatter
{
static public function format(id:Int, device:Device):String
{
return switch (device)
{
case Keys: getKeyName(id);
case Gamepad(gamepadID): getButtonName(id, FlxG.gamepads.getByID(gamepadID));
}
}
static public function getKeyName(id:Int):String
{
return switch(id)
{
case ZERO : "0";
case ONE : "1";
case TWO : "2";
case THREE : "3";
case FOUR : "4";
case FIVE : "5";
case SIX : "6";
case SEVEN : "7";
case EIGHT : "8";
case NINE : "9";
case PAGEUP : "PgUp";
case PAGEDOWN : "PgDown";
// case HOME : "Hm";
// case END : "End";
// case INSERT : "Ins";
// case ESCAPE : "Esc";
// case MINUS : "-";
// case PLUS : "+";
// case DELETE : "Del";
case BACKSPACE : "BckSpc";
case LBRACKET : "[";
case RBRACKET : "]";
case BACKSLASH : "\\";
case CAPSLOCK : "Caps";
case SEMICOLON : ";";
case QUOTE : "'";
// case ENTER : "Ent";
// case SHIFT : "Shf";
case COMMA : ",";
case PERIOD : ".";
case SLASH : "/";
case GRAVEACCENT : "`";
case CONTROL : "Ctrl";
case ALT : "Alt";
// case SPACE : "Spc";
// case UP : "Up";
// case DOWN : "Dn";
// case LEFT : "Lf";
// case RIGHT : "Rt";
// case TAB : "Tab";
case PRINTSCREEN : "PrtScrn";
case NUMPADZERO : "#0";
case NUMPADONE : "#1";
case NUMPADTWO : "#2";
case NUMPADTHREE : "#3";
case NUMPADFOUR : "#4";
case NUMPADFIVE : "#5";
case NUMPADSIX : "#6";
case NUMPADSEVEN : "#7";
case NUMPADEIGHT : "#8";
case NUMPADNINE : "#9";
case NUMPADMINUS : "#-";
case NUMPADPLUS : "#+";
case NUMPADPERIOD : "#.";
case NUMPADMULTIPLY: "#*";
default: titleCase(FlxKey.toStringMap[id]);
}
}
static var dirReg = ~/^(l|r).?-(left|right|down|up)$/;
inline static public function getButtonName(id:Int, gamepad:FlxGamepad):String
{
return switch(gamepad.getInputLabel(id))
{
// case null | "": shortenButtonName(FlxGamepadInputID.toStringMap[id]);
case label: shortenButtonName(label);
}
}
static function shortenButtonName(name:String)
{
return switch (name == null ? "" : name.toLowerCase())
{
case "": "[?]";
// case "square" : "[]";
// case "circle" : "()";
// case "triangle": "/\\";
// case "plus" : "+";
// case "minus" : "-";
// case "home" : "Hm";
// case "guide" : "Gd";
// case "back" : "Bk";
// case "select" : "Bk";
// case "start" : "St";
// case "left" : "Lf";
// case "right" : "Rt";
// case "down" : "Dn";
// case "up" : "Up";
case dir if (dirReg.match(dir)):
dirReg.matched(1).toUpperCase() + " " + titleCase(dirReg.matched(2));
case label: titleCase(label);
}
}
inline static function titleCaseTrim(str:String, length = 8)
{
return str.charAt(0).toUpperCase() + str.substr(1, length - 1).toLowerCase();
}
inline static function titleCase(str:String)
{
return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
}
inline static public function parsePadName(name:String):ControllerName
{
return ControllerName.parseName(name);
}
inline static public function getPadName(gamepad:FlxGamepad):ControllerName
{
return ControllerName.getName(gamepad);
}
inline static public function getPadNameById(id:Int):ControllerName
{
return ControllerName.getNameById(id);
}
}
@:forward
@:enum abstract ControllerName(String) from String to String
{
var OUYA = "Ouya" ;
var PS4 = "PS4" ;
var LOGI = "Logi" ;
var XBOX = "XBox" ;
var XINPUT = "XInput" ;
var WII = "Wii" ;
var PRO_CON = "Pro_Con" ;
var JOYCONS = "Joycons" ;
var JOYCON_L = "Joycon_L";
var JOYCON_R = "Joycon_R";
var MFI = "MFI" ;
var PAD = "Pad" ;
static public function getAssetByDevice(device:Device):String
{
return switch (device)
{
case Keys: getAsset(null);
case Gamepad(id): getAsset(FlxG.gamepads.getByID(id));
}
}
static public function getAsset(gamepad:FlxGamepad):String
{
if (gamepad == null)
return 'assets/images/ui/devices/Keys.png';
final name = parseName(gamepad.name);
var path = 'assets/images/ui/devices/$name.png';
if (openfl.utils.Assets.exists(path))
return path;
return 'assets/images/ui/devices/Pad.png';
}
inline static public function getNameById(id:Int):ControllerName return getName(FlxG.gamepads.getByID(id));
inline static public function getName(gamepad:FlxGamepad):ControllerName return parseName(gamepad.name);
static public function parseName(name:String):ControllerName
{
name = name.toLowerCase().remove("-").remove("_");
return
if (name.contains("ouya"))
OUYA;
else if (name.contains("wireless controller") || name.contains("ps4"))
PS4;
else if (name.contains("logitech"))
LOGI;
else if (name.contains("xbox"))
XBOX
else if (name.contains("xinput"))
XINPUT;
else if (name.contains("nintendo rvlcnt01tr") || name.contains("nintendo rvlcnt01"))
WII;
else if (name.contains("mayflash wiimote pc adapter"))
WII;
else if (name.contains("pro controller"))
PRO_CON;
else if (name.contains("joycon l+r"))
JOYCONS;
else if (name.contains("joycon (l)"))
JOYCON_L;
else if (name.contains("joycon (r)"))
JOYCON_R;
else if (name.contains("mfi"))
MFI;
else
PAD;
}
}

View File

@ -0,0 +1,45 @@
package game.objects;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.util.FlxTimer;
using StringTools;
class Boyfriend extends Character
{
// public var stunned:Bool = false;
public function new(x:Float, y:Float, ?char:String = 'bf')
{
super(x, y, char, true);
}
public var startedDeath:Bool = false;
override function update(elapsed:Float)
{
if (!debugMode)
{
if (animation.curAnim.name.startsWith('sing'))
{
holdTimer += elapsed;
}
else
holdTimer = 0;
if (animation.curAnim.name.endsWith('miss') && animation.curAnim.finished && !debugMode)
{
playAnim('idle', true, false, 10);
}
if (animation.curAnim.name == 'firstDeath' && animation.curAnim.finished && startedDeath)
{
playAnim('deathLoop');
}
}
super.update(elapsed);
}
}

View File

@ -0,0 +1,701 @@
package game.objects;
import game.data.backend.Section.SwagSection;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.animation.FlxBaseAnimation;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.util.FlxSort;
import haxe.io.Path;
import game.state.*;
import game.data.backend.*;
import game.objects.stages.background.*;
using StringTools;
class Character extends FlxSprite
{
public var animOffsets:Map<String, Array<Dynamic>>;
public var debugMode:Bool = false;
public var isPlayer:Bool = false;
public var curCharacter:String = 'bf';
public var holdTimer:Float = 0;
public var animationNotes:Array<Dynamic> = [];
public function new(x:Float, y:Float, ?character:String = "bf", ?isPlayer:Bool = false)
{
super(x, y);
animOffsets = new Map<String, Array<Dynamic>>();
curCharacter = character;
this.isPlayer = isPlayer;
var tex:FlxAtlasFrames;
antialiasing = true;
switch (curCharacter)
{
case 'gf':
// GIRLFRIEND CODE
tex = Paths.getSparrowAtlas('characters/GF_assets');
frames = tex;
quickAnimAdd('cheer', 'GF Cheer');
quickAnimAdd('singLEFT', 'GF left note');
quickAnimAdd('singRIGHT', 'GF Right Note');
quickAnimAdd('singUP', 'GF Up Note');
quickAnimAdd('singDOWN', 'GF Down Note');
animation.addByIndices('sad', 'gf sad', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], "", 24, true);
animation.addByIndices('danceLeft', 'GF Dancing Beat', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
animation.addByIndices('danceRight', 'GF Dancing Beat', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
animation.addByIndices('hairBlow', "GF Dancing Beat Hair blowing", [0, 1, 2, 3], "", 24);
animation.addByIndices('hairFall', "GF Dancing Beat Hair Landing", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], "", 24, false);
animation.addByPrefix('scared', 'GF FEAR', 24, true);
loadOffsetFile(curCharacter);
playAnim('danceRight');
case 'gf-christmas':
tex = Paths.getSparrowAtlas('characters/gfChristmas');
frames = tex;
quickAnimAdd('cheer', 'GF Cheer');
quickAnimAdd('singLEFT', 'GF left note');
quickAnimAdd('singRIGHT', 'GF Right Note');
quickAnimAdd('singUP', 'GF Up Note');
quickAnimAdd('singDOWN', 'GF Down Note');
animation.addByIndices('sad', 'gf sad', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], "", 24, false);
animation.addByIndices('danceLeft', 'GF Dancing Beat', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
animation.addByIndices('danceRight', 'GF Dancing Beat', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
animation.addByIndices('hairBlow', "GF Dancing Beat Hair blowing", [0, 1, 2, 3], "", 24);
animation.addByIndices('hairFall', "GF Dancing Beat Hair Landing", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], "", 24, false);
animation.addByPrefix('scared', 'GF FEAR', 24, true);
loadOffsetFile(curCharacter);
playAnim('danceRight');
case 'gf-tankmen':
frames = Paths.getSparrowAtlas('characters/gfTankmen');
animation.addByIndices('sad', 'GF Crying at Gunpoint', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], "", 24, true);
animation.addByIndices('danceLeft', 'GF Dancing at Gunpoint', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
animation.addByIndices('danceRight', 'GF Dancing at Gunpoint', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
loadOffsetFile('gf');
playAnim('danceRight');
case 'bf-holding-gf':
frames = Paths.getSparrowAtlas('characters/bfAndGF');
quickAnimAdd('idle', 'BF idle dance');
quickAnimAdd('singDOWN', 'BF NOTE DOWN0');
quickAnimAdd('singLEFT', 'BF NOTE LEFT0');
quickAnimAdd('singRIGHT', 'BF NOTE RIGHT0');
quickAnimAdd('singUP', 'BF NOTE UP0');
quickAnimAdd('singDOWNmiss', 'BF NOTE DOWN MISS');
quickAnimAdd('singLEFTmiss', 'BF NOTE LEFT MISS');
quickAnimAdd('singRIGHTmiss', 'BF NOTE RIGHT MISS');
quickAnimAdd('singUPmiss', 'BF NOTE UP MISS');
quickAnimAdd('bfCatch', 'BF catches GF');
loadOffsetFile(curCharacter);
playAnim('idle');
flipX = true;
case 'gf-car':
tex = Paths.getSparrowAtlas('characters/gfCar');
frames = tex;
animation.addByIndices('singUP', 'GF Dancing Beat Hair blowing CAR', [0], "", 24, false);
animation.addByIndices('danceLeft', 'GF Dancing Beat Hair blowing CAR', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
animation.addByIndices('danceRight', 'GF Dancing Beat Hair blowing CAR', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24,
false);
animation.addByIndices('idleHair', 'GF Dancing Beat Hair blowing CAR', [10, 11, 12, 25, 26, 27], "", 24, true);
loadOffsetFile(curCharacter);
playAnim('danceRight');
case 'gf-pixel':
tex = Paths.getSparrowAtlas('characters/gfPixel');
frames = tex;
animation.addByIndices('singUP', 'GF IDLE', [2], "", 24, false);
animation.addByIndices('danceLeft', 'GF IDLE', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
animation.addByIndices('danceRight', 'GF IDLE', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
loadOffsetFile(curCharacter);
playAnim('danceRight');
setGraphicSize(Std.int(width * PlayState.daPixelZoom));
updateHitbox();
antialiasing = false;
case 'dad':
// DAD ANIMATION LOADING CODE
tex = Paths.getSparrowAtlas('characters/DADDY_DEAREST');
frames = tex;
quickAnimAdd('idle', 'Dad idle dance');
quickAnimAdd('singUP', 'Dad Sing Note UP');
quickAnimAdd('singRIGHT', 'Dad Sing Note RIGHT');
quickAnimAdd('singDOWN', 'Dad Sing Note DOWN');
quickAnimAdd('singLEFT', 'Dad Sing Note LEFT');
loadOffsetFile(curCharacter);
playAnim('idle');
case 'spooky':
tex = Paths.getSparrowAtlas('characters/spooky_kids_assets');
frames = tex;
quickAnimAdd('singUP', 'spooky UP NOTE');
quickAnimAdd('singDOWN', 'spooky DOWN note');
quickAnimAdd('singLEFT', 'note sing left');
quickAnimAdd('singRIGHT', 'spooky sing right');
animation.addByIndices('danceLeft', 'spooky dance idle', [0, 2, 6], "", 12, false);
animation.addByIndices('danceRight', 'spooky dance idle', [8, 10, 12, 14], "", 12, false);
loadOffsetFile(curCharacter);
playAnim('danceRight');
case 'mom':
tex = Paths.getSparrowAtlas('characters/Mom_Assets');
frames = tex;
quickAnimAdd('idle', "Mom Idle");
quickAnimAdd('singUP', "Mom Up Pose");
quickAnimAdd('singDOWN', "MOM DOWN POSE");
quickAnimAdd('singLEFT', 'Mom Left Pose');
// ANIMATION IS CALLED MOM LEFT POSE BUT ITS FOR THE RIGHT
// CUZ DAVE IS DUMB!
quickAnimAdd('singRIGHT', 'Mom Pose Left');
loadOffsetFile(curCharacter);
playAnim('idle');
case 'mom-car':
tex = Paths.getSparrowAtlas('characters/momCar');
frames = tex;
quickAnimAdd('idle', "Mom Idle");
quickAnimAdd('singUP', "Mom Up Pose");
quickAnimAdd('singDOWN', "MOM DOWN POSE");
quickAnimAdd('singLEFT', 'Mom Left Pose');
// ANIMATION IS CALLED MOM LEFT POSE BUT ITS FOR THE RIGHT
// CUZ DAVE IS DUMB!
quickAnimAdd('singRIGHT', 'Mom Pose Left');
animation.addByIndices('idleHair', "Mom Idle", [10, 11, 12, 13], "", 24, true);
loadOffsetFile(curCharacter);
playAnim('idle');
case 'monster':
tex = Paths.getSparrowAtlas('characters/Monster_Assets');
frames = tex;
quickAnimAdd('idle', 'monster idle');
quickAnimAdd('singUP', 'monster up note');
quickAnimAdd('singDOWN', 'monster down');
quickAnimAdd('singLEFT', 'Monster left note');
quickAnimAdd('singRIGHT', 'Monster Right note');
loadOffsetFile(curCharacter);
playAnim('idle');
case 'monster-christmas':
tex = Paths.getSparrowAtlas('characters/monsterChristmas');
frames = tex;
quickAnimAdd('idle', 'monster idle');
quickAnimAdd('singUP', 'monster up note');
quickAnimAdd('singDOWN', 'monster down');
quickAnimAdd('singLEFT', 'Monster left note');
quickAnimAdd('singRIGHT', 'Monster Right note');
loadOffsetFile(curCharacter);
playAnim('idle');
case 'pico':
tex = Paths.getSparrowAtlas('characters/Pico_FNF_assetss');
frames = tex;
quickAnimAdd('idle', "Pico Idle Dance");
quickAnimAdd('singUP', 'pico Up note0');
quickAnimAdd('singDOWN', 'Pico Down Note0');
if (isPlayer)
{
quickAnimAdd('singLEFT', 'Pico NOTE LEFT0');
quickAnimAdd('singRIGHT', 'Pico Note Right0');
quickAnimAdd('singRIGHTmiss', 'Pico Note Right Miss');
quickAnimAdd('singLEFTmiss', 'Pico NOTE LEFT miss');
}
else
{
// Need to be flipped! REDO THIS LATER!
quickAnimAdd('singLEFT', 'Pico Note Right0');
quickAnimAdd('singRIGHT', 'Pico NOTE LEFT0');
quickAnimAdd('singRIGHTmiss', 'Pico NOTE LEFT miss');
quickAnimAdd('singLEFTmiss', 'Pico Note Right Miss');
}
quickAnimAdd('singUPmiss', 'pico Up note miss');
quickAnimAdd('singDOWNmiss', 'Pico Down Note MISS');
loadOffsetFile(curCharacter);
playAnim('idle');
flipX = true;
case 'pico-speaker':
frames = Paths.getSparrowAtlas('characters/picoSpeaker');
quickAnimAdd('shoot1', "Pico shoot 1");
quickAnimAdd('shoot2', "Pico shoot 2");
quickAnimAdd('shoot3', "Pico shoot 3");
quickAnimAdd('shoot4', "Pico shoot 4");
// here for now, will be replaced later for less copypaste
loadOffsetFile(curCharacter);
playAnim('shoot1');
loadMappedAnims();
case 'bf':
var tex = Paths.getSparrowAtlas('characters/BOYFRIEND');
frames = tex;
quickAnimAdd('idle', 'BF idle dance');
quickAnimAdd('singUP', 'BF NOTE UP0');
quickAnimAdd('singLEFT', 'BF NOTE LEFT0');
quickAnimAdd('singRIGHT', 'BF NOTE RIGHT0');
quickAnimAdd('singDOWN', 'BF NOTE DOWN0');
quickAnimAdd('singUPmiss', 'BF NOTE UP MISS');
quickAnimAdd('singLEFTmiss', 'BF NOTE LEFT MISS');
quickAnimAdd('singRIGHTmiss', 'BF NOTE RIGHT MISS');
quickAnimAdd('singDOWNmiss', 'BF NOTE DOWN MISS');
quickAnimAdd('hey', 'BF HEY');
quickAnimAdd('firstDeath', "BF dies");
animation.addByPrefix('deathLoop', "BF Dead Loop", 24, true);
quickAnimAdd('deathConfirm', "BF Dead confirm");
animation.addByPrefix('scared', 'BF idle shaking', 24, true);
loadOffsetFile(curCharacter);
playAnim('idle');
flipX = true;
loadOffsetFile(curCharacter);
case 'bf-christmas':
var tex = Paths.getSparrowAtlas('characters/bfChristmas');
frames = tex;
quickAnimAdd('idle', 'BF idle dance');
quickAnimAdd('singUP', 'BF NOTE UP0');
quickAnimAdd('singLEFT', 'BF NOTE LEFT0');
quickAnimAdd('singRIGHT', 'BF NOTE RIGHT0');
quickAnimAdd('singDOWN', 'BF NOTE DOWN0');
quickAnimAdd('singUPmiss', 'BF NOTE UP MISS');
quickAnimAdd('singLEFTmiss', 'BF NOTE LEFT MISS');
quickAnimAdd('singRIGHTmiss', 'BF NOTE RIGHT MISS');
quickAnimAdd('singDOWNmiss', 'BF NOTE DOWN MISS');
quickAnimAdd('hey', 'BF HEY');
loadOffsetFile(curCharacter);
playAnim('idle');
flipX = true;
case 'bf-car':
var tex = Paths.getSparrowAtlas('characters/bfCar');
frames = tex;
quickAnimAdd('idle', 'BF idle dance');
quickAnimAdd('singUP', 'BF NOTE UP0');
quickAnimAdd('singLEFT', 'BF NOTE LEFT0');
quickAnimAdd('singRIGHT', 'BF NOTE RIGHT0');
quickAnimAdd('singDOWN', 'BF NOTE DOWN0');
quickAnimAdd('singUPmiss', 'BF NOTE UP MISS');
quickAnimAdd('singLEFTmiss', 'BF NOTE LEFT MISS');
quickAnimAdd('singRIGHTmiss', 'BF NOTE RIGHT MISS');
quickAnimAdd('singDOWNmiss', 'BF NOTE DOWN MISS');
animation.addByIndices('idleHair', 'BF idle dance', [10, 11, 12, 13], "", 24, true);
loadOffsetFile(curCharacter);
playAnim('idle');
flipX = true;
case 'bf-pixel':
frames = Paths.getSparrowAtlas('characters/bfPixel');
quickAnimAdd('idle', 'BF IDLE');
quickAnimAdd('singUP', 'BF UP NOTE');
quickAnimAdd('singLEFT', 'BF LEFT NOTE');
quickAnimAdd('singRIGHT', 'BF RIGHT NOTE');
quickAnimAdd('singDOWN', 'BF DOWN NOTE');
quickAnimAdd('singUPmiss', 'BF UP MISS');
quickAnimAdd('singLEFTmiss', 'BF LEFT MISS');
quickAnimAdd('singRIGHTmiss', 'BF RIGHT MISS');
quickAnimAdd('singDOWNmiss', 'BF DOWN MISS');
loadOffsetFile(curCharacter);
setGraphicSize(Std.int(width * 6));
updateHitbox();
playAnim('idle');
width -= 100;
height -= 100;
antialiasing = false;
flipX = true;
case 'bf-pixel-dead':
frames = Paths.getSparrowAtlas('characters/bfPixelsDEAD');
quickAnimAdd('singUP', "BF Dies pixel");
quickAnimAdd('firstDeath', "BF Dies pixel");
animation.addByPrefix('deathLoop', "Retry Loop", 24, true);
quickAnimAdd('deathConfirm', "RETRY CONFIRM");
animation.play('firstDeath');
loadOffsetFile(curCharacter);
playAnim('firstDeath');
// pixel bullshit
setGraphicSize(Std.int(width * 6));
updateHitbox();
antialiasing = false;
flipX = true;
case 'bf-holding-gf-dead':
frames = Paths.getSparrowAtlas('characters/bfHoldingGF-DEAD');
quickAnimAdd('singUP', 'BF Dead with GF Loop');
quickAnimAdd('firstDeath', 'BF Dies with GF');
animation.addByPrefix('deathLoop', 'BF Dead with GF Loop', 24, true);
quickAnimAdd('deathConfirm', 'RETRY confirm holding gf');
loadOffsetFile(curCharacter);
playAnim('firstDeath');
flipX = true;
case 'senpai':
frames = Paths.getSparrowAtlas('characters/senpai');
quickAnimAdd('idle', 'Senpai Idle');
// at framerate 16.8 animation plays over 2 beats at 144bpm,
// but if the game lags or the bpm is > 144 (mods etc.)
// he may miss his next dance
// animation.getByName('idle').frameRate = 16.8;
quickAnimAdd('singUP', 'SENPAI UP NOTE');
quickAnimAdd('singLEFT', 'SENPAI LEFT NOTE');
quickAnimAdd('singRIGHT', 'SENPAI RIGHT NOTE');
quickAnimAdd('singDOWN', 'SENPAI DOWN NOTE');
loadOffsetFile(curCharacter);
playAnim('idle');
setGraphicSize(Std.int(width * 6));
updateHitbox();
antialiasing = false;
case 'senpai-angry':
frames = Paths.getSparrowAtlas('characters/senpai');
quickAnimAdd('idle', 'Angry Senpai Idle');
quickAnimAdd('singUP', 'Angry Senpai UP NOTE');
quickAnimAdd('singLEFT', 'Angry Senpai LEFT NOTE');
quickAnimAdd('singRIGHT', 'Angry Senpai RIGHT NOTE');
quickAnimAdd('singDOWN', 'Angry Senpai DOWN NOTE');
loadOffsetFile(curCharacter);
playAnim('idle');
setGraphicSize(Std.int(width * 6));
updateHitbox();
antialiasing = false;
case 'spirit':
frames = Paths.getPackerAtlas('characters/spirit');
quickAnimAdd('idle', "idle spirit_");
quickAnimAdd('singUP', "up_");
quickAnimAdd('singRIGHT', "right_");
quickAnimAdd('singLEFT', "left_");
quickAnimAdd('singDOWN', "spirit down_");
loadOffsetFile(curCharacter);
setGraphicSize(Std.int(width * 6));
updateHitbox();
playAnim('idle');
antialiasing = false;
case 'parents-christmas':
frames = Paths.getSparrowAtlas('characters/mom_dad_christmas_assets');
quickAnimAdd('idle', 'Parent Christmas Idle');
quickAnimAdd('singUP', 'Parent Up Note Dad');
quickAnimAdd('singDOWN', 'Parent Down Note Dad');
quickAnimAdd('singLEFT', 'Parent Left Note Dad');
quickAnimAdd('singRIGHT', 'Parent Right Note Dad');
quickAnimAdd('singUP-alt', 'Parent Up Note Mom');
quickAnimAdd('singDOWN-alt', 'Parent Down Note Mom');
quickAnimAdd('singLEFT-alt', 'Parent Left Note Mom');
quickAnimAdd('singRIGHT-alt', 'Parent Right Note Mom');
loadOffsetFile(curCharacter);
playAnim('idle');
case 'tankman':
frames = Paths.getSparrowAtlas('characters/tankmanCaptain');
quickAnimAdd('idle', "Tankman Idle Dance");
if (isPlayer)
{
quickAnimAdd('singLEFT', 'Tankman Note Left ');
quickAnimAdd('singRIGHT', 'Tankman Right Note ');
quickAnimAdd('singLEFTmiss', 'Tankman Note Left MISS');
quickAnimAdd('singRIGHTmiss', 'Tankman Right Note MISS');
}
else
{
// Need to be flipped! REDO THIS LATER
quickAnimAdd('singLEFT', 'Tankman Right Note ');
quickAnimAdd('singRIGHT', 'Tankman Note Left ');
quickAnimAdd('singLEFTmiss', 'Tankman Right Note MISS');
quickAnimAdd('singRIGHTmiss', 'Tankman Note Left MISS');
}
quickAnimAdd('singUP', 'Tankman UP note ');
quickAnimAdd('singDOWN', 'Tankman DOWN note ');
quickAnimAdd('singUPmiss', 'Tankman UP note MISS');
quickAnimAdd('singDOWNmiss', 'Tankman DOWN note MISS');
// PRETTY GOOD tankman
// TANKMAN UGH instanc
quickAnimAdd('singDOWN-alt', 'PRETTY GOOD');
quickAnimAdd('singUP-alt', 'TANKMAN UGH');
loadOffsetFile(curCharacter);
playAnim('idle');
flipX = true;
}
dance();
animation.finish();
if (isPlayer)
{
flipX = !flipX;
// Doesn't flip for BF, since his are already in the right place???
if (!curCharacter.startsWith('bf'))
{
// var animArray
var oldRight = animation.getByName('singRIGHT').frames;
animation.getByName('singRIGHT').frames = animation.getByName('singLEFT').frames;
animation.getByName('singLEFT').frames = oldRight;
// IF THEY HAVE MISS ANIMATIONS??
if (animation.getByName('singRIGHTmiss') != null)
{
var oldMiss = animation.getByName('singRIGHTmiss').frames;
animation.getByName('singRIGHTmiss').frames = animation.getByName('singLEFTmiss').frames;
animation.getByName('singLEFTmiss').frames = oldMiss;
}
}
}
}
public function loadMappedAnims()
{
var swagshit = Song.loadFromJson('picospeaker', 'stress');
var notes = swagshit.notes;
for (section in notes)
{
for (idk in section.sectionNotes)
{
animationNotes.push(idk);
}
}
TankmenBG.animationNotes = animationNotes;
trace(animationNotes);
animationNotes.sort(sortAnims);
}
function sortAnims(val1:Array<Dynamic>, val2:Array<Dynamic>):Int
{
return FlxSort.byValues(FlxSort.ASCENDING, val1[0], val2[0]);
}
function quickAnimAdd(name:String, prefix:String)
{
animation.addByPrefix(name, prefix, 24, false);
}
private function loadOffsetFile(offsetCharacter:String)
{
var daFile:Array<String> = CoolUtil.coolTextFile(Paths.file("images/characters/" + offsetCharacter + "Offsets.txt"));
for (i in daFile)
{
var splitWords:Array<String> = i.split(" ");
addOffset(splitWords[0], Std.parseInt(splitWords[1]), Std.parseInt(splitWords[2]));
}
}
override function update(elapsed:Float)
{
if (!curCharacter.startsWith('bf'))
{
if (animation.curAnim.name.startsWith('sing'))
{
holdTimer += elapsed;
}
var dadVar:Float = 4;
if (curCharacter == 'dad')
dadVar = 6.1;
if (holdTimer >= Conductor.stepCrochet * dadVar * 0.001)
{
dance();
holdTimer = 0;
}
}
if (curCharacter.endsWith('-car'))
{
// looping hair anims after idle finished
if (!animation.curAnim.name.startsWith('sing') && animation.curAnim.finished)
playAnim('idleHair');
}
switch (curCharacter)
{
case 'gf':
if (animation.curAnim.name == 'hairFall' && animation.curAnim.finished)
playAnim('danceRight');
case "pico-speaker":
// for pico??
if (animationNotes.length > 0)
{
if (Conductor.songPosition > animationNotes[0][0])
{
trace('played shoot anim' + animationNotes[0][1]);
var shootAnim:Int = 1;
if (animationNotes[0][1] >= 2)
shootAnim = 3;
shootAnim += FlxG.random.int(0, 1);
playAnim('shoot' + shootAnim, true);
animationNotes.shift();
}
}
if (animation.curAnim.finished)
{
playAnim(animation.curAnim.name, false, false, animation.curAnim.numFrames - 3);
}
}
super.update(elapsed);
}
private var danced:Bool = false;
/**
* FOR GF DANCING SHIT
*/
public function dance()
{
if (!debugMode)
{
switch (curCharacter)
{
case 'gf' | 'gf-christmas' | 'gf-car' | 'gf-pixel' | 'gf-tankmen':
if (!animation.curAnim.name.startsWith('hair'))
{
danced = !danced;
if (danced)
playAnim('danceRight');
else
playAnim('danceLeft');
}
case 'pico-speaker':
// lol weed
// playAnim('shoot' + FlxG.random.int(1, 4), true);
case 'tankman':
if (!animation.curAnim.name.endsWith('DOWN-alt'))
playAnim('idle');
case 'spooky':
danced = !danced;
if (danced)
playAnim('danceRight');
else
playAnim('danceLeft');
default:
playAnim('idle');
}
}
}
public function playAnim(AnimName:String, Force:Bool = false, Reversed:Bool = false, Frame:Int = 0):Void
{
animation.play(AnimName, Force, Reversed, Frame);
var daOffset = animOffsets.get(AnimName);
if (animOffsets.exists(AnimName))
{
offset.set(daOffset[0], daOffset[1]);
}
else
offset.set(0, 0);
if (curCharacter == 'gf')
{
if (AnimName == 'singLEFT')
{
danced = true;
}
else if (AnimName == 'singRIGHT')
{
danced = false;
}
if (AnimName == 'singUP' || AnimName == 'singDOWN')
{
danced = !danced;
}
}
}
public function addOffset(name:String, x:Float = 0, y:Float = 0)
{
animOffsets[name] = [x, y];
}
}

View File

@ -0,0 +1,96 @@
package game.objects;
import flixel.FlxG;
import flixel.FlxSprite;
import game.state.PlayState;
/*
Pulled a Forever Engine and moved the ratings, combo numbers n stuff into
a separate class
- Zyflx
*/
class JudgeSpr
{
public static function spawnJudgeSpr(rating:String, isPixel:Bool = false)
{
var ratingSpr:FlxSprite = new FlxSprite().loadGraphic(Paths.image(rating));
ratingSpr.x = FlxG.width * 0.55 - 40;
if (ratingSpr.x < FlxG.camera.scroll.x)
ratingSpr.x = FlxG.camera.scroll.x;
else if (ratingSpr.x > FlxG.camera.scroll.x + FlxG.camera.width - ratingSpr.width)
ratingSpr.x = FlxG.camera.scroll.x + FlxG.camera.width - ratingSpr.width;
ratingSpr.y = FlxG.camera.scroll.y + FlxG.camera.height * 0.4 - 60;
ratingSpr.acceleration.y = 550;
ratingSpr.velocity.y -= FlxG.random.int(140, 175);
ratingSpr.velocity.x -= FlxG.random.int(0, 10);
if (isPixel)
{
ratingSpr.setGraphicSize(Std.int(ratingSpr.width * PlayState.daPixelZoom * 0.7));
}
else
{
ratingSpr.setGraphicSize(Std.int(ratingSpr.width * 0.7));
ratingSpr.antialiasing = true;
}
ratingSpr.updateHitbox();
return ratingSpr;
}
public static function spawnComboNum(path:String, isPixel:Bool = false)
{
var comboNum:FlxSprite = new FlxSprite().loadGraphic(Paths.image(path));
if (isPixel)
{
comboNum.setGraphicSize(Std.int(comboNum.width * PlayState.daPixelZoom));
}
else
{
comboNum.setGraphicSize(Std.int(comboNum.width * 0.5));
}
comboNum.updateHitbox();
comboNum.acceleration.y = FlxG.random.int(200, 300);
comboNum.velocity.y -= FlxG.random.int(140, 160);
comboNum.velocity.x = FlxG.random.float(-5, 5);
return comboNum;
}
public static function spawnComboSpr(path:String, isPixel:Bool = false)
{
var comboSpr:FlxSprite = new FlxSprite();
comboSpr.loadGraphic(Paths.image(path));
comboSpr.y = FlxG.camera.scroll.y + FlxG.camera.height * 0.4 + 80;
comboSpr.x = FlxG.width * 0.55;
if (comboSpr.x < FlxG.camera.scroll.x + 194)
comboSpr.x = FlxG.camera.scroll.x + 194;
else if (comboSpr.x > FlxG.camera.scroll.x + FlxG.camera.width - comboSpr.width)
comboSpr.x = FlxG.camera.scroll.x + FlxG.camera.width - comboSpr.width;
comboSpr.acceleration.y = 600;
comboSpr.velocity.y -= 150;
comboSpr.velocity.x += FlxG.random.int(1, 10);
if (isPixel)
{
comboSpr.setGraphicSize(Std.int(comboSpr.width * PlayState.daPixelZoom * 0.7));
}
else
{
comboSpr.setGraphicSize(Std.int(comboSpr.width * 0.7));
comboSpr.antialiasing = true;
}
comboSpr.updateHitbox();
return comboSpr;
}
}

View File

@ -0,0 +1,81 @@
package game.objects.cutscene;
import animate.FlxAnimate;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.addons.display.FlxGridOverlay;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.math.FlxPoint;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import openfl.display.BitmapData;
// import animateAtlasPlayer.assets.AssetManager;
// import animateAtlasPlayer.core.Animation;
class CutsceneAnimTestState extends FlxState
{
var cutsceneGroup:CutsceneCharacter;
var curSelected:Int = 0;
var debugTxt:FlxText;
public function new()
{
super();
var gridBG:FlxSprite = FlxGridOverlay.create(10, 10);
gridBG.scrollFactor.set(0.5, 0.5);
add(gridBG);
debugTxt = new FlxText(900, 20, 0, "", 20);
debugTxt.color = FlxColor.BLUE;
add(debugTxt);
var animated:FlxAnimate = new FlxAnimate(600, 200);
add(animated);
// createCutscene(0);
// createCutscene(1);
// createCutscene(2);
// createCutscene(3);
// createCutscene(4);
}
override function update(elapsed:Float)
{
/* if (FlxG.keys.pressed.SHIFT)
{
if (FlxG.keys.justPressed.UP)
curSelected -= 1;
if (FlxG.keys.justPressed.DOWN)
curSelected += 1;
if (curSelected < 0)
curSelected = cutsceneGroup.members.length - 1;
if (curSelected >= cutsceneGroup.members.length)
curSelected = 0;
}
else
{
var valueMulti:Float = 1;
if (FlxG.keys.pressed.SPACE)
valueMulti = 10;
if (FlxG.keys.justPressed.UP)
cutsceneGroup.members[curSelected].y -= valueMulti;
if (FlxG.keys.justPressed.DOWN)
cutsceneGroup.members[curSelected].y += valueMulti;
if (FlxG.keys.justPressed.LEFT)
cutsceneGroup.members[curSelected].x -= valueMulti;
if (FlxG.keys.justPressed.RIGHT)
cutsceneGroup.members[curSelected].x += valueMulti;
}
debugTxt.text = curSelected + " : " + cutsceneGroup.members[curSelected].getPosition();
*/
super.update(elapsed);
}
}

View File

@ -0,0 +1,79 @@
package game.objects.cutscene;
import flixel.FlxSprite;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.math.FlxPoint;
using StringTools;
class CutsceneCharacter extends FlxTypedGroup<FlxSprite>
{
public var coolPos:FlxPoint = FlxPoint.get();
public var animShit:Map<String, FlxPoint> = new Map();
private var imageShit:String;
public function new(x:Float, y:Float, imageShit:String)
{
super();
coolPos.set(x, y);
this.imageShit = imageShit;
parseOffsets();
createCutscene(0);
}
// shitshow, oh well
var arrayLMFAOOOO:Array<String> = [];
function parseOffsets()
{
var splitShit:Array<String> = CoolUtil.coolTextFile(Paths.file('images/cutsceneStuff/' + imageShit + "CutsceneOffsets.txt"));
for (i in splitShit)
{
var xAndY:FlxPoint = FlxPoint.get();
var dumbSplit:Array<String> = i.split('---')[1].trim().split(' ');
trace('cool split: ' + i.split('---')[1]);
trace(dumbSplit);
xAndY.set(Std.parseFloat(dumbSplit[0]), Std.parseFloat(dumbSplit[1]));
animShit.set(i.split('---')[0].trim(), xAndY);
arrayLMFAOOOO.push(i.split('---')[0].trim());
}
trace(animShit);
}
public function createCutscene(daNum:Int = 0)
{
var cutScene:FlxSprite = new FlxSprite(coolPos.x + animShit.get(arrayLMFAOOOO[daNum]).x, coolPos.y + animShit.get(arrayLMFAOOOO[daNum]).y);
cutScene.frames = Paths.getSparrowAtlas('cutsceneStuff/' + imageShit + "-" + daNum);
cutScene.animation.addByPrefix('weed', arrayLMFAOOOO[daNum], 24, false);
cutScene.animation.play('weed');
cutScene.antialiasing = true;
cutScene.animation.finishCallback = function(anim:String)
{
cutScene.kill();
cutScene.destroy();
cutScene = null;
if (daNum + 1 < arrayLMFAOOOO.length)
createCutscene(daNum + 1);
else
ended();
};
add(cutScene);
}
public var onFinish:Void->Void;
public function ended():Void
{
if (onFinish != null)
onFinish();
}
}

View File

@ -0,0 +1,62 @@
package game.objects.cutscene;
import flixel.FlxBasic;
import flixel.FlxG;
import flixel.FlxSprite;
import openfl.events.NetStatusEvent;
import openfl.media.Video;
import openfl.net.NetConnection;
import openfl.net.NetStream;
class FlxVideo extends FlxBasic
{
var video:Video;
var netStream:NetStream;
public var finishCallback:Void->Void;
/**
* Doesn't actually interact with Flixel shit, only just a pleasant to use class
*/
public function new(vidSrc:String)
{
super();
video = new Video();
video.x = 0;
video.y = 0;
FlxG.addChildBelowMouse(video);
var netConnection = new NetConnection();
netConnection.connect(null);
netStream = new NetStream(netConnection);
netStream.client = {onMetaData: client_onMetaData};
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus);
netStream.play(Paths.file(vidSrc));
}
public function finishVideo():Void
{
netStream.dispose();
FlxG.removeChild(video);
if (finishCallback != null)
finishCallback();
}
public function client_onMetaData(metaData:Dynamic)
{
video.attachNetStream(netStream);
video.width = FlxG.width;
video.height = FlxG.height;
}
private function netConnection_onNetStatus(event:NetStatusEvent):Void
{
if (event.info.code == 'NetStream.Play.Complete')
finishVideo();
}
}

View File

@ -0,0 +1,27 @@
package;
import flixel.FlxSprite;
import flixel.system.FlxSound;
class TankCutscene extends FlxSprite
{
public var startSyncAudio:FlxSound;
public function new(x:Float, y:Float)
{
super(x, y);
}
var startedPlayingSound:Bool = false;
override function update(elapsed:Float)
{
if (animation.curAnim.curFrame >= 1 && !startedPlayingSound)
{
startSyncAudio.play();
startedPlayingSound = true;
}
super.update(elapsed);
}
}

View File

@ -0,0 +1,34 @@
package game.objects.shaders;
import flixel.util.FlxColor;
import openfl.display.ShaderParameter;
typedef BlendModeShader =
{
var uBlendColor:ShaderParameter<Float>;
}
class BlendModeEffect
{
public var shader(default, null):BlendModeShader;
@:isVar
public var color(default, set):FlxColor;
public function new(shader:BlendModeShader, color:FlxColor):Void
{
shader.uBlendColor.value = [];
this.shader = shader;
this.color = color;
}
function set_color(color:FlxColor):FlxColor
{
shader.uBlendColor.value[0] = color.redFloat;
shader.uBlendColor.value[1] = color.greenFloat;
shader.uBlendColor.value[2] = color.blueFloat;
shader.uBlendColor.value[3] = color.alphaFloat;
return this.color = color;
}
}

View File

@ -0,0 +1,49 @@
package game.objects.shaders;
import flixel.system.FlxAssets.FlxShader;
class BuildingShaders
{
public var shader(default, null):BuildingShader;
public var daAlpha:Float = 1;
public function new():Void
{
shader = new BuildingShader();
shader.alphaShit.value = [0];
}
public function update(elapsed:Float):Void
{
shader.alphaShit.value[0] += elapsed;
}
public function reset()
{
shader.alphaShit.value[0] = 0;
}
}
class BuildingShader extends FlxShader
{
@:glFragmentSource('
#pragma header
uniform float alphaShit;
void main()
{
vec4 color = flixel_texture2D(bitmap, openfl_TextureCoordv);
if (color.a > 0.0)
color -= alphaShit;
gl_FragColor = color;
}
')
public function new()
{
super();
}
}

View File

@ -0,0 +1,159 @@
package game.objects.shaders;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxColor;
class ColorSwap
{
public var shader(default, null):ColorSwapShader;
public var colorToReplace(default, set):FlxColor;
public var newColor(default, set):FlxColor;
public var daTime(default, set):Float;
public var hasOutline(default, set):Bool = false;
public var hueShit:Float = 0;
public function new():Void
{
shader = new ColorSwapShader();
shader.uTime.value = [0];
shader.money.value = [0];
shader.awesomeOutline.value = [hasOutline];
}
public function update(elapsed:Float):Void
{
shader.uTime.value[0] += elapsed;
hueShit += elapsed;
// trace(shader.money.value[0]);
}
function set_colorToReplace(color:FlxColor):FlxColor
{
colorToReplace = color;
return color;
}
function set_hasOutline(lol:Bool):Bool
{
shader.awesomeOutline.value = [lol];
return lol;
}
function set_daTime(daTime:Float):Float
{
return daTime;
}
function set_newColor(color:FlxColor):FlxColor
{
newColor = color;
return color;
}
}
class ColorSwapShader extends FlxShader
{
@:glFragmentSource('
#pragma header
uniform float uTime;
uniform float money;
uniform bool awesomeOutline;
const float offset = 1.0 / 128.0;
vec3 normalizeColor(vec3 color)
{
return vec3(
color[0] / 255.0,
color[1] / 255.0,
color[2] / 255.0
);
}
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main()
{
vec4 color = flixel_texture2D(bitmap, openfl_TextureCoordv);
vec4 swagColor = vec4(rgb2hsv(vec3(color[0], color[1], color[2])), color[3]);
// [0] is the hue???
swagColor[0] += uTime;
// swagColor[1] += uTime;
// money += swagColor[0];
color = vec4(hsv2rgb(vec3(swagColor[0], swagColor[1], swagColor[2])), swagColor[3]);
if (awesomeOutline)
{
// Outline bullshit?
vec2 size = vec2(3, 3);
if (color.a <= 0.5) {
float w = size.x / openfl_TextureSize.x;
float h = size.y / openfl_TextureSize.y;
if (flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x + w, openfl_TextureCoordv.y)).a != 0.
|| flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x - w, openfl_TextureCoordv.y)).a != 0.
|| flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x, openfl_TextureCoordv.y + h)).a != 0.
|| flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x, openfl_TextureCoordv.y - h)).a != 0.)
color = vec4(1.0, 1.0, 1.0, 1.0);
}
}
gl_FragColor = color;
/*
if (color.a > 0.5)
gl_FragColor = color;
else
{
float a = flixel_texture2D(bitmap, vec2(openfl_TextureCoordv + offset, openfl_TextureCoordv.y)).a +
flixel_texture2D(bitmap, vec2(openfl_TextureCoordv, openfl_TextureCoordv.y - offset)).a +
flixel_texture2D(bitmap, vec2(openfl_TextureCoordv - offset, openfl_TextureCoordv.y)).a +
flixel_texture2D(bitmap, vec2(openfl_TextureCoordv, openfl_TextureCoordv.y + offset)).a;
if (color.a < 1.0 && a > 0.0)
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.8);
else
gl_FragColor = color;
} */
}
')
public function new()
{
super();
}
}

View File

@ -0,0 +1,33 @@
package game.objects.shaders;
import flixel.system.FlxAssets.FlxShader;
class OverlayShader extends FlxShader
{
@:glFragmentSource('
#pragma header
uniform vec4 uBlendColor;
vec3 blendLighten(base:Vec3, blend:Vec3) : Vec3 {
return mix(
1.0 - 2.0 * (1.0 - base) * (1.0 - blend),
2.0 * base * blend,
step( base, vec3(0.5) )
);
}
vec4 blendLighten(vec4 base, vec4 blend, float opacity)
{
return (blendLighten(base, blend) * opacity + base * (1.0 - opacity));
}
void main()
{
vec4 base = texture2D(bitmap, openfl_TextureCoordv);
gl_FragColor = blendLighten(base, uBlendColor, uBlendColor.a);
}')
public function new()
{
super();
}
}

View File

@ -0,0 +1,133 @@
package game.objects.shaders;
// STOLEN FROM HAXEFLIXEL DEMO LOL
import flixel.system.FlxAssets.FlxShader;
enum WiggleEffectType
{
DREAMY;
WAVY;
HEAT_WAVE_HORIZONTAL;
HEAT_WAVE_VERTICAL;
FLAG;
}
class WiggleEffect
{
public var shader(default, null):WiggleShader = new WiggleShader();
public var effectType(default, set):WiggleEffectType = DREAMY;
public var waveSpeed(default, set):Float = 0;
public var waveFrequency(default, set):Float = 0;
public var waveAmplitude(default, set):Float = 0;
public function new():Void
{
shader.uTime.value = [0];
}
public function update(elapsed:Float):Void
{
shader.uTime.value[0] += elapsed;
}
function set_effectType(v:WiggleEffectType):WiggleEffectType
{
effectType = v;
shader.effectType.value = [WiggleEffectType.getConstructors().indexOf(Std.string(v))];
return v;
}
function set_waveSpeed(v:Float):Float
{
waveSpeed = v;
shader.uSpeed.value = [waveSpeed];
return v;
}
function set_waveFrequency(v:Float):Float
{
waveFrequency = v;
shader.uFrequency.value = [waveFrequency];
return v;
}
function set_waveAmplitude(v:Float):Float
{
waveAmplitude = v;
shader.uWaveAmplitude.value = [waveAmplitude];
return v;
}
}
class WiggleShader extends FlxShader
{
@:glFragmentSource('
#pragma header
//uniform float tx, ty; // x,y waves phase
uniform float uTime;
const int EFFECT_TYPE_DREAMY = 0;
const int EFFECT_TYPE_WAVY = 1;
const int EFFECT_TYPE_HEAT_WAVE_HORIZONTAL = 2;
const int EFFECT_TYPE_HEAT_WAVE_VERTICAL = 3;
const int EFFECT_TYPE_FLAG = 4;
uniform int effectType;
/**
* How fast the waves move over time
*/
uniform float uSpeed;
/**
* Number of waves over time
*/
uniform float uFrequency;
/**
* How much the pixels are going to stretch over the waves
*/
uniform float uWaveAmplitude;
vec2 sineWave(vec2 pt)
{
float x = 0.0;
float y = 0.0;
if (effectType == EFFECT_TYPE_DREAMY)
{
float offsetX = sin(pt.y * uFrequency + uTime * uSpeed) * uWaveAmplitude;
pt.x += offsetX; // * (pt.y - 1.0); // <- Uncomment to stop bottom part of the screen from moving
}
else if (effectType == EFFECT_TYPE_WAVY)
{
float offsetY = sin(pt.x * uFrequency + uTime * uSpeed) * uWaveAmplitude;
pt.y += offsetY; // * (pt.y - 1.0); // <- Uncomment to stop bottom part of the screen from moving
}
else if (effectType == EFFECT_TYPE_HEAT_WAVE_HORIZONTAL)
{
x = sin(pt.x * uFrequency + uTime * uSpeed) * uWaveAmplitude;
}
else if (effectType == EFFECT_TYPE_HEAT_WAVE_VERTICAL)
{
y = sin(pt.y * uFrequency + uTime * uSpeed) * uWaveAmplitude;
}
else if (effectType == EFFECT_TYPE_FLAG)
{
y = sin(pt.y * uFrequency + 10.0 * pt.x + uTime * uSpeed) * uWaveAmplitude;
x = sin(pt.x * uFrequency + 5.0 * pt.y + uTime * uSpeed) * uWaveAmplitude;
}
return vec2(pt.x + x, pt.y + y);
}
void main()
{
vec2 uv = sineWave(openfl_TextureCoordv);
gl_FragColor = texture2D(bitmap, uv);
}')
public function new()
{
super();
}
}

View File

@ -0,0 +1,672 @@
package game.objects.stages;
import flixel.FlxBasic;
import flixel.FlxSprite;
import flixel.FlxG;
import flixel.math.FlxAngle;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import flixel.system.FlxSound;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.addons.effects.FlxTrail;
import flixel.addons.effects.chainable.FlxWaveEffect;
import game.data.backend.*;
import game.objects.*;
import game.objects.stages.background.*;
import game.state.PlayState;
import game.objects.shaders.BuildingShaders;
import game.objects.shaders.BuildingShaders.BuildingShader;
/*
If it wasn't obvious already, this class is heavily based off of
Forever Engines "Stage.hx"
Forever Engine by beloved
*/
class GameStage extends FlxTypedGroup<FlxBasic>
{
var pixelZoom = PlayState.daPixelZoom;
// Spooky Stage Stuff
var halloweenBG:FlxSprite;
var lightningStrikeBeat:Int = 0;
var lightningOffset:Int = 8;
// Philly Stage Stuff
// I love philly cheesesteaks
var phillyTrain:FlxSprite;
var trainSound:FlxSound;
var phillyCityLights:FlxTypedGroup<FlxSprite>;
var lightFadeShader:BuildingShaders;
// Limo Stage Stuff
public var limo:FlxSprite;
var fastCar:FlxSprite;
var grpLimoDancers:FlxTypedGroup<BackgroundDancer>;
// Mall Stage Stuff
var upperBoppers:FlxSprite;
var bottomBoppers:FlxSprite;
var santa:FlxSprite;
// School Stuff
var bgGirls:BackgroundGirls;
// Tank Stage Stuff
var tankWatchtower:BGSprite;
var tankGround:BGSprite;
public var tankmanRun:FlxTypedGroup<TankmenBG>;
public var foregroundSprites:FlxTypedGroup<BGSprite>;
// For if you want to have sprites in front of the characters
public var fgSprites:FlxTypedGroup<FlxBasic>;
public function new()
{
super();
foregroundSprites = new FlxTypedGroup<BGSprite>();
fgSprites = new FlxTypedGroup<FlxBasic>();
switch (getStage())
{
case 'stage':
PlayState.defaultCamZoom = 0.9;
var bg:BGSprite = new BGSprite('stageback', -600, -200, 0.9, 0.9);
add(bg);
var stageFront:FlxSprite = new FlxSprite(-650, 600).loadGraphic(Paths.image('stagefront'));
stageFront.setGraphicSize(Std.int(stageFront.width * 1.1));
stageFront.updateHitbox();
stageFront.antialiasing = true;
stageFront.scrollFactor.set(0.9, 0.9);
stageFront.active = false;
add(stageFront);
var stageCurtains:FlxSprite = new FlxSprite(-500, -300).loadGraphic(Paths.image('stagecurtains'));
stageCurtains.setGraphicSize(Std.int(stageCurtains.width * 0.9));
stageCurtains.updateHitbox();
stageCurtains.antialiasing = true;
stageCurtains.scrollFactor.set(1.3, 1.3);
stageCurtains.active = false;
add(stageCurtains);
case 'spooky':
var hallowTex = Paths.getSparrowAtlas('halloween_bg');
halloweenBG = new FlxSprite(-200, -100);
halloweenBG.frames = hallowTex;
halloweenBG.animation.addByPrefix('idle', 'halloweem bg0');
halloweenBG.animation.addByPrefix('lightning', 'halloweem bg lightning strike', 24, false);
halloweenBG.animation.play('idle');
halloweenBG.antialiasing = true;
add(halloweenBG);
case 'philly':
var bg:FlxSprite = new FlxSprite(-100).loadGraphic(Paths.image('philly/sky'));
bg.scrollFactor.set(0.1, 0.1);
add(bg);
var city:FlxSprite = new FlxSprite(-10).loadGraphic(Paths.image('philly/city'));
city.scrollFactor.set(0.3, 0.3);
city.setGraphicSize(Std.int(city.width * 0.85));
city.updateHitbox();
add(city);
lightFadeShader = new BuildingShaders();
phillyCityLights = new FlxTypedGroup<FlxSprite>();
add(phillyCityLights);
for (i in 0...5)
{
var light:FlxSprite = new FlxSprite(city.x).loadGraphic(Paths.image('philly/win' + i));
light.scrollFactor.set(0.3, 0.3);
light.visible = false;
light.setGraphicSize(Std.int(light.width * 0.85));
light.updateHitbox();
light.antialiasing = true;
light.shader = lightFadeShader.shader;
phillyCityLights.add(light);
}
var streetBehind:FlxSprite = new FlxSprite(-40, 50).loadGraphic(Paths.image('philly/behindTrain'));
add(streetBehind);
phillyTrain = new FlxSprite(2000, 360).loadGraphic(Paths.image('philly/train'));
add(phillyTrain);
var street:FlxSprite = new FlxSprite(-40, streetBehind.y).loadGraphic(Paths.image('philly/street'));
add(street);
trainSound = new FlxSound().loadEmbedded(Paths.sound('train_passes'));
FlxG.sound.list.add(trainSound);
case 'limo':
var skyBG:FlxSprite = new FlxSprite(-120, -50).loadGraphic(Paths.image('limo/limoSunset'));
skyBG.scrollFactor.set(0.1, 0.1);
add(skyBG);
var bgLimo:FlxSprite = new FlxSprite(-200, 480);
bgLimo.frames = Paths.getSparrowAtlas('limo/bgLimo');
bgLimo.animation.addByPrefix('drive', "background limo pink", 24);
bgLimo.animation.play('drive');
bgLimo.scrollFactor.set(0.4, 0.4);
add(bgLimo);
grpLimoDancers = new FlxTypedGroup<BackgroundDancer>();
add(grpLimoDancers);
for (i in 0...5)
{
var dancer:BackgroundDancer = new BackgroundDancer((370 * i) + 130, bgLimo.y - 400);
dancer.scrollFactor.set(0.4, 0.4);
grpLimoDancers.add(dancer);
}
var overlayShit:FlxSprite = new FlxSprite(-500, -600).loadGraphic(Paths.image('limo/limoOverlay'));
overlayShit.alpha = 0.5;
limo = new FlxSprite(-120, 550);
limo.frames = Paths.getSparrowAtlas('limo/limoDrive');
limo.animation.addByPrefix('drive', "Limo stage", 24);
limo.animation.play('drive');
limo.antialiasing = true;
fastCar = new FlxSprite(-300, 160).loadGraphic(Paths.image('limo/fastCarLol'));
case 'mall':
PlayState.defaultCamZoom = 0.80;
var bg:FlxSprite = new FlxSprite(-1000, -500).loadGraphic(Paths.image('christmas/bgWalls'));
bg.antialiasing = true;
bg.scrollFactor.set(0.2, 0.2);
bg.active = false;
bg.setGraphicSize(Std.int(bg.width * 0.8));
bg.updateHitbox();
add(bg);
upperBoppers = new FlxSprite(-240, -90);
upperBoppers.frames = Paths.getSparrowAtlas('christmas/upperBop');
upperBoppers.animation.addByPrefix('bop', "Upper Crowd Bob", 24, false);
upperBoppers.antialiasing = true;
upperBoppers.scrollFactor.set(0.33, 0.33);
upperBoppers.setGraphicSize(Std.int(upperBoppers.width * 0.85));
upperBoppers.updateHitbox();
add(upperBoppers);
var bgEscalator:FlxSprite = new FlxSprite(-1100, -600).loadGraphic(Paths.image('christmas/bgEscalator'));
bgEscalator.antialiasing = true;
bgEscalator.scrollFactor.set(0.3, 0.3);
bgEscalator.active = false;
bgEscalator.setGraphicSize(Std.int(bgEscalator.width * 0.9));
bgEscalator.updateHitbox();
add(bgEscalator);
var tree:FlxSprite = new FlxSprite(370, -250).loadGraphic(Paths.image('christmas/christmasTree'));
tree.antialiasing = true;
tree.scrollFactor.set(0.40, 0.40);
add(tree);
bottomBoppers = new FlxSprite(-300, 140);
bottomBoppers.frames = Paths.getSparrowAtlas('christmas/bottomBop');
bottomBoppers.animation.addByPrefix('bop', 'Bottom Level Boppers', 24, false);
bottomBoppers.antialiasing = true;
bottomBoppers.scrollFactor.set(0.9, 0.9);
bottomBoppers.setGraphicSize(Std.int(bottomBoppers.width * 1));
bottomBoppers.updateHitbox();
add(bottomBoppers);
var fgSnow:FlxSprite = new FlxSprite(-600, 700).loadGraphic(Paths.image('christmas/fgSnow'));
fgSnow.active = false;
fgSnow.antialiasing = true;
add(fgSnow);
santa = new FlxSprite(-840, 150);
santa.frames = Paths.getSparrowAtlas('christmas/santa');
santa.animation.addByPrefix('idle', 'santa idle in fear', 24, false);
santa.antialiasing = true;
add(santa);
case 'mallEvil':
var bg:FlxSprite = new FlxSprite(-400, -500).loadGraphic(Paths.image('christmas/evilBG'));
bg.antialiasing = true;
bg.scrollFactor.set(0.2, 0.2);
bg.active = false;
bg.setGraphicSize(Std.int(bg.width * 0.8));
bg.updateHitbox();
add(bg);
var evilTree:FlxSprite = new FlxSprite(300, -300).loadGraphic(Paths.image('christmas/evilTree'));
evilTree.antialiasing = true;
evilTree.scrollFactor.set(0.2, 0.2);
add(evilTree);
var evilSnow:FlxSprite = new FlxSprite(-200, 700).loadGraphic(Paths.image("christmas/evilSnow"));
evilSnow.antialiasing = true;
add(evilSnow);
case 'school':
PlayState.isPixel = true;
var bgSky = new FlxSprite().loadGraphic(Paths.image('weeb/weebSky'));
bgSky.scrollFactor.set(0.1, 0.1);
add(bgSky);
var repositionShit = -200;
var bgSchool:FlxSprite = new FlxSprite(repositionShit, 0).loadGraphic(Paths.image('weeb/weebSchool'));
bgSchool.scrollFactor.set(0.6, 0.90);
add(bgSchool);
var bgStreet:FlxSprite = new FlxSprite(repositionShit).loadGraphic(Paths.image('weeb/weebStreet'));
bgStreet.scrollFactor.set(0.95, 0.95);
add(bgStreet);
var fgTrees:FlxSprite = new FlxSprite(repositionShit + 170, 130).loadGraphic(Paths.image('weeb/weebTreesBack'));
fgTrees.scrollFactor.set(0.9, 0.9);
add(fgTrees);
var bgTrees:FlxSprite = new FlxSprite(repositionShit - 380, -800);
var treetex = Paths.getPackerAtlas('weeb/weebTrees');
bgTrees.frames = treetex;
bgTrees.animation.add('treeLoop', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], 12);
bgTrees.animation.play('treeLoop');
bgTrees.scrollFactor.set(0.85, 0.85);
add(bgTrees);
var treeLeaves:FlxSprite = new FlxSprite(repositionShit, -40);
treeLeaves.frames = Paths.getSparrowAtlas('weeb/petals');
treeLeaves.animation.addByPrefix('leaves', 'PETALS ALL', 24, true);
treeLeaves.animation.play('leaves');
treeLeaves.scrollFactor.set(0.85, 0.85);
add(treeLeaves);
var widShit = Std.int(bgSky.width * 6);
bgSky.setGraphicSize(widShit);
bgSchool.setGraphicSize(widShit);
bgStreet.setGraphicSize(widShit);
bgTrees.setGraphicSize(Std.int(widShit * 1.4));
fgTrees.setGraphicSize(Std.int(widShit * 0.8));
treeLeaves.setGraphicSize(widShit);
fgTrees.updateHitbox();
bgSky.updateHitbox();
bgSchool.updateHitbox();
bgStreet.updateHitbox();
bgTrees.updateHitbox();
treeLeaves.updateHitbox();
bgGirls = new BackgroundGirls(-100, 190);
bgGirls.scrollFactor.set(0.9, 0.9);
if (PlayState.SONG.song.toLowerCase() == 'roses') bgGirls.getScared();
bgGirls.setGraphicSize(Std.int(bgGirls.width * pixelZoom));
bgGirls.updateHitbox();
add(bgGirls);
case 'schoolEvil':
PlayState.isPixel = true;
var waveEffectBG = new FlxWaveEffect(FlxWaveMode.ALL, 2, -1, 3, 2);
var waveEffectFG = new FlxWaveEffect(FlxWaveMode.ALL, 2, -1, 5, 2);
var posX = 400;
var posY = 200;
var bg:FlxSprite = new FlxSprite(posX, posY);
bg.frames = Paths.getSparrowAtlas('weeb/animatedEvilSchool');
bg.animation.addByPrefix('idle', 'background 2', 24);
bg.animation.play('idle');
bg.scrollFactor.set(0.8, 0.9);
bg.scale.set(6, 6);
add(bg);
case 'tank':
PlayState.defaultCamZoom = 0.90;
var bg:BGSprite = new BGSprite('tankSky', -400, -400, 0, 0);
add(bg);
var tankSky:BGSprite = new BGSprite('tankClouds', FlxG.random.int(-700, -100), FlxG.random.int(-20, 20), 0.1, 0.1);
tankSky.active = true;
tankSky.velocity.x = FlxG.random.float(5, 15);
add(tankSky);
var tankMountains:BGSprite = new BGSprite('tankMountains', -300, -20, 0.2, 0.2);
tankMountains.setGraphicSize(Std.int(tankMountains.width * 1.2));
tankMountains.updateHitbox();
add(tankMountains);
var tankBuildings:BGSprite = new BGSprite('tankBuildings', -200, 0, 0.30, 0.30);
tankBuildings.setGraphicSize(Std.int(tankBuildings.width * 1.1));
tankBuildings.updateHitbox();
add(tankBuildings);
var tankRuins:BGSprite = new BGSprite('tankRuins', -200, 0, 0.35, 0.35);
tankRuins.setGraphicSize(Std.int(tankRuins.width * 1.1));
tankRuins.updateHitbox();
add(tankRuins);
var smokeLeft:BGSprite = new BGSprite('smokeLeft', -200, -100, 0.4, 0.4, ['SmokeBlurLeft'], true);
add(smokeLeft);
var smokeRight:BGSprite = new BGSprite('smokeRight', 1100, -100, 0.4, 0.4, ['SmokeRight'], true);
add(smokeRight);
// tankGround.
tankWatchtower = new BGSprite('tankWatchtower', 100, 50, 0.5, 0.5, ['watchtower gradient color']);
add(tankWatchtower);
tankGround = new BGSprite('tankRolling', 300, 300, 0.5, 0.5, ['BG tank w lighting'], true);
add(tankGround);
// tankGround.active = false;
tankmanRun = new FlxTypedGroup<TankmenBG>();
add(tankmanRun);
var tankGround:BGSprite = new BGSprite('tankGround', -420, -150);
tankGround.setGraphicSize(Std.int(tankGround.width * 1.15));
tankGround.updateHitbox();
add(tankGround);
moveTank();
// smokeLeft.screenCenter();
var fgTank0:BGSprite = new BGSprite('tank0', -500, 650, 1.7, 1.5, ['fg']);
foregroundSprites.add(fgTank0);
var fgTank1:BGSprite = new BGSprite('tank1', -300, 750, 2, 0.2, ['fg']);
foregroundSprites.add(fgTank1);
// just called 'foreground' just cuz small inconsistency no bbiggei
var fgTank2:BGSprite = new BGSprite('tank2', 450, 940, 1.5, 1.5, ['foreground']);
foregroundSprites.add(fgTank2);
var fgTank4:BGSprite = new BGSprite('tank4', 1300, 900, 1.5, 1.5, ['fg']);
foregroundSprites.add(fgTank4);
var fgTank5:BGSprite = new BGSprite('tank5', 1620, 700, 1.5, 1.5, ['fg']);
foregroundSprites.add(fgTank5);
var fgTank3:BGSprite = new BGSprite('tank3', 1300, 1200, 3.5, 2.5, ['fg']);
foregroundSprites.add(fgTank3);
}
}
// Define Your Songs Stage Here
public function getStage()
{
var curStage:String = 'stage';
switch (PlayState.SONG.song.toLowerCase())
{
case 'spookeez' | 'south' | 'monster': curStage = 'spooky';
case 'pico' | 'philly' | 'blammed': curStage = 'philly';
case 'satin-panties' | 'high' | 'milf': curStage = 'limo';
case 'coca' | 'eggnog': curStage = 'mall';
case 'winter-horrorland': curStage = 'mallEvil';
case 'senpai' | 'roses': curStage = 'school';
case 'thorns': curStage = 'schoolEvil';
case 'ugh' | 'guns' | 'stress': curStage = 'tank';
}
return curStage;
}
public function getGF()
{
var GF:String = 'gf';
switch (getStage())
{
case 'limo': GF = 'gf-car';
case 'mall' | 'mallEvil': GF = 'gf-christmas';
case 'tank': GF = 'gf-tankmen';
}
if (PlayState.isPixel) GF = 'gf-pixel';
if (PlayState.SONG.song.toLowerCase() == 'stress') GF = 'pico-speaker';
return GF;
}
// Put Character Positions Here
public function positionChars(bf:Character, dad:Character, gf:Character)
{
switch (getStage())
{
case 'limo':
bf.y -= 220;
bf.x += 260;
resetFastCar();
add(fastCar);
case 'mall':
bf.x += 200;
case 'mallEvil':
bf.x += 320;
dad.y -= 80;
case 'school':
bf.x += 200;
bf.y += 220;
gf.x += 180;
gf.y += 300;
case 'schoolEvil':
var evilTrail = new FlxTrail(dad, null, 4, 24, 0.3, 0.069);
add(evilTrail);
bf.x += 200;
bf.y += 220;
gf.x += 180;
gf.y += 300;
case "tank":
gf.y += 10;
gf.x -= 30;
bf.x += 40;
bf.y += 0;
dad.y += 60;
dad.x -= 80;
if (getGF() != 'pico-speaker')
{
gf.x -= 170;
gf.y -= 75;
}
}
}
public function updateStage(elapsed:Float, bf:Character, dad:Character, gf:Character)
{
switch (getStage())
{
case 'philly':
if (trainMoving)
{
trainFrameTiming += elapsed;
if (trainFrameTiming >= 1 / 24)
{
updateTrainPos(gf);
trainFrameTiming = 0;
}
}
lightFadeShader.update((Conductor.crochet / 1000) * FlxG.elapsed * 1.5);
case 'tank': moveTank();
}
}
// Stage Events eg: bgChar bopping etc.
public function beatHit(beat:Int, bf:Character, dad:Character, gf:Character)
{
switch (getStage())
{
case 'spooky':
if (FlxG.random.bool(10) && beat > lightningStrikeBeat + lightningOffset) {
FlxG.sound.play(Paths.soundRandom('thunder_', 1, 2));
halloweenBG.animation.play('lightning');
lightningStrikeBeat = beat;
lightningOffset = FlxG.random.int(8, 24);
bf.playAnim('scared', true);
gf.playAnim('scared', true);
}
case 'philly':
if (!trainMoving) trainCooldown += 1;
if (beat % 4 == 0)
{
lightFadeShader.reset();
phillyCityLights.forEach(function(light:FlxSprite)
{
light.visible = false;
});
curLight = FlxG.random.int(0, phillyCityLights.length - 1);
phillyCityLights.members[curLight].visible = true;
}
if (beat % 8 == 4 && FlxG.random.bool(30) && !trainMoving && trainCooldown > 8)
{
trainCooldown = FlxG.random.int(-4, 0);
trainStart();
}
case 'limo':
grpLimoDancers.forEach(function(dancer:BackgroundDancer)
{
dancer.dance();
});
if (FlxG.random.bool(10) && fastCarCanDrive) fastCarDrive();
case 'mall':
upperBoppers.animation.play('bop', true);
bottomBoppers.animation.play('bop', true);
santa.animation.play('idle', true);
case 'school': bgGirls.dance();
case 'tank':
tankWatchtower.dance();
foregroundSprites.forEach(function(spr:BGSprite)
{
spr.dance();
});
}
}
// Same as above
public function stepHit(step:Int, bf:Character, dad:Character, gf:Character)
{
}
// Other
// Philly Stuff
var trainMoving:Bool = false;
var trainFrameTiming:Float = 0;
var trainCars:Int = 8;
var trainFinishing:Bool = false;
var trainCooldown:Int = 0;
var startedMoving:Bool = false;
var curLight:Int = 0;
function updateTrainPos(gf:Character):Void
{
if (trainSound.time >= 4700)
{
startedMoving = true;
gf.playAnim('hairBlow');
}
if (startedMoving)
{
phillyTrain.x -= 400;
if (phillyTrain.x < -2000 && !trainFinishing)
{
phillyTrain.x = -1150;
trainCars -= 1;
if (trainCars <= 0) trainFinishing = true;
}
if (phillyTrain.x < -4000 && trainFinishing) trainReset(gf);
}
}
function trainReset(gf:Character):Void
{
gf.playAnim('hairFall');
phillyTrain.x = FlxG.width + 200;
trainMoving = false;
trainCars = 8;
trainFinishing = false;
startedMoving = false;
}
function trainStart():Void
{
trainMoving = true;
trainSound.play(true);
}
// Limo Stuff
var fastCarCanDrive:Bool = true;
function fastCarDrive()
{
FlxG.sound.play(Paths.soundRandom('carPass', 0, 1), 0.7);
fastCar.velocity.x = (FlxG.random.int(170, 220) / FlxG.elapsed) * 3;
fastCarCanDrive = false;
new FlxTimer().start(2, function(tmr:FlxTimer)
{
resetFastCar();
});
}
public function resetFastCar():Void
{
fastCar.x = -12600;
fastCar.y = FlxG.random.int(140, 250);
fastCar.velocity.x = 0;
fastCarCanDrive = true;
}
// Tank Stuff
var tankResetShit:Bool = false;
var tankMoving:Bool = false;
var tankAngle:Float = FlxG.random.int(-90, 45);
var tankSpeed:Float = FlxG.random.float(5, 7);
var tankX:Float = 400;
function moveTank():Void
{
if (!PlayState.inCutscene)
{
var daAngleOffset:Float = 1;
tankAngle += FlxG.elapsed * tankSpeed;
tankGround.angle = tankAngle - 90 + 15;
tankGround.x = tankX + Math.cos(FlxAngle.asRadians((tankAngle * daAngleOffset) + 180)) * 1500;
tankGround.y = 1300 + Math.sin(FlxAngle.asRadians((tankAngle * daAngleOffset) + 180)) * 1100;
}
}
override function add(obj:FlxBasic):FlxBasic { return super.add(obj); }
}

View File

@ -0,0 +1,43 @@
package game.objects.stages.background;
import flixel.FlxSprite;
class BGSprite extends FlxSprite
{
/**
Cool lil utility thing just so that it can easy do antialiasing and scrollfactor bullshit
*/
public var idleAnim:String;
public function new(image:String, x:Float = 0, y:Float = 0, parX:Float = 1, parY:Float = 1, ?daAnimations:Array<String>, ?loopingAnim:Bool = false)
{
super(x, y);
if (daAnimations != null)
{
frames = Paths.getSparrowAtlas(image);
for (anims in daAnimations)
{
animation.addByPrefix(anims, anims, 24, loopingAnim);
animation.play(anims);
if (idleAnim == null)
idleAnim = anims;
}
}
else
{
loadGraphic(Paths.image(image));
active = false;
}
scrollFactor.set(parX, parY);
antialiasing = true;
}
public function dance():Void
{
if (idleAnim != null)
animation.play(idleAnim);
}
}

View File

@ -0,0 +1,28 @@
package game.objects.stages.background;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
class BackgroundDancer extends FlxSprite
{
public function new(x:Float, y:Float)
{
super(x, y);
frames = Paths.getSparrowAtlas("limo/limoDancer");
animation.addByIndices('danceLeft', 'bg dancer sketch PINK', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
animation.addByIndices('danceRight', 'bg dancer sketch PINK', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
animation.play('danceLeft');
animation.finish();
antialiasing = true;
}
var danceDir:Bool = false;
public function dance():Void
{
danceDir = !danceDir;
var anim:String = danceDir ? 'danceRight' : 'danceLeft';
animation.play(anim, true);
}
}

View File

@ -0,0 +1,38 @@
package game.objects.stages.background;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
class BackgroundGirls extends FlxSprite
{
public function new(x:Float, y:Float)
{
super(x, y);
// BG fangirls dissuaded
frames = Paths.getSparrowAtlas('weeb/bgFreaks');
animation.addByIndices('danceLeft', 'BG girls group', CoolUtil.numberArray(14), "", 24, false);
animation.addByIndices('danceRight', 'BG girls group', CoolUtil.numberArray(30, 15), "", 24, false);
animation.play('danceLeft');
animation.finish();
}
var danceDir:Bool = false;
public function getScared():Void
{
animation.addByIndices('danceLeft', 'BG fangirls dissuaded', CoolUtil.numberArray(14), "", 24, false);
animation.addByIndices('danceRight', 'BG fangirls dissuaded', CoolUtil.numberArray(30, 15), "", 24, false);
dance();
animation.finish();
}
public function dance():Void
{
danceDir = !danceDir;
var anim:String = danceDir ? 'danceRight' : 'danceLeft';
animation.play(anim, true);
}
}

View File

@ -0,0 +1,92 @@
package game.objects.stages.background;
import flixel.FlxG;
import flixel.FlxSprite;
import haxe.display.Display.Package;
import game.data.backend.Conductor;
class TankmenBG extends FlxSprite
{
public static var animationNotes:Array<Dynamic> = [];
public var strumTime:Float = 0;
public var goingRight:Bool = false;
public var tankSpeed:Float = 0.7;
public var endingOffset:Float;
public function new(x:Float, y:Float, isGoingRight:Bool)
{
super(x, y);
// makeGraphic(200, 200);
frames = Paths.getSparrowAtlas('tankmanKilled1');
antialiasing = true;
animation.addByPrefix('run', 'tankman running', 24, true);
animation.addByPrefix('shot', 'John Shot ' + FlxG.random.int(1, 2), 24, false);
animation.play('run');
animation.curAnim.curFrame = FlxG.random.int(0, animation.curAnim.numFrames - 1);
updateHitbox();
setGraphicSize(Std.int(width * 0.8));
updateHitbox();
}
public function resetShit(x:Float, y:Float, isGoingRight:Bool)
{
setPosition(x, y);
goingRight = isGoingRight;
endingOffset = FlxG.random.float(50, 200);
tankSpeed = FlxG.random.float(0.6, 1);
if (goingRight)
flipX = true;
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (x >= FlxG.width * 1.2 || x <= FlxG.width * -0.5)
visible = false;
else
visible = true;
if (animation.curAnim.name == 'run')
{
var endDirection:Float = (FlxG.width * 0.74) + endingOffset;
if (goingRight)
{
endDirection = (FlxG.width * 0.02) - endingOffset;
x = (endDirection + (Conductor.songPosition - strumTime) * tankSpeed);
}
else
{
x = (endDirection - (Conductor.songPosition - strumTime) * tankSpeed);
}
}
if (Conductor.songPosition > strumTime)
{
// kill();
animation.play('shot');
if (goingRight)
{
offset.y = 200;
offset.x = 300;
}
}
if (animation.curAnim.name == 'shot' && animation.curAnim.curFrame >= animation.curAnim.frames.length - 1)
{
kill();
}
}
}

View File

@ -0,0 +1,84 @@
package game.state;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.transition.FlxTransitionableState;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.input.gamepad.FlxGamepad;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import game.objects.*;
class GameOverState extends FlxTransitionableState
{
var bfX:Float = 0;
var bfY:Float = 0;
public function new(x:Float, y:Float)
{
super();
bfX = x;
bfY = y;
}
override function create()
{
/* var loser:FlxSprite = new FlxSprite(100, 100);
var loseTex = FlxAtlasFrames.fromSparrow(AssetPaths.lose.png, AssetPaths.lose.xml);
loser.frames = loseTex;
loser.animation.addByPrefix('lose', 'lose', 24, false);
loser.animation.play('lose');
// add(loser); */
var bf:Boyfriend = new Boyfriend(bfX, bfY);
// bf.scrollFactor.set();
add(bf);
bf.playAnim('firstDeath');
FlxG.camera.follow(bf, LOCKON, 0.001);
/*
var restart:FlxSprite = new FlxSprite(500, 50).loadGraphic(AssetPaths.restart.png);
restart.setGraphicSize(Std.int(restart.width * 0.6));
restart.updateHitbox();
restart.alpha = 0;
restart.antialiasing = true;
// add(restart); */
FlxG.sound.music.fadeOut(2, FlxG.sound.music.volume * 0.6);
// FlxTween.tween(restart, {alpha: 1}, 1, {ease: FlxEase.quartInOut});
// FlxTween.tween(restart, {y: restart.y + 40}, 7, {ease: FlxEase.quartInOut, type: PINGPONG});
super.create();
}
private var fading:Bool = false;
override function update(elapsed:Float)
{
var pressed:Bool = FlxG.keys.justPressed.ANY;
var gamepad:FlxGamepad = FlxG.gamepads.lastActive;
if (gamepad != null)
{
if (gamepad.justPressed.ANY)
pressed = true;
}
pressed = false;
if (pressed && !fading)
{
fading = true;
FlxG.sound.music.fadeOut(0.5, 0, function(twn:FlxTween)
{
FlxG.sound.music.stop();
LoadingState.loadAndSwitchState(new PlayState());
});
}
super.update(elapsed);
}
}

View File

@ -0,0 +1,90 @@
package game.state;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import game.state.menus.*;
class GitarooPause extends MusicBeatState
{
var replayButton:FlxSprite;
var cancelButton:FlxSprite;
var replaySelect:Bool = false;
public function new():Void
{
super();
}
override function create()
{
if (FlxG.sound.music != null)
FlxG.sound.music.stop();
var bg:FlxSprite = new FlxSprite().loadGraphic(Paths.image('pauseAlt/pauseBG'));
add(bg);
var bf:FlxSprite = new FlxSprite(0, 30);
bf.frames = Paths.getSparrowAtlas('pauseAlt/bfLol');
bf.animation.addByPrefix('lol', "funnyThing", 13);
bf.animation.play('lol');
add(bf);
bf.screenCenter(X);
replayButton = new FlxSprite(FlxG.width * 0.28, FlxG.height * 0.7);
replayButton.frames = Paths.getSparrowAtlas('pauseAlt/pauseUI');
replayButton.animation.addByPrefix('selected', 'bluereplay', 0, false);
replayButton.animation.appendByPrefix('selected', 'yellowreplay');
replayButton.animation.play('selected');
add(replayButton);
cancelButton = new FlxSprite(FlxG.width * 0.58, replayButton.y);
cancelButton.frames = Paths.getSparrowAtlas('pauseAlt/pauseUI');
cancelButton.animation.addByPrefix('selected', 'bluecancel', 0, false);
cancelButton.animation.appendByPrefix('selected', 'cancelyellow');
cancelButton.animation.play('selected');
add(cancelButton);
changeThing();
super.create();
}
override function update(elapsed:Float)
{
if (controls.UI_LEFT_P || controls.UI_RIGHT_P)
changeThing();
if (controls.ACCEPT)
{
if (replaySelect)
{
FlxG.switchState(new PlayState());
}
else
{
FlxG.switchState(new MainMenuState());
}
}
super.update(elapsed);
}
function changeThing():Void
{
replaySelect = !replaySelect;
if (replaySelect)
{
cancelButton.animation.curAnim.curFrame = 0;
replayButton.animation.curAnim.curFrame = 1;
}
else
{
cancelButton.animation.curAnim.curFrame = 1;
replayButton.animation.curAnim.curFrame = 0;
}
}
}

View File

@ -0,0 +1,339 @@
package game.state;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.math.FlxMath;
import flixel.util.FlxTimer;
import haxe.io.Path;
import lime.app.Future;
import lime.app.Promise;
import lime.utils.AssetLibrary;
import lime.utils.AssetManifest;
import lime.utils.Assets as LimeAssets;
import openfl.utils.Assets;
class LoadingState extends MusicBeatState
{
inline static var MIN_TIME = 1.0;
var target:FlxState;
var stopMusic = false;
var callbacks:MultiCallback;
var danceLeft = false;
var loadBar:FlxSprite;
var funkay:FlxSprite;
function new(target:FlxState, stopMusic:Bool)
{
super();
this.target = target;
this.stopMusic = stopMusic;
}
override function create()
{
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, 0xFFcaff4d);
add(bg);
funkay = new FlxSprite();
funkay.loadGraphic(Paths.image('funkay'));
funkay.setGraphicSize(0, FlxG.height);
funkay.updateHitbox();
funkay.antialiasing = true;
add(funkay);
funkay.scrollFactor.set();
funkay.screenCenter();
loadBar = new FlxSprite(0, FlxG.height - 20).makeGraphic(FlxG.width, 10, 0xFFff16d2);
loadBar.screenCenter(X);
add(loadBar);
initSongsManifest().onComplete(function(lib)
{
callbacks = new MultiCallback(onLoad);
var introComplete = callbacks.add("introComplete");
checkLoadSong(getSongPath());
if (PlayState.SONG.needsVoices)
checkLoadSong(getVocalPath());
checkLibrary("shared");
if (PlayState.storyWeek > 0)
checkLibrary("week" + PlayState.storyWeek);
else
checkLibrary("tutorial");
var fadeTime = 0.5;
FlxG.camera.fade(FlxG.camera.bgColor, fadeTime, true);
new FlxTimer().start(fadeTime + MIN_TIME, function(_) introComplete());
});
}
function checkLoadSong(path:String)
{
if (!Assets.cache.hasSound(path))
{
var library = Assets.getLibrary("songs");
var symbolPath = path.split(":").pop();
// @:privateAccess
// library.types.set(symbolPath, SOUND);
// @:privateAccess
// library.pathGroups.set(symbolPath, [library.__cacheBreak(symbolPath)]);
var callback = callbacks.add("song:" + path);
Assets.loadSound(path).onComplete(function(_)
{
callback();
});
}
}
function checkLibrary(library:String)
{
trace(Assets.hasLibrary(library));
if (Assets.getLibrary(library) == null)
{
@:privateAccess
if (!LimeAssets.libraryPaths.exists(library))
throw "Missing library: " + library;
var callback = callbacks.add("library:" + library);
Assets.loadLibrary(library).onComplete(function(_)
{
callback();
});
}
}
override function beatHit()
{
super.beatHit();
// logo.animation.play('bump');
danceLeft = !danceLeft;
/*
if (danceLeft)
gfDance.animation.play('danceRight');
else
gfDance.animation.play('danceLeft'); */
}
var targetShit:Float = 0;
override function update(elapsed:Float)
{
super.update(elapsed);
funkay.setGraphicSize(Std.int(FlxMath.lerp(FlxG.width * 0.88, funkay.width, 0.9)));
funkay.updateHitbox();
// funkay.updateHitbox();
if (controls.ACCEPT)
{
funkay.setGraphicSize(Std.int(funkay.width + 60));
funkay.updateHitbox();
// funkay.setGraphicSize(0, Std.int(funkay.height + 50));
// funkay.updateHitbox();
// funkay.screenCenter();
}
if (callbacks != null)
{
targetShit = FlxMath.remapToRange(callbacks.numRemaining / callbacks.length, 1, 0, 0, 1);
loadBar.scale.x = FlxMath.lerp(loadBar.scale.x, targetShit, 0.50);
FlxG.watch.addQuick('percentage?', callbacks.numRemaining / callbacks.length);
}
#if debug
if (FlxG.keys.justPressed.SPACE)
trace('fired: ' + callbacks.getFired() + " unfired:" + callbacks.getUnfired());
#end
}
function onLoad()
{
if (stopMusic && FlxG.sound.music != null)
FlxG.sound.music.stop();
FlxG.switchState(target);
}
static function getSongPath()
{
return Paths.inst(PlayState.SONG.song);
}
static function getVocalPath()
{
return Paths.voices(PlayState.SONG.song);
}
inline static public function loadAndSwitchState(target:FlxState, stopMusic = false)
{
FlxG.switchState(getNextState(target, stopMusic));
}
static function getNextState(target:FlxState, stopMusic = false):FlxState
{
Paths.setCurrentLevel("week" + PlayState.storyWeek);
#if NO_PRELOAD_ALL
var loaded = isSoundLoaded(getSongPath())
&& (!PlayState.SONG.needsVoices || isSoundLoaded(getVocalPath()))
&& isLibraryLoaded("shared");
if (!loaded)
return new LoadingState(target, stopMusic);
#end
if (stopMusic && FlxG.sound.music != null)
FlxG.sound.music.stop();
return target;
}
#if NO_PRELOAD_ALL
static function isSoundLoaded(path:String):Bool
{
return Assets.cache.hasSound(path);
}
static function isLibraryLoaded(library:String):Bool
{
return Assets.getLibrary(library) != null;
}
#end
override function destroy()
{
super.destroy();
callbacks = null;
}
static function initSongsManifest()
{
var id = "songs";
var promise = new Promise<AssetLibrary>();
var library = LimeAssets.getLibrary(id);
if (library != null)
{
return Future.withValue(library);
}
var path = id;
var rootPath = null;
@:privateAccess
var libraryPaths = LimeAssets.libraryPaths;
if (libraryPaths.exists(id))
{
path = libraryPaths[id];
rootPath = Path.directory(path);
}
else
{
if (StringTools.endsWith(path, ".bundle"))
{
rootPath = path;
path += "/library.json";
}
else
{
rootPath = Path.directory(path);
}
@:privateAccess
path = LimeAssets.__cacheBreak(path);
}
AssetManifest.loadFromFile(path, rootPath).onComplete(function(manifest)
{
if (manifest == null)
{
promise.error("Cannot parse asset manifest for library \"" + id + "\"");
return;
}
var library = AssetLibrary.fromManifest(manifest);
if (library == null)
{
promise.error("Cannot open library \"" + id + "\"");
}
else
{
@:privateAccess
LimeAssets.libraries.set(id, library);
library.onChange.add(LimeAssets.onChange.dispatch);
promise.completeWith(Future.withValue(library));
}
}).onError(function(_)
{
promise.error("There is no asset library with an ID of \"" + id + "\"");
});
return promise.future;
}
}
class MultiCallback
{
public var callback:Void->Void;
public var logId:String = null;
public var length(default, null) = 0;
public var numRemaining(default, null) = 0;
var unfired = new Map<String, Void->Void>();
var fired = new Array<String>();
public function new(callback:Void->Void, logId:String = null)
{
this.callback = callback;
this.logId = logId;
}
public function add(id = "untitled")
{
id = '$length:$id';
length++;
numRemaining++;
var func:Void->Void = null;
func = function()
{
if (unfired.exists(id))
{
unfired.remove(id);
fired.push(id);
numRemaining--;
if (logId != null)
log('fired $id, $numRemaining remaining');
if (numRemaining == 0)
{
if (logId != null)
log('all callbacks fired');
callback();
}
}
else
log('already fired $id');
}
unfired[id] = func;
return func;
}
inline function log(msg):Void
{
if (logId != null)
trace('$logId: $msg');
}
public function getFired()
return fired.copy();
public function getUnfired()
return [for (id in unfired.keys()) id];
}

View File

@ -0,0 +1,76 @@
package game.state;
import game.data.backend.*;
import game.data.backend.Conductor.BPMChangeEvent;
import game.state.menus.options.controls.*;
import game.data.*;
import flixel.FlxG;
import flixel.FlxGame;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.ui.FlxUIState;
import flixel.math.FlxRect;
import flixel.util.FlxTimer;
class MusicBeatState extends FlxUIState
{
private var curStep:Int = 0;
private var curBeat:Int = 0;
private var controls(get, never):Controls;
inline function get_controls():Controls
return PlayerSettings.player1.controls;
override function create()
{
if (transIn != null)
trace('reg ' + transIn.region);
super.create();
}
override function update(elapsed:Float)
{
// everyStep();
var oldStep:Int = curStep;
updateCurStep();
updateBeat();
if (oldStep != curStep && curStep >= 0)
stepHit();
super.update(elapsed);
}
private function updateBeat():Void
{
curBeat = Math.floor(curStep / 4);
}
private function updateCurStep():Void
{
var lastChange:BPMChangeEvent = {
stepTime: 0,
songTime: 0,
bpm: 0
}
for (i in 0...Conductor.bpmChangeMap.length)
{
if (Conductor.songPosition >= Conductor.bpmChangeMap[i].songTime)
lastChange = Conductor.bpmChangeMap[i];
}
curStep = lastChange.stepTime + Math.floor((Conductor.songPosition - lastChange.songTime) / Conductor.stepCrochet);
}
public function stepHit():Void
{
if (curStep % 4 == 0)
beatHit();
}
public function beatHit():Void
{
// do literally nothing dumbass
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
package game.state;
import flixel.FlxG;
import openfl.display.Sprite;
import openfl.events.AsyncErrorEvent;
import openfl.events.MouseEvent;
import openfl.events.NetStatusEvent;
import openfl.media.Video;
import openfl.net.NetConnection;
import openfl.net.NetStream;
import game.state.menus.*;
class VideoState extends MusicBeatState
{
var video:Video;
var netStream:NetStream;
private var overlay:Sprite;
public static var seenVideo:Bool = false;
override function create()
{
super.create();
seenVideo = true;
FlxG.save.data.seenVideo = true;
FlxG.save.flush();
if (FlxG.sound.music != null)
FlxG.sound.music.stop();
video = new Video();
FlxG.addChildBelowMouse(video);
var netConnection = new NetConnection();
netConnection.connect(null);
netStream = new NetStream(netConnection);
netStream.client = {onMetaData: client_onMetaData};
netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, netStream_onAsyncError);
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus);
// netStream.addEventListener(NetStatusEvent.NET_STATUS);
netStream.play(Paths.file('music/kickstarterTrailer.mp4'));
overlay = new Sprite();
overlay.graphics.beginFill(0, 0.5);
overlay.graphics.drawRect(0, 0, 1280, 720);
overlay.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown);
overlay.buttonMode = true;
// FlxG.stage.addChild(overlay);
}
override function update(elapsed:Float)
{
if (controls.ACCEPT)
finishVid();
super.update(elapsed);
}
function finishVid():Void
{
netStream.dispose();
FlxG.removeChild(video);
TitleState.initialized = false;
FlxG.switchState(new TitleState());
}
private function client_onMetaData(metaData:Dynamic)
{
video.attachNetStream(netStream);
video.width = video.videoWidth;
video.height = video.videoHeight;
// video.
}
private function netStream_onAsyncError(event:AsyncErrorEvent):Void
{
trace("Error loading video");
}
private function netConnection_onNetStatus(event:NetStatusEvent):Void
{
if (event.info.code == 'NetStream.Play.Complete')
{
finishVid();
}
trace(event.toString());
}
private function overlay_onMouseDown(event:MouseEvent):Void
{
netStream.soundTransform.volume = 0.2;
netStream.soundTransform.pan = -1;
// netStream.play(Paths.file('music/kickstarterTrailer.mp4'));
FlxG.stage.removeChild(overlay);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,345 @@
package game.state.menus;
#if discord_rpc
import game.data.backend.Discord.DiscordClient;
#end
import flash.text.TextField;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.display.FlxGridOverlay;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.math.FlxMath;
import flixel.text.FlxText;
import flixel.tweens.FlxTween;
import flixel.tweens.FlxEase;
import flixel.util.FlxColor;
import lime.utils.Assets;
import game.ui.AtlasMenuList.AtlasMenuItem;
import game.ui.MenuList.MenuTypedList;
import game.ui.*;
import game.ui.gameplay.*;
import game.data.backend.*;
using StringTools;
class FreeplayState extends MusicBeatState
{
var songs:Array<SongMetadata> = [];
// var selector:FlxText;
var curSelected:Int = 0;
var curDifficulty:Int = 1;
var scoreText:FlxText;
var diffText:FlxText;
var lerpScore:Float = 0;
var intendedScore:Int = 0;
var coolColors:Array<Int> = [
0xff9271fd,
0xff9271fd,
0xff223344,
0xFF941653,
0xFFfc96d7,
0xFFa0d1ff,
0xffff78bf,
0xfff6b604
];
private var grpSongs:FlxTypedGroup<Alphabet>;
private var curPlaying:Bool = false;
private var iconArray:Array<HealthIcon> = [];
var bg:FlxSprite;
var scoreBG:FlxSprite;
var difficulty:FlxSprite;
var grpArrows:FlxTypedGroup<FlxSprite>;
override function create()
{
#if discord_rpc
// Updating Discord Rich Presence
DiscordClient.changePresence("In the Menus", null);
#end
var isDebug:Bool = false;
var initSonglist = CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
for (i in 0...initSonglist.length)
{
songs.push(new SongMetadata(initSonglist[i], 1, 'gf'));
}
if (FlxG.sound.music != null)
{
if (!FlxG.sound.music.playing)
FlxG.sound.playMusic(Paths.music('freakyMenu'));
}
if (StoryMenuState.weekUnlocked[2] || isDebug)
addWeek(['Bopeebo', 'Fresh', 'Dadbattle'], 1, ['dad']);
if (StoryMenuState.weekUnlocked[2] || isDebug)
addWeek(['Spookeez', 'South', 'Monster'], 2, ['spooky', 'spooky', 'monster']);
if (StoryMenuState.weekUnlocked[3] || isDebug)
addWeek(['Pico', 'Philly', 'Blammed'], 3, ['pico']);
if (StoryMenuState.weekUnlocked[4] || isDebug)
addWeek(['Satin-Panties', 'High', 'Milf'], 4, ['mom']);
if (StoryMenuState.weekUnlocked[5] || isDebug)
addWeek(['Cocoa', 'Eggnog', 'Winter-Horrorland'], 5, ['parents-christmas', 'parents-christmas', 'monster-christmas']);
if (StoryMenuState.weekUnlocked[6] || isDebug)
addWeek(['Senpai', 'Roses', 'Thorns'], 6, ['senpai', 'senpai', 'spirit']);
if (StoryMenuState.weekUnlocked[7] || isDebug)
addWeek(['Ugh', 'Guns', 'Stress'], 7, ['tankman']);
addSong('Test', 1, 'bf-pixel');
// LOAD MUSIC
// LOAD CHARACTERS
bg = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
add(bg);
var songListBG:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, 150, FlxColor.BLACK);
songListBG.screenCenter(Y);
add(songListBG);
grpSongs = new FlxTypedGroup<Alphabet>();
add(grpSongs);
for (i in 0...songs.length)
{
var songText:Alphabet = new Alphabet(0, (70 * i) + 30, songs[i].songName, true, false);
// songText.isMenuItem = true;
// songText.targetY = i;
songText.screenCenter(XY);
songText.visible = false;
grpSongs.add(songText);
var icon:HealthIcon = new HealthIcon(songs[i].songCharacter);
icon.sprTracker = songText;
// using a FlxGroup is too much fuss!
iconArray.push(icon);
add(icon);
// songText.x += 40;
// DONT PUT X IN THE FIRST PARAMETER OF new ALPHABET() !!
// songText.screenCenter(X);
}
scoreBG = new FlxSprite(0, songListBG.y + 210).makeGraphic(FlxG.width, 100, 0x99000000);
scoreBG.antialiasing = false;
scoreBG.screenCenter(X);
add(scoreBG);
scoreText = new FlxText(0, scoreBG.y + 30, 0, "", 40);
scoreText.setFormat(Paths.font("vcr.ttf"), 40, FlxColor.WHITE, CENTER);
scoreText.screenCenter(X);
scoreText.x -= 140;
diffText = new FlxText(scoreText.x, scoreText.y + 36, 0, "", 24);
diffText.font = scoreText.font;
// add(diffText);
var menuUITex = Paths.getSparrowAtlas('campaign_menu_UI_assets');
difficulty = new FlxSprite(0, scoreBG.y + 140);
difficulty.frames = menuUITex;
difficulty.animation.addByPrefix('easy', 'EASY');
difficulty.animation.addByPrefix('normal', 'NORMAL');
difficulty.animation.addByPrefix('hard', 'HARD');
difficulty.animation.play('easy');
difficulty.screenCenter(X);
difficulty.x += 40;
add(difficulty);
grpArrows = new FlxTypedGroup<FlxSprite>();
add(grpArrows);
var arrowNames:Array<String> = ['left', 'right'];
for (i in 0...arrowNames.length)
{
var xmlEndName:String = (i == 0 ? 'left' : 'right');
var arrow:FlxSprite = new FlxSprite(0, difficulty.y - 10);
arrow.frames = menuUITex;
arrow.animation.addByPrefix('idle', 'arrow $xmlEndName');
arrow.animation.addByPrefix('press', 'arrow push $xmlEndName', 24, false);
arrow.animation.play('idle');
grpArrows.ID = i;
grpArrows.add(arrow);
arrow.x = (i == 0 ? difficulty.x - 180 : difficulty.x + 300);
FlxTween.tween(arrow, {x: (i == 0 ? arrow.x + 10 : arrow.x - 10)}, 1, {ease: FlxEase.sineInOut, type: PINGPONG});
}
add(scoreText);
changeSelection();
changeDiff();
var swag:Alphabet = new Alphabet(1, 0, "swag");
super.create();
}
public function addSong(songName:String, weekNum:Int, songCharacter:String)
{
songs.push(new SongMetadata(songName, weekNum, songCharacter));
}
public function addWeek(songs:Array<String>, weekNum:Int, ?songCharacters:Array<String>)
{
if (songCharacters == null)
songCharacters = ['bf'];
var num:Int = 0;
for (song in songs)
{
addSong(song, weekNum, songCharacters[num]);
if (songCharacters.length != 1)
num++;
}
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (FlxG.sound.music != null)
{
if (FlxG.sound.music.volume < 0.7)
{
FlxG.sound.music.volume += 0.5 * FlxG.elapsed;
}
}
if (FlxG.sound.music != null) Conductor.songPosition = FlxG.sound.music.time;
FlxG.camera.zoom = FlxMath.lerp(1, FlxG.camera.zoom, CoolUtil.boundTo(1 - (elapsed * 4), 0, 1));
lerpScore = CoolUtil.coolLerp(lerpScore, intendedScore, 0.4);
bg.color = FlxColor.interpolate(bg.color, coolColors[songs[curSelected].week % coolColors.length], CoolUtil.camLerpShit(0.045));
scoreText.text = "PERSONAL BEST:" + Math.round(lerpScore);
var upP = controls.UI_UP_P;
var downP = controls.UI_DOWN_P;
var accepted = controls.ACCEPT;
if (upP)
changeSelection(-1);
if (downP)
changeSelection(1);
if (FlxG.mouse.wheel != 0)
changeSelection(-Math.round(FlxG.mouse.wheel / 4));
if (controls.UI_RIGHT)
grpArrows.members[1].animation.play('press');
else
grpArrows.members[1].animation.play('idle');
if (controls.UI_LEFT)
grpArrows.members[0].animation.play('press');
else
grpArrows.members[0].animation.play('idle');
if (controls.UI_LEFT_P) {
changeDiff(-1);
}
if (controls.UI_RIGHT_P) {
changeDiff(1);
}
if (controls.BACK)
{
FlxG.sound.play(Paths.sound('cancelMenu'));
FlxG.switchState(new MainMenuState());
}
if (accepted)
{
var poop:String = Highscore.formatSong(songs[curSelected].songName.toLowerCase(), curDifficulty);
PlayState.SONG = Song.loadFromJson(poop, songs[curSelected].songName.toLowerCase());
PlayState.isStoryMode = false;
PlayState.storyDifficulty = curDifficulty;
PlayState.storyWeek = songs[curSelected].week;
trace('CUR WEEK' + PlayState.storyWeek);
LoadingState.loadAndSwitchState(new PlayState());
}
}
override function beatHit()
{
if (curBeat % 1 == 0) FlxG.camera.zoom += 0.015;
super.beatHit();
}
function changeDiff(change:Int = 0)
{
curDifficulty += change;
if (curDifficulty < 0)
curDifficulty = 2;
if (curDifficulty > 2)
curDifficulty = 0;
intendedScore = Highscore.getScore(songs[curSelected].songName, curDifficulty);
PlayState.storyDifficulty = curDifficulty;
difficulty.offset.x = 0;
switch (curDifficulty) {case 1: difficulty.offset.x = 70; case 0 | 2: difficulty.offset.x = 20;}
difficulty.animation.play(CoolUtil.difficultyString().toLowerCase());
}
function changeSelection(change:Int = 0)
{
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
curSelected += change;
if (curSelected < 0)
curSelected = songs.length - 1;
if (curSelected >= songs.length)
curSelected = 0;
intendedScore = Highscore.getScore(songs[curSelected].songName, curDifficulty);
#if PRELOAD_ALL
var song = Song.loadFromJson(songs[curSelected].songName, songs[curSelected].songName);
FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName), 0);
Conductor.changeBPM(song.bpm);
#end
for (i in 0...iconArray.length) iconArray[i].visible = false;
iconArray[curSelected].visible = true;
for (item in grpSongs.members) item.visible = false;
grpSongs.members[curSelected].visible = true;
}
}
class SongMetadata
{
public var songName:String = "";
public var week:Int = 0;
public var songCharacter:String = "";
public function new(song:String, week:Int, songCharacter:String)
{
this.songName = song;
this.week = week;
this.songCharacter = songCharacter;
}
}

View File

@ -0,0 +1,289 @@
package game.state.menus;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.addons.transition.FlxTransitionableState;
import flixel.effects.FlxFlicker;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.text.FlxText;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import flixel.math.FlxMath;
import lime.app.Application;
import game.state.*;
import game.state.menus.*;
import game.state.subState.*;
import game.state.menus.options.OptionsState;
import game.state.menus.options.PreferencesMenu;
import game.ui.AtlasMenuList;
import game.ui.MenuList;
import game.ui.*;
import game.ui.menu.*;
import game.data.backend.Conductor;
import game.data.backend.SwagCamera;
using StringTools;
#if discord_rpc
import game.data.backend.Discord.DiscordClient;
#end
class MainMenuState extends MusicBeatState
{
// var menuItems:MainMenuList;
var menuItems:FlxTypedGroup<FlxSprite>;
var menuOptions:Array<String> = ['story mode', 'freeplay', 'options'];
var curSelected:Int = 0;
var selected:Bool = false;
var magenta:FlxSprite;
var logo:FlxSprite;
override function create()
{
#if discord_rpc
// Updating Discord Rich Presence
DiscordClient.changePresence("In the Menus", null);
#end
transIn = FlxTransitionableState.defaultTransIn;
transOut = FlxTransitionableState.defaultTransOut;
if (!FlxG.sound.music.playing)
{
FlxG.sound.playMusic(Paths.music('freakyMenu'));
}
persistentUpdate = persistentDraw = true;
var bg:FlxSprite = new FlxSprite(Paths.image('menuBG'));
bg.scrollFactor.x = 0;
bg.scrollFactor.y = 0.17;
bg.setGraphicSize(Std.int(bg.width * 1.2));
bg.updateHitbox();
bg.screenCenter();
bg.antialiasing = true;
add(bg);
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.antialiasing = true;
magenta.color = 0xFFfd719b;
if (PreferencesMenu.preferences.get('flashing-menu')) add(magenta);
// FUCK YOU FNF LOGO
// Actually Kill Yourself
logo = new FlxSprite(0, -130).loadGraphic(Paths.image('logo'));
logo.screenCenter(X);
add(logo);
menuItems = new FlxTypedGroup<FlxSprite>();
add(menuItems);
// This took forever to get the x value right
// the menu options kept having hard sex in front of the fnf logo every time
var menItemTex = Paths.getSparrowAtlas('main_menu');
for (i in 0...menuOptions.length)
{
var menuItem:FlxSprite = new FlxSprite(10 + (i * 500) , FlxG.height / 2 + 100);
menuItem.frames = menItemTex;
menuItem.animation.addByPrefix('idle', menuOptions[i] + ' idle', 24);
menuItem.animation.addByPrefix('selected', menuOptions[i] + ' selected', 24);
menuItem.animation.play('idle');
menuItem.ID = i;
// menuItem.screenCenter(Y);
menuItems.add(menuItem);
menuItem.scale.set(0.7, 0.7);
menuItem.updateHitbox();
if (i == 1) menuItem.y += 130;
if (i == 2) menuItem.x -= 100;
}
changeOption();
var versionShit:FlxText = new FlxText(5, FlxG.height - 32, 0, "FNF v" + Application.current.meta.get('version'), 12);
versionShit.scrollFactor.set();
versionShit.setFormat("VCR OSD Mono", 16, FlxColor.WHITE, LEFT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
add(versionShit);
versionShit.text += '\nZyflixel Engine Dev Build (HEAVY WIP)';
super.create();
}
public function openPrompt(prompt:Prompt, onClose:Void->Void)
{
// menuItems.enabled = false;
prompt.closeCallback = function()
{
// menuItems.enabled = true;
if (onClose != null)
onClose();
}
openSubState(prompt);
}
override function update(elapsed:Float)
{
if (FlxG.sound.music.volume < 0.8) FlxG.sound.music.volume += 0.5 * FlxG.elapsed;
if (FlxG.sound.music != null) Conductor.songPosition = FlxG.sound.music.time;
FlxG.camera.zoom = FlxMath.lerp(1, FlxG.camera.zoom, CoolUtil.boundTo(1 - (elapsed * 4), 0, 1));
logo.scale.x = FlxMath.lerp(0.6, logo.scale.x, CoolUtil.boundTo(1 - (elapsed * 9), 0, 1));
logo.scale.y = FlxMath.lerp(0.6, logo.scale.y, CoolUtil.boundTo(1 - (elapsed * 9), 0, 1));
if (!selected)
{
if (controls.UI_LEFT_P)
{
FlxG.sound.play(Paths.sound('scrollMenu'));
changeOption(-1);
}
else if (controls.UI_RIGHT_P)
{
FlxG.sound.play(Paths.sound('scrollMenu'));
changeOption(1);
}
}
if (controls.BACK)
{
FlxG.sound.play(Paths.sound('cancelMenu'));
FlxG.switchState(new TitleState());
}
if (controls.ACCEPT && !selected)
{
selected = true;
FlxG.sound.play(Paths.sound('confirmMenu'));
FlxFlicker.flicker(magenta, 1.1, 0.15, false, true);
menuItems.forEach(function(spr:FlxSprite)
{
if (curSelected != spr.ID)
{
FlxTween.tween(spr, {alpha: 0}, 0.4, {ease: FlxEase.quadOut,
onComplete: function(twn:FlxTween)
{
spr.kill();
}
});
}
else
{
FlxFlicker.flicker(spr, 1, 0.06, true, false, function(flicker:FlxFlicker)
{
var options:String = menuOptions[curSelected];
switch (options)
{
case 'story mode':
FlxG.switchState(new StoryMenuState());
case 'freeplay':
FlxG.switchState(new FreeplayState());
case 'options':
FlxG.switchState(new OptionsState());
}
});
}
});
}
super.update(elapsed);
}
override function beatHit()
{
if (curBeat % 2 == 0) {
FlxG.camera.zoom += 0.015;
logo.scale.set(0.7, 0.7);
}
super.beatHit();
}
function changeOption(num:Int = 0)
{
curSelected += num;
if (curSelected < 0)
curSelected = menuItems.length - 1;
else if (curSelected >= menuItems.length)
curSelected = 0;
menuItems.forEach(function(item:FlxSprite)
{
item.offset.x = 0;
item.animation.play('idle');
item.updateHitbox();
if (item.ID == curSelected)
{
item.animation.play('selected');
switch (item.ID)
{
case 0: item.offset.x = 100;
case 1: item.offset.x = 130;
case 2: item.offset.x = 130;
}
}
});
}
}
/*private class MainMenuList extends MenuTypedList<MainMenuItem>
{
public var atlas:FlxAtlasFrames;
public function new()
{
atlas = Paths.getSparrowAtlas('main_menu');
super(Vertical);
}
public function createItem(x = 0.0, y = 0.0, name:String, callback, fireInstantly = false)
{
var item = new MainMenuItem(x, y, name, atlas, callback);
item.fireInstantly = fireInstantly;
item.ID = length;
return addItem(name, item);
}
override function destroy()
{
super.destroy();
atlas = null;
}
}
private class MainMenuItem extends AtlasMenuItem
{
public function new(x = 0.0, y = 0.0, name, atlas, callback)
{
super(x, y, name, atlas, callback);
scrollFactor.set();
}
override function changeAnim(anim:String)
{
super.changeAnim(anim);
// position by center
centerOrigin();
offset.copyFrom(origin);
}
}*/

View File

@ -0,0 +1,451 @@
package game.state.menus;
#if discord_rpc
import game.data.backend.Discord.DiscordClient;
#end
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.transition.FlxTransitionableState;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.group.FlxGroup;
import flixel.math.FlxMath;
import flixel.text.FlxText;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import lime.net.curl.CURLCode;
import game.ui.menu.*;
import game.data.backend.Highscore;
import game.data.backend.Song;
using StringTools;
class StoryMenuState extends MusicBeatState
{
var scoreText:FlxText;
var weekData:Array<Dynamic> = [
['Tutorial'],
['Bopeebo', 'Fresh', 'Dadbattle'],
['Spookeez', 'South', "Monster"],
['Pico', 'Philly', "Blammed"],
['Satin-Panties', "High", "Milf"],
['Cocoa', 'Eggnog', 'Winter-Horrorland'],
['Senpai', 'Roses', 'Thorns'],
['Ugh', 'Guns', 'Stress']
];
var curDifficulty:Int = 1;
public static var weekUnlocked:Array<Bool> = [true, true, true, true, true, true, true, true];
var weekCharacters:Array<Dynamic> = [
['dad', 'bf', 'gf'],
['dad', 'bf', 'gf'],
['spooky', 'bf', 'gf'],
['pico', 'bf', 'gf'],
['mom', 'bf', 'gf'],
['parents-christmas', 'bf', 'gf'],
['senpai', 'bf', 'gf'],
['tankman', 'bf', 'gf']
];
var weekNames:Array<String> = [
"",
"Daddy Dearest",
"Spooky Month",
"PICO",
"MOMMY MUST MURDER",
"RED SNOW",
"hating simulator ft. moawling",
"TANKMAN"
];
var txtWeekTitle:FlxText;
var curWeek:Int = 0;
var txtTracklist:FlxText;
var grpWeekText:FlxTypedGroup<MenuItem>;
var grpWeekCharacters:FlxTypedGroup<MenuCharacter>;
var grpLocks:FlxTypedGroup<FlxSprite>;
var difficultySelectors:FlxGroup;
var sprDifficulty:FlxSprite;
var leftArrow:FlxSprite;
var rightArrow:FlxSprite;
override function create()
{
transIn = FlxTransitionableState.defaultTransIn;
transOut = FlxTransitionableState.defaultTransOut;
if (FlxG.sound.music != null)
{
if (!FlxG.sound.music.playing)
FlxG.sound.playMusic(Paths.music('freakyMenu'));
}
persistentUpdate = persistentDraw = true;
scoreText = new FlxText(10, 10, 0, "SCORE: 49324858", 36);
scoreText.setFormat("VCR OSD Mono", 32);
txtWeekTitle = new FlxText(FlxG.width * 0.7, 10, 0, "", 32);
txtWeekTitle.setFormat("VCR OSD Mono", 32, FlxColor.WHITE, RIGHT);
txtWeekTitle.alpha = 0.7;
var rankText:FlxText = new FlxText(0, 10);
rankText.text = 'RANK: GREAT';
rankText.setFormat(Paths.font("vcr.ttf"), 32);
rankText.size = scoreText.size;
rankText.screenCenter(X);
var ui_tex = Paths.getSparrowAtlas('campaign_menu_UI_assets');
var yellowBG:FlxSprite = new FlxSprite(0, 56).makeGraphic(FlxG.width, 400, 0xFFF9CF51);
grpWeekText = new FlxTypedGroup<MenuItem>();
add(grpWeekText);
var blackBarThingie:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, 56, FlxColor.BLACK);
add(blackBarThingie);
grpWeekCharacters = new FlxTypedGroup<MenuCharacter>();
grpLocks = new FlxTypedGroup<FlxSprite>();
add(grpLocks);
trace("Line 70");
#if discord_rpc
// Updating Discord Rich Presence
DiscordClient.changePresence("In the Menus", null);
#end
for (i in 0...weekData.length)
{
var weekThing:MenuItem = new MenuItem(0, yellowBG.y + yellowBG.height + 10, i);
weekThing.y += ((weekThing.height + 20) * i);
weekThing.targetY = i;
grpWeekText.add(weekThing);
weekThing.screenCenter(X);
weekThing.antialiasing = true;
// weekThing.updateHitbox();
// Needs an offset thingie
if (!weekUnlocked[i])
{
var lock:FlxSprite = new FlxSprite(weekThing.width + 10 + weekThing.x);
lock.frames = ui_tex;
lock.animation.addByPrefix('lock', 'lock');
lock.animation.play('lock');
lock.ID = i;
lock.antialiasing = true;
grpLocks.add(lock);
}
}
trace("Line 96");
for (char in 0...3)
{
var weekCharacterThing:MenuCharacter = new MenuCharacter((FlxG.width * 0.25) * (1 + char) - 150, weekCharacters[curWeek][char]);
weekCharacterThing.y += 70;
weekCharacterThing.antialiasing = true;
switch (weekCharacterThing.character)
{
case 'dad':
weekCharacterThing.setGraphicSize(Std.int(weekCharacterThing.width * 0.5));
weekCharacterThing.updateHitbox();
case 'bf':
weekCharacterThing.setGraphicSize(Std.int(weekCharacterThing.width * 0.9));
weekCharacterThing.updateHitbox();
weekCharacterThing.x -= 80;
case 'gf':
weekCharacterThing.setGraphicSize(Std.int(weekCharacterThing.width * 0.5));
weekCharacterThing.updateHitbox();
case 'pico':
weekCharacterThing.flipX = true;
case 'parents-christmas':
weekCharacterThing.setGraphicSize(Std.int(weekCharacterThing.width * 0.9));
weekCharacterThing.updateHitbox();
}
grpWeekCharacters.add(weekCharacterThing);
}
difficultySelectors = new FlxGroup();
add(difficultySelectors);
trace("Line 124");
leftArrow = new FlxSprite(grpWeekText.members[0].x + grpWeekText.members[0].width + 10, grpWeekText.members[0].y + 10);
leftArrow.frames = ui_tex;
leftArrow.animation.addByPrefix('idle', "arrow left");
leftArrow.animation.addByPrefix('press', "arrow push left");
leftArrow.animation.play('idle');
difficultySelectors.add(leftArrow);
sprDifficulty = new FlxSprite(leftArrow.x + 130, leftArrow.y);
sprDifficulty.frames = ui_tex;
sprDifficulty.animation.addByPrefix('easy', 'EASY');
sprDifficulty.animation.addByPrefix('normal', 'NORMAL');
sprDifficulty.animation.addByPrefix('hard', 'HARD');
sprDifficulty.animation.play('easy');
changeDifficulty();
difficultySelectors.add(sprDifficulty);
rightArrow = new FlxSprite(sprDifficulty.x + sprDifficulty.width + 50, leftArrow.y);
rightArrow.frames = ui_tex;
rightArrow.animation.addByPrefix('idle', 'arrow right');
rightArrow.animation.addByPrefix('press', "arrow push right", 24, false);
rightArrow.animation.play('idle');
difficultySelectors.add(rightArrow);
trace("Line 150");
add(yellowBG);
add(grpWeekCharacters);
txtTracklist = new FlxText(FlxG.width * 0.05, yellowBG.x + yellowBG.height + 100, 0, "Tracks", 32);
txtTracklist.alignment = CENTER;
txtTracklist.font = rankText.font;
txtTracklist.color = 0xFFe55777;
add(txtTracklist);
// add(rankText);
add(scoreText);
add(txtWeekTitle);
updateText();
trace("Line 165");
super.create();
}
override function update(elapsed:Float)
{
// scoreText.setFormat('VCR OSD Mono', 32);
lerpScore = CoolUtil.coolLerp(lerpScore, intendedScore, 0.5);
scoreText.text = "WEEK SCORE:" + Math.round(lerpScore);
txtWeekTitle.text = weekNames[curWeek].toUpperCase();
txtWeekTitle.x = FlxG.width - (txtWeekTitle.width + 10);
// FlxG.watch.addQuick('font', scoreText.font);
difficultySelectors.visible = weekUnlocked[curWeek];
grpLocks.forEach(function(lock:FlxSprite)
{
lock.y = grpWeekText.members[lock.ID].y;
});
if (!movedBack)
{
if (!selectedWeek)
{
if (controls.UI_UP_P)
{
changeWeek(-1);
}
if (controls.UI_DOWN_P)
{
changeWeek(1);
}
if (controls.UI_RIGHT)
rightArrow.animation.play('press')
else
rightArrow.animation.play('idle');
if (controls.UI_LEFT)
leftArrow.animation.play('press');
else
leftArrow.animation.play('idle');
if (controls.UI_RIGHT_P)
changeDifficulty(1);
if (controls.UI_LEFT_P)
changeDifficulty(-1);
}
if (controls.ACCEPT)
{
selectWeek();
}
}
if (controls.BACK && !movedBack && !selectedWeek)
{
FlxG.sound.play(Paths.sound('cancelMenu'));
movedBack = true;
FlxG.switchState(new MainMenuState());
}
super.update(elapsed);
}
var movedBack:Bool = false;
var selectedWeek:Bool = false;
var stopspamming:Bool = false;
function selectWeek()
{
if (weekUnlocked[curWeek])
{
if (stopspamming == false)
{
FlxG.sound.play(Paths.sound('confirmMenu'));
grpWeekText.members[curWeek].startFlashing();
grpWeekCharacters.members[1].animation.play('bfConfirm');
stopspamming = true;
}
PlayState.storyPlaylist = weekData[curWeek];
PlayState.isStoryMode = true;
selectedWeek = true;
var diffic = "";
switch (curDifficulty)
{
case 0:
diffic = '-easy';
case 2:
diffic = '-hard';
}
PlayState.storyDifficulty = curDifficulty;
PlayState.SONG = Song.loadFromJson(PlayState.storyPlaylist[0].toLowerCase() + diffic, PlayState.storyPlaylist[0].toLowerCase());
PlayState.storyWeek = curWeek;
PlayState.campaignScore = 0;
new FlxTimer().start(1, function(tmr:FlxTimer)
{
LoadingState.loadAndSwitchState(new PlayState(), true);
});
}
}
function changeDifficulty(change:Int = 0):Void
{
curDifficulty += change;
if (curDifficulty < 0)
curDifficulty = 2;
if (curDifficulty > 2)
curDifficulty = 0;
sprDifficulty.offset.x = 0;
switch (curDifficulty)
{
case 0:
sprDifficulty.animation.play('easy');
sprDifficulty.offset.x = 20;
case 1:
sprDifficulty.animation.play('normal');
sprDifficulty.offset.x = 70;
case 2:
sprDifficulty.animation.play('hard');
sprDifficulty.offset.x = 20;
}
sprDifficulty.alpha = 0;
// USING THESE WEIRD VALUES SO THAT IT DOESNT FLOAT UP
sprDifficulty.y = leftArrow.y - 15;
intendedScore = Highscore.getWeekScore(curWeek, curDifficulty);
FlxTween.tween(sprDifficulty, {y: leftArrow.y + 15, alpha: 1}, 0.07);
}
var lerpScore:Float = 0;
var intendedScore:Int = 0;
function changeWeek(change:Int = 0):Void
{
curWeek += change;
if (curWeek >= weekData.length)
curWeek = 0;
if (curWeek < 0)
curWeek = weekData.length - 1;
var bullShit:Int = 0;
for (item in grpWeekText.members)
{
item.targetY = bullShit - curWeek;
if (item.targetY == Std.int(0) && weekUnlocked[curWeek])
item.alpha = 1;
else
item.alpha = 0.6;
bullShit++;
}
FlxG.sound.play(Paths.sound('scrollMenu'));
updateText();
}
function updateText()
{
grpWeekCharacters.members[0].animation.play(weekCharacters[curWeek][0]);
grpWeekCharacters.members[1].animation.play(weekCharacters[curWeek][1]);
grpWeekCharacters.members[2].animation.play(weekCharacters[curWeek][2]);
txtTracklist.text = "Tracks\n";
switch (grpWeekCharacters.members[0].animation.curAnim.name)
{
case 'parents-christmas':
grpWeekCharacters.members[0].offset.set(200, 200);
grpWeekCharacters.members[0].setGraphicSize(Std.int(grpWeekCharacters.members[0].width * 0.99));
case 'senpai':
grpWeekCharacters.members[0].offset.set(130, 0);
grpWeekCharacters.members[0].setGraphicSize(Std.int(grpWeekCharacters.members[0].width * 1.4));
case 'mom':
grpWeekCharacters.members[0].offset.set(100, 200);
grpWeekCharacters.members[0].setGraphicSize(Std.int(grpWeekCharacters.members[0].width * 1));
case 'dad':
grpWeekCharacters.members[0].offset.set(120, 200);
grpWeekCharacters.members[0].setGraphicSize(Std.int(grpWeekCharacters.members[0].width * 1));
case 'tankman':
grpWeekCharacters.members[0].offset.set(60, -20);
grpWeekCharacters.members[0].setGraphicSize(Std.int(grpWeekCharacters.members[0].width * 1));
default:
grpWeekCharacters.members[0].offset.set(100, 100);
grpWeekCharacters.members[0].setGraphicSize(Std.int(grpWeekCharacters.members[0].width * 1));
// grpWeekCharacters.members[0].updateHitbox();
}
var stringThing:Array<String> = weekData[curWeek];
for (i in stringThing)
{
txtTracklist.text += "\n" + i;
}
txtTracklist.text = txtTracklist.text.toUpperCase();
txtTracklist.screenCenter(X);
txtTracklist.x -= FlxG.width * 0.35;
intendedScore = Highscore.getWeekScore(curWeek, curDifficulty);
}
}

View File

@ -0,0 +1,543 @@
package game.state.menus;
import flixel.FlxG;
import flixel.FlxGame;
import flixel.FlxSprite;
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.transition.TransitionData;
import flixel.graphics.FlxGraphic;
import flixel.group.FlxGroup;
import flixel.input.gamepad.FlxGamepad;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.math.FlxMath;
import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.system.FlxAssets;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import lime.app.Application;
import lime.ui.Window;
import openfl.Assets;
import openfl.display.Sprite;
import openfl.events.AsyncErrorEvent;
import openfl.events.AsyncErrorEvent;
import openfl.events.Event;
import openfl.events.MouseEvent;
import openfl.events.NetStatusEvent;
import openfl.media.Video;
import openfl.net.NetConnection;
import openfl.net.NetStream;
import game.objects.shaders.BuildingShaders.BuildingShader;
import game.objects.shaders.BuildingShaders;
import game.objects.shaders.ColorSwap;
import game.state.menus.options.*;
import game.state.*;
import game.state.subState.*;
import game.state.menus.*;
import game.state.charting.*;
import game.objects.cutscene.*;
import game.data.*;
import game.data.backend.*;
import game.ui.*;
using StringTools;
#if discord_rpc
import game.data.backend.Discord.DiscordClient;
#end
#if desktop
import sys.FileSystem;
import sys.io.File;
import sys.thread.Thread;
#end
class TitleState extends MusicBeatState
{
public static var initialized:Bool = false;
var startedIntro:Bool;
var blackScreen:FlxSprite;
var credGroup:FlxGroup;
var credTextShit:Alphabet;
var textGroup:FlxGroup;
var ngSpr:FlxSprite;
var curWacky:Array<String> = [];
var wackyImage:FlxSprite;
var lastBeat:Int = 0;
var swagShader:ColorSwap;
var alphaShader:BuildingShaders;
var thingie:FlxSprite;
var video:Video;
var netStream:NetStream;
private var overlay:Sprite;
// Note: If you are adding songs to the game, make sure you add the songs here
var gameSongs:Array<String> = [
'test', 'tutorial', 'bopeebo', 'fresh', 'dadbattle', 'spookeez', 'south', 'monster',
'pico', 'philly', 'blammed', 'satin-panties', 'high', 'milf', 'cocoa', 'eggnog', 'winter-horrorland',
'senpai', 'roses', 'thorns', 'ugh', 'guns', 'stress'];
override public function create():Void
{
#if polymod
// polymod.Polymod.init({modRoot: "mods", dirs: ['introMod'], framework: OPENFL});
// FlxG.bitmap.clearCache();
#end
// A Cache State Will Be Added Soon but this is just so that
// the game doesn't lag when you go up or down an option in freeplay
// when hovering over it for the first time
cacheSongs();
startedIntro = false;
FlxG.game.focusLostFramerate = 60;
swagShader = new ColorSwap();
alphaShader = new BuildingShaders();
FlxG.sound.muteKeys = [ZERO];
curWacky = FlxG.random.getObject(getIntroTextShit());
// DEBUG BULLSHIT
super.create();
FlxG.save.bind('funkin', 'ninjamuffin99');
PreferencesMenu.initPrefs();
PlayerSettings.init();
Highscore.load();
#if newgrounds
// NGio.init();
#end
if (FlxG.save.data.weekUnlocked != null)
{
// FIX LATER!!!
// WEEK UNLOCK PROGRESSION!!
// StoryMenuState.weekUnlocked = FlxG.save.data.weekUnlocked;
if (StoryMenuState.weekUnlocked.length < 4)
StoryMenuState.weekUnlocked.insert(0, true);
// QUICK PATCH OOPS!
if (!StoryMenuState.weekUnlocked[0])
StoryMenuState.weekUnlocked[0] = true;
}
if (FlxG.save.data.seenVideo != null)
{
VideoState.seenVideo = FlxG.save.data.seenVideo;
}
#if FREEPLAY
FlxG.switchState(new FreeplayState());
#elseif ANIMATE
FlxG.switchState(new CutsceneAnimTestState());
#elseif CHARTING
FlxG.switchState(new ChartingState());
#else
new FlxTimer().start(1, function(tmr:FlxTimer)
{
startIntro();
});
#end
#if discord_rpc
DiscordClient.initialize();
Application.current.onExit.add(function(exitCode)
{
DiscordClient.shutdown();
});
#end
}
private function client_onMetaData(metaData:Dynamic)
{
video.attachNetStream(netStream);
video.width = video.videoWidth;
video.height = video.videoHeight;
// video.
}
private function netStream_onAsyncError(event:AsyncErrorEvent):Void
{
trace("Error loading video");
}
private function netConnection_onNetStatus(event:NetStatusEvent):Void
{
if (event.info.code == 'NetStream.Play.Complete')
{
// netStream.dispose();
// FlxG.stage.removeChild(video);
startIntro();
}
trace(event.toString());
}
private function overlay_onMouseDown(event:MouseEvent):Void
{
netStream.soundTransform.volume = 0.2;
netStream.soundTransform.pan = -1;
// netStream.play(Paths.file('music/kickstarterTrailer.mp4'));
FlxG.stage.removeChild(overlay);
}
var logoBl:FlxSprite;
var gfDance:FlxSprite;
var danceLeft:Bool = false;
var titleText:FlxSprite;
function startIntro()
{
if (!initialized)
{
var diamond:FlxGraphic = FlxGraphic.fromClass(GraphicTransTileDiamond);
diamond.persist = true;
diamond.destroyOnNoUse = false;
FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), {asset: diamond, width: 32, height: 32},
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1),
{asset: diamond, width: 32, height: 32}, new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
}
if (FlxG.sound.music == null || !FlxG.sound.music.playing)
{
FlxG.sound.playMusic(Paths.music('freakyMenu'), 0);
FlxG.sound.music.fadeIn(4, 0, 0.7);
}
Conductor.changeBPM(102);
persistentUpdate = true;
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
// bg.antialiasing = true;
// bg.setGraphicSize(Std.int(bg.width * 0.6));
// bg.updateHitbox();
add(bg);
logoBl = new FlxSprite(-150, -100);
logoBl.frames = Paths.getSparrowAtlas('logoBumpin');
logoBl.antialiasing = true;
logoBl.animation.addByPrefix('bump', 'logo bumpin', 24);
logoBl.animation.play('bump');
logoBl.updateHitbox();
logoBl.shader = swagShader.shader;
// logoBl.shader = alphaShader.shader;
// trace();
// logoBl.screenCenter();
// logoBl.color = FlxColor.BLACK;
gfDance = new FlxSprite(FlxG.width * 0.4, FlxG.height * 0.07);
gfDance.frames = Paths.getSparrowAtlas('gfDanceTitle');
gfDance.animation.addByIndices('danceLeft', 'gfDance', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
gfDance.animation.addByIndices('danceRight', 'gfDance', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
gfDance.antialiasing = true;
add(gfDance);
gfDance.shader = swagShader.shader;
add(logoBl);
titleText = new FlxSprite(100, FlxG.height * 0.8);
titleText.frames = Paths.getSparrowAtlas('titleEnter');
titleText.animation.addByPrefix('idle', "Press Enter to Begin", 24);
titleText.animation.addByPrefix('press', "ENTER PRESSED", 24);
titleText.antialiasing = true;
titleText.animation.play('idle');
titleText.updateHitbox();
// titleText.screenCenter(X);
add(titleText);
var logo:FlxSprite = new FlxSprite().loadGraphic(Paths.image('logo'));
logo.screenCenter();
logo.antialiasing = true;
// add(logo);
// FlxTween.tween(logoBl, {y: logoBl.y + 50}, 0.6, {ease: FlxEase.quadInOut, type: PINGPONG});
// FlxTween.tween(logo, {y: logoBl.y + 50}, 0.6, {ease: FlxEase.quadInOut, type: PINGPONG, startDelay: 0.1});
credGroup = new FlxGroup();
add(credGroup);
textGroup = new FlxGroup();
blackScreen = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
credGroup.add(blackScreen);
// var atlasBullShit:FlxSprite = new FlxSprite();
// atlasBullShit.frames = CoolUtil.fromAnimate(Paths.image('money'), Paths.file('images/money.json'));
// credGroup.add(atlasBullShit);
credTextShit = new Alphabet(0, 0, "ninjamuffin99\nPhantomArcade\nkawaisprite\nevilsk8er", true);
credTextShit.screenCenter();
// credTextShit.alignment = CENTER;
credTextShit.visible = false;
ngSpr = new FlxSprite(0, FlxG.height * 0.52).loadGraphic(Paths.image('newgrounds_logo'));
add(ngSpr);
ngSpr.visible = false;
ngSpr.setGraphicSize(Std.int(ngSpr.width * 0.8));
ngSpr.updateHitbox();
ngSpr.screenCenter(X);
ngSpr.antialiasing = true;
FlxTween.tween(credTextShit, {y: credTextShit.y + 20}, 2.9, {ease: FlxEase.quadInOut, type: PINGPONG});
FlxG.mouse.visible = false;
if (initialized)
skipIntro();
else
initialized = true;
if (FlxG.sound.music != null)
FlxG.sound.music.onComplete = function() FlxG.switchState(new VideoState());
startedIntro = true;
// credGroup.add(credTextShit);
}
function getIntroTextShit():Array<Array<String>>
{
var fullText:String = Assets.getText(Paths.txt('introText'));
var firstArray:Array<String> = fullText.split('\n');
var swagGoodArray:Array<Array<String>> = [];
for (i in firstArray)
{
swagGoodArray.push(i.split('--'));
}
return swagGoodArray;
}
var transitioning:Bool = false;
override function update(elapsed:Float)
{
#if debug
if (FlxG.keys.justPressed.EIGHT)
FlxG.switchState(new CutsceneAnimTestState());
#end
if (FlxG.sound.music != null) Conductor.songPosition = FlxG.sound.music.time;
if (FlxG.keys.justPressed.F) FlxG.fullscreen = !FlxG.fullscreen;
FlxG.camera.zoom = FlxMath.lerp(1, FlxG.camera.zoom, CoolUtil.boundTo(1 - (elapsed * 4), 0, 1));
var pressedEnter:Bool = FlxG.keys.justPressed.ENTER;
#if mobile
for (touch in FlxG.touches.list)
{
if (touch.justPressed)
pressedEnter = true;
}
#end
var gamepad:FlxGamepad = FlxG.gamepads.lastActive;
if (gamepad != null)
{
if (gamepad.justPressed.START)
pressedEnter = true;
#if switch
if (gamepad.justPressed.B)
pressedEnter = true;
#end
}
if (pressedEnter && !transitioning && skippedIntro)
{
if (FlxG.sound.music != null)
FlxG.sound.music.onComplete = null;
// netStream.play(Paths.file('music/kickstarterTrailer.mp4'));
// NGio.unlockMedal(60960);
// If it's Friday according to da clock
if (Date.now().getDay() == 5)
// NGio.unlockMedal(61034);
titleText.animation.play('press');
FlxG.camera.flash(FlxColor.WHITE, 1);
FlxG.sound.play(Paths.sound('confirmMenu'), 0.7);
transitioning = true;
// FlxG.sound.music.stop();
FlxG.switchState(new MainMenuState());
// FlxG.sound.play(Paths.music('titleShoot'), 0.7);
}
if (pressedEnter && !skippedIntro && initialized) skipIntro();
if (controls.UI_LEFT) swagShader.update(-elapsed * 0.1);
if (controls.UI_RIGHT) swagShader.update(elapsed * 0.1);
super.update(elapsed);
}
function createCoolText(textArray:Array<String>)
{
for (i in 0...textArray.length)
{
var money:Alphabet = new Alphabet(0, 0, textArray[i], true, false);
money.screenCenter(X);
money.y += (i * 60) + 200;
credGroup.add(money);
textGroup.add(money);
}
}
function addMoreText(text:String)
{
var coolText:Alphabet = new Alphabet(0, 0, text, true, false);
coolText.screenCenter(X);
coolText.y += (textGroup.length * 60) + 200;
credGroup.add(coolText);
textGroup.add(coolText);
}
function deleteCoolText()
{
while (textGroup.members.length > 0)
{
credGroup.remove(textGroup.members[0], true);
textGroup.remove(textGroup.members[0], true);
}
}
var isRainbow:Bool = false;
override function beatHit()
{
super.beatHit();
if (!startedIntro)
return;
if (curBeat % 1 == 0) FlxG.camera.zoom += 0.015;
if (skippedIntro)
{
logoBl.animation.play('bump', true);
danceLeft = !danceLeft;
var anim:String = danceLeft ? 'danceRight' : 'danceLeft';
gfDance.animation.play(anim);
}
else
{
FlxG.log.add(curBeat);
// if the user is draggin the window some beats will
// be missed so this is just to compensate
if (curBeat > lastBeat)
{
for (i in lastBeat...curBeat)
{
switch (i + 1)
{
case 1:
createCoolText(['ninjamuffin99', 'phantomArcade', 'kawaisprite', 'evilsk8er']);
// credTextShit.visible = true;
case 3:
addMoreText('present');
// credTextShit.text += '\npresent...';
// credTextShit.addText();
case 4:
deleteCoolText();
// credTextShit.visible = false;
// credTextShit.text = 'In association \nwith';
// credTextShit.screenCenter();
case 5:
createCoolText(['In association', 'with']);
case 7:
addMoreText('newgrounds');
ngSpr.visible = true;
// credTextShit.text += '\nNewgrounds';
case 8:
deleteCoolText();
ngSpr.visible = false;
// credTextShit.visible = false;
// credTextShit.text = 'Shoutouts Tom Fulp';
// credTextShit.screenCenter();
case 9:
createCoolText([curWacky[0]]);
// credTextShit.visible = true;
case 11:
addMoreText(curWacky[1]);
// credTextShit.text += '\nlmao';
case 12:
deleteCoolText();
// credTextShit.visible = false;
// credTextShit.text = "Friday";
// credTextShit.screenCenter();
case 13:
addMoreText('Friday');
// credTextShit.visible = true;
case 14:
addMoreText('Night');
// credTextShit.text += '\nNight';
case 15:
addMoreText('Funkin'); // credTextShit.text += '\nFunkin';
case 16:
skipIntro();
}
}
}
lastBeat = curBeat;
}
}
var skippedIntro:Bool = false;
function skipIntro():Void
{
if (!skippedIntro)
{
remove(ngSpr);
FlxG.camera.flash(FlxColor.WHITE, 4);
remove(credGroup);
skippedIntro = true;
}
}
function cacheSongs()
{
for (songs in gameSongs)
{
if (Assets.exists(Paths.inst(songs)))
{
FlxG.sound.cache(Paths.inst(songs));
}
}
}
}

View File

@ -0,0 +1,6 @@
package game.state.menus.options;
class Options
{
public static var masterVolume:Float = 1;
}

View File

@ -0,0 +1,288 @@
package game.state.menus.options;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxSubState;
import flixel.addons.transition.FlxTransitionableState;
import flixel.group.FlxGroup;
import flixel.util.FlxSignal;
import game.state.subState.*;
import game.state.menus.options.controls.*;
import game.data.PlayerSettings;
import game.ui.TextMenuList;
import game.ui.ModMenu;
// typedef OptionsState = OptionsMenu_old;
// class OptionsState_new extends MusicBeatState
class OptionsState extends MusicBeatState
{
var pages = new Map<PageName, Page>();
var currentName:PageName = Options;
var currentPage(get, never):Page;
inline function get_currentPage()
return pages[currentName];
override function create()
{
var menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
menuBG.color = 0xFFea71fd;
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
menuBG.updateHitbox();
menuBG.screenCenter();
menuBG.scrollFactor.set(0, 0);
add(menuBG);
var options = addPage(Options, new OptionsMenu(false));
var preferences = addPage(Preferences, new PreferencesMenu());
var controls = addPage(Controls, new ControlsMenu());
// var colors = addPage(Colors, new ColorsMenu());
#if cpp
var mods = addPage(Mods, new ModMenu());
#end
if (options.hasMultipleOptions())
{
options.onExit.add(exitToMainMenu);
controls.onExit.add(switchPage.bind(Options));
// colors.onExit.add(switchPage.bind(Options));
preferences.onExit.add(switchPage.bind(Options));
#if cpp
mods.onExit.add(switchPage.bind(Options));
#end
}
else
{
// No need to show Options page
controls.onExit.add(exitToMainMenu);
setPage(Controls);
}
// disable for intro transition
currentPage.enabled = false;
super.create();
}
function addPage<T:Page>(name:PageName, page:T)
{
page.onSwitch.add(switchPage);
pages[name] = page;
add(page);
page.exists = currentName == name;
return page;
}
function setPage(name:PageName)
{
if (pages.exists(currentName))
currentPage.exists = false;
currentName = name;
if (pages.exists(currentName))
currentPage.exists = true;
}
override function finishTransIn()
{
super.finishTransIn();
currentPage.enabled = true;
}
function switchPage(name:PageName)
{
// Todo animate?
setPage(name);
}
function exitToMainMenu()
{
currentPage.enabled = false;
// Todo animate?
FlxG.switchState(new MainMenuState());
}
}
class Page extends FlxGroup
{
public var onSwitch(default, null) = new FlxTypedSignal<PageName->Void>();
public var onExit(default, null) = new FlxSignal();
public var enabled(default, set) = true;
public var canExit = true;
var controls(get, never):Controls;
inline function get_controls()
return PlayerSettings.player1.controls;
var subState:FlxSubState;
inline function switchPage(name:PageName)
{
onSwitch.dispatch(name);
}
inline function exit()
{
onExit.dispatch();
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (enabled)
updateEnabled(elapsed);
}
function updateEnabled(elapsed:Float)
{
if (canExit && controls.BACK)
{
FlxG.sound.play(Paths.sound('cancelMenu'));
exit();
}
}
function set_enabled(value:Bool)
{
return this.enabled = value;
}
function openPrompt(prompt:Prompt, onClose:Void->Void)
{
enabled = false;
prompt.closeCallback = function()
{
enabled = true;
if (onClose != null)
onClose();
}
FlxG.state.openSubState(prompt);
}
override function destroy()
{
super.destroy();
onSwitch.removeAll();
}
}
class OptionsMenu extends Page
{
var items:TextMenuList;
public function new(showDonate:Bool)
{
super();
add(items = new TextMenuList());
createItem('preferences', function() switchPage(Preferences));
createItem("controls", function() switchPage(Controls));
// createItem('colors', function() switchPage(Colors));
#if cpp
createItem('mods', function() switchPage(Mods));
#end
#if CAN_OPEN_LINKS
if (showDonate)
{
var hasPopupBlocker = #if web true #else false #end;
createItem('donate', selectDonate, hasPopupBlocker);
}
#end
#if newgrounds
/*if (NGio.isLoggedIn)
createItem("logout", selectLogout);
else
createItem("login", selectLogin);*/
#end
createItem("exit", exit);
}
function createItem(name:String, callback:Void->Void, fireInstantly = false)
{
var item = items.createItem(0, 100 + items.length * 100, name, Bold, callback);
item.fireInstantly = fireInstantly;
item.screenCenter(X);
return item;
}
override function set_enabled(value:Bool)
{
items.enabled = value;
return super.set_enabled(value);
}
/**
* True if this page has multiple options, excluding the exit option.
* If false, there's no reason to ever show this page.
*/
public function hasMultipleOptions():Bool
{
return items.length > 2;
}
#if CAN_OPEN_LINKS
function selectDonate()
{
#if linux
Sys.command('/usr/bin/xdg-open', ["https://ninja-muffin24.itch.io/funkin", "&"]);
#else
FlxG.openURL('https://ninja-muffin24.itch.io/funkin');
#end
}
#end
#if newgrounds
/*function selectLogin()
{
openNgPrompt(NgPrompt.showLogin());
}
function selectLogout()
{
openNgPrompt(NgPrompt.showLogout());
}
public function openNgPrompt(prompt:Prompt, ?onClose:Void->Void)
{
var onPromptClose = checkLoginStatus;
if (onClose != null)
{
onPromptClose = function()
{
checkLoginStatus();
onClose();
}
}
openPrompt(prompt, onPromptClose);
}
function checkLoginStatus()
{
// this shit don't work!! wtf!!!!
var prevLoggedIn = items.has("logout");
if (prevLoggedIn && !NGio.isLoggedIn)
items.resetItem("logout", "login", selectLogin);
else if (!prevLoggedIn && NGio.isLoggedIn)
items.resetItem("login", "logout", selectLogout);
}*/
#end
}
enum PageName
{
Options;
Controls;
Colors;
Mods;
Preferences;
}

View File

@ -0,0 +1,221 @@
package game.state.menus.options;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.group.FlxGroup;
import flixel.util.FlxColor;
import game.ui.AtlasText.AtlasFont;
import game.ui.TextMenuList;
import game.ui.TextMenuList.TextMenuItem;
import game.data.backend.SwagCamera;
import game.state.menus.options.*;
class PreferencesMenu extends OptionsState.Page
{
public static var preferences:Map<String, Dynamic> = new Map();
var items:TextMenuList;
var checkboxes:Array<CheckboxThingie> = [];
var menuCamera:FlxCamera;
var camFollow:FlxObject;
public function new()
{
super();
menuCamera = new SwagCamera();
FlxG.cameras.add(menuCamera, false);
menuCamera.bgColor = 0x0;
camera = menuCamera;
add(items = new TextMenuList());
createPrefItem('naughtyness', 'censor-naughty', true);
createPrefItem('downscroll', 'downscroll', false);
createPrefItem('flashing menu', 'flashing-menu', true);
createPrefItem('Camera Zooming on Beat', 'camera-zoom', true);
createPrefItem('FPS Counter', 'fps-counter', true);
createPrefItem('Auto Pause', 'auto-pause', false);
camFollow = new FlxObject(FlxG.width / 2, 0, 140, 70);
if (items != null)
camFollow.y = items.selectedItem.y;
menuCamera.follow(camFollow, null, 0.06);
var margin = 160;
menuCamera.deadzone.set(0, margin, menuCamera.width, 40);
menuCamera.minScrollY = 0;
items.onChange.add(function(selected)
{
camFollow.y = selected.y;
});
}
public static function getPref(pref:String):Dynamic
{
return preferences.get(pref);
}
// easy shorthand?
public static function setPref(pref:String, value:Dynamic):Void
{
preferences.set(pref, value);
}
public static function initPrefs():Void
{
preferenceCheck('censor-naughty', true);
preferenceCheck('downscroll', false);
preferenceCheck('flashing-menu', true);
preferenceCheck('camera-zoom', true);
preferenceCheck('fps-counter', true);
preferenceCheck('auto-pause', false);
preferenceCheck('master-volume', 1);
#if muted
setPref('master-volume', 0);
FlxG.sound.muted = true;
#end
if (!getPref('fps-counter'))
FlxG.stage.removeChild(Main.fpsCounter);
FlxG.autoPause = getPref('auto-pause');
}
private function createPrefItem(prefName:String, prefString:String, prefValue:Dynamic):Void
{
items.createItem(120, (120 * items.length) + 30, prefName, AtlasFont.Bold, function()
{
preferenceCheck(prefString, prefValue);
switch (Type.typeof(prefValue).getName())
{
case 'TBool':
prefToggle(prefString);
default:
trace('swag');
}
});
switch (Type.typeof(prefValue).getName())
{
case 'TBool':
createCheckbox(prefString);
default:
trace('swag');
}
trace(Type.typeof(prefValue).getName());
}
function createCheckbox(prefString:String)
{
var checkbox:CheckboxThingie = new CheckboxThingie(0, 120 * (items.length - 1), preferences.get(prefString));
checkboxes.push(checkbox);
add(checkbox);
}
/**
* Assumes that the preference has already been checked/set?
*/
private function prefToggle(prefName:String)
{
var daSwap:Bool = preferences.get(prefName);
daSwap = !daSwap;
preferences.set(prefName, daSwap);
checkboxes[items.selectedIndex].daValue = daSwap;
trace('toggled? ' + preferences.get(prefName));
switch (prefName)
{
case 'fps-counter':
if (getPref('fps-counter'))
FlxG.stage.addChild(Main.fpsCounter);
else
FlxG.stage.removeChild(Main.fpsCounter);
case 'auto-pause':
FlxG.autoPause = getPref('auto-pause');
}
if (prefName == 'fps-counter') {}
}
override function update(elapsed:Float)
{
super.update(elapsed);
// menuCamera.followLerp = CoolUtil.camLerpShit(0.05);
items.forEach(function(daItem:TextMenuItem)
{
if (items.selectedItem == daItem)
daItem.x = 150;
else
daItem.x = 120;
});
}
private static function preferenceCheck(prefString:String, prefValue:Dynamic):Void
{
if (preferences.get(prefString) == null)
{
preferences.set(prefString, prefValue);
trace('set preference!');
}
else
{
trace('found preference: ' + preferences.get(prefString));
}
}
}
class CheckboxThingie extends FlxSprite
{
public var daValue(default, set):Bool;
public function new(x:Float, y:Float, daValue:Bool = false)
{
super(x, y);
frames = Paths.getSparrowAtlas('checkboxThingie');
animation.addByPrefix('static', 'Check Box unselected', 24, false);
animation.addByPrefix('checked', 'Check Box selecting animation', 24, false);
antialiasing = true;
setGraphicSize(Std.int(width * 0.7));
updateHitbox();
this.daValue = daValue;
}
override function update(elapsed:Float)
{
super.update(elapsed);
switch (animation.curAnim.name)
{
case 'static':
offset.set();
case 'checked':
offset.set(17, 70);
}
}
function set_daValue(value:Bool):Bool
{
if (value)
animation.play('checked', true);
else
animation.play('static');
return value;
}
}

View File

@ -0,0 +1,692 @@
package game.state.menus.options.controls;
import flixel.FlxG;
import flixel.input.FlxInput;
import flixel.input.actions.FlxAction;
import flixel.input.actions.FlxActionInput;
import flixel.input.actions.FlxActionInputDigital;
import flixel.input.actions.FlxActionManager;
import flixel.input.actions.FlxActionSet;
import flixel.input.gamepad.FlxGamepadButton;
import flixel.input.gamepad.FlxGamepadInputID;
import flixel.input.keyboard.FlxKey;
/**
* Since, in many cases multiple actions should use similar keys, we don't want the
* rebinding UI to list every action. ActionBinders are what the user percieves as
* an input so, for instance, they can't set jump-press and jump-release to different keys.
*/
enum Control
{
// List notes in order from left to right on gameplay screen.
NOTE_LEFT;
NOTE_DOWN;
NOTE_UP;
NOTE_RIGHT;
UI_UP;
UI_LEFT;
UI_RIGHT;
UI_DOWN;
RESET;
ACCEPT;
BACK;
PAUSE;
#if CAN_CHEAT
CHEAT;
#end
}
@:enum
abstract Action(String) to String from String
{
var UI_UP = "ui_up";
var UI_LEFT = "ui_left";
var UI_RIGHT = "ui_right";
var UI_DOWN = "ui_down";
var UI_UP_P = "ui_up-press";
var UI_LEFT_P = "ui_left-press";
var UI_RIGHT_P = "ui_right-press";
var UI_DOWN_P = "ui_down-press";
var UI_UP_R = "ui_up-release";
var UI_LEFT_R = "ui_left-release";
var UI_RIGHT_R = "ui_right-release";
var UI_DOWN_R = "ui_down-release";
var NOTE_UP = "note_up";
var NOTE_LEFT = "note_left";
var NOTE_RIGHT = "note_right";
var NOTE_DOWN = "note_down";
var NOTE_UP_P = "note_up-press";
var NOTE_LEFT_P = "note_left-press";
var NOTE_RIGHT_P = "note_right-press";
var NOTE_DOWN_P = "note_down-press";
var NOTE_UP_R = "note_up-release";
var NOTE_LEFT_R = "note_left-release";
var NOTE_RIGHT_R = "note_right-release";
var NOTE_DOWN_R = "note_down-release";
var ACCEPT = "accept";
var BACK = "back";
var PAUSE = "pause";
var RESET = "reset";
#if CAN_CHEAT
var CHEAT = "cheat";
#end
}
enum Device
{
Keys;
Gamepad(id:Int);
}
enum KeyboardScheme
{
Solo;
Duo(first:Bool);
None;
Custom;
}
/**
* A list of actions that a player would invoke via some input device.
* Uses FlxActions to funnel various inputs to a single action.
*/
class Controls extends FlxActionSet
{
var _ui_up = new FlxActionDigital(Action.UI_UP);
var _ui_left = new FlxActionDigital(Action.UI_LEFT);
var _ui_right = new FlxActionDigital(Action.UI_RIGHT);
var _ui_down = new FlxActionDigital(Action.UI_DOWN);
var _ui_upP = new FlxActionDigital(Action.UI_UP_P);
var _ui_leftP = new FlxActionDigital(Action.UI_LEFT_P);
var _ui_rightP = new FlxActionDigital(Action.UI_RIGHT_P);
var _ui_downP = new FlxActionDigital(Action.UI_DOWN_P);
var _ui_upR = new FlxActionDigital(Action.UI_UP_R);
var _ui_leftR = new FlxActionDigital(Action.UI_LEFT_R);
var _ui_rightR = new FlxActionDigital(Action.UI_RIGHT_R);
var _ui_downR = new FlxActionDigital(Action.UI_DOWN_R);
var _note_up = new FlxActionDigital(Action.NOTE_UP);
var _note_left = new FlxActionDigital(Action.NOTE_LEFT);
var _note_right = new FlxActionDigital(Action.NOTE_RIGHT);
var _note_down = new FlxActionDigital(Action.NOTE_DOWN);
var _note_upP = new FlxActionDigital(Action.NOTE_UP_P);
var _note_leftP = new FlxActionDigital(Action.NOTE_LEFT_P);
var _note_rightP = new FlxActionDigital(Action.NOTE_RIGHT_P);
var _note_downP = new FlxActionDigital(Action.NOTE_DOWN_P);
var _note_upR = new FlxActionDigital(Action.NOTE_UP_R);
var _note_leftR = new FlxActionDigital(Action.NOTE_LEFT_R);
var _note_rightR = new FlxActionDigital(Action.NOTE_RIGHT_R);
var _note_downR = new FlxActionDigital(Action.NOTE_DOWN_R);
var _accept = new FlxActionDigital(Action.ACCEPT);
var _back = new FlxActionDigital(Action.BACK);
var _pause = new FlxActionDigital(Action.PAUSE);
var _reset = new FlxActionDigital(Action.RESET);
#if CAN_CHEAT
var _cheat = new FlxActionDigital(Action.CHEAT);
#end
var byName:Map<String, FlxActionDigital> = new Map<String, FlxActionDigital>();
public var gamepadsAdded:Array<Int> = [];
public var keyboardScheme = KeyboardScheme.None;
public var UI_UP (get, never):Bool; inline function get_UI_UP () return _ui_up .check();
public var UI_LEFT (get, never):Bool; inline function get_UI_LEFT () return _ui_left .check();
public var UI_RIGHT(get, never):Bool; inline function get_UI_RIGHT() return _ui_right.check();
public var UI_DOWN (get, never):Bool; inline function get_UI_DOWN () return _ui_down .check();
public var UI_UP_P (get, never):Bool; inline function get_UI_UP_P () return _ui_upP .check();
public var UI_LEFT_P (get, never):Bool; inline function get_UI_LEFT_P () return _ui_leftP .check();
public var UI_RIGHT_P(get, never):Bool; inline function get_UI_RIGHT_P() return _ui_rightP.check();
public var UI_DOWN_P (get, never):Bool; inline function get_UI_DOWN_P () return _ui_downP .check();
public var UI_UP_R (get, never):Bool; inline function get_UI_UP_R () return _ui_upR .check();
public var UI_LEFT_R (get, never):Bool; inline function get_UI_LEFT_R () return _ui_leftR .check();
public var UI_RIGHT_R(get, never):Bool; inline function get_UI_RIGHT_R() return _ui_rightR.check();
public var UI_DOWN_R (get, never):Bool; inline function get_UI_DOWN_R () return _ui_downR .check();
public var NOTE_UP (get, never):Bool; inline function get_NOTE_UP () return _note_up .check();
public var NOTE_LEFT (get, never):Bool; inline function get_NOTE_LEFT () return _note_left .check();
public var NOTE_RIGHT(get, never):Bool; inline function get_NOTE_RIGHT() return _note_right.check();
public var NOTE_DOWN (get, never):Bool; inline function get_NOTE_DOWN () return _note_down .check();
public var NOTE_UP_P (get, never):Bool; inline function get_NOTE_UP_P () return _note_upP .check();
public var NOTE_LEFT_P (get, never):Bool; inline function get_NOTE_LEFT_P () return _note_leftP .check();
public var NOTE_RIGHT_P(get, never):Bool; inline function get_NOTE_RIGHT_P() return _note_rightP.check();
public var NOTE_DOWN_P (get, never):Bool; inline function get_NOTE_DOWN_P () return _note_downP .check();
public var NOTE_UP_R (get, never):Bool; inline function get_NOTE_UP_R () return _note_upR .check();
public var NOTE_LEFT_R (get, never):Bool; inline function get_NOTE_LEFT_R () return _note_leftR .check();
public var NOTE_RIGHT_R(get, never):Bool; inline function get_NOTE_RIGHT_R() return _note_rightR.check();
public var NOTE_DOWN_R (get, never):Bool; inline function get_NOTE_DOWN_R () return _note_downR .check();
public var ACCEPT(get, never):Bool; inline function get_ACCEPT() return _accept.check();
public var BACK (get, never):Bool; inline function get_BACK () return _back .check();
public var PAUSE (get, never):Bool; inline function get_PAUSE () return _pause .check();
public var RESET (get, never):Bool; inline function get_RESET () return _reset .check();
#if CAN_CHEAT
public var CHEAT (get, never):Bool; inline function get_CHEAT () return _cheat.check ();
#end
public function new(name, scheme:KeyboardScheme = null)
{
super(name);
add(_ui_up);
add(_ui_left);
add(_ui_right);
add(_ui_down);
add(_ui_upP);
add(_ui_leftP);
add(_ui_rightP);
add(_ui_downP);
add(_ui_upR);
add(_ui_leftR);
add(_ui_rightR);
add(_ui_downR);
add(_note_up);
add(_note_left);
add(_note_right);
add(_note_down);
add(_note_upP);
add(_note_leftP);
add(_note_rightP);
add(_note_downP);
add(_note_upR);
add(_note_leftR);
add(_note_rightR);
add(_note_downR);
add(_accept);
add(_back);
add(_pause);
add(_reset);
#if CAN_CHEAT
add(_cheat);
#end
for (action in digitalActions)
byName[action.name] = action;
if (scheme == null)
scheme = None;
setKeyboardScheme(scheme, false);
}
override function update()
{
super.update();
}
// inline
public function checkByName(name:Action):Bool
{
#if debug
if (!byName.exists(name))
throw 'Invalid name: $name';
#end
return byName[name].check();
}
public function getDialogueName(action:FlxActionDigital):String
{
var input = action.inputs[0];
return switch input.device
{
case KEYBOARD: return '[${(input.inputID : FlxKey)}]';
case GAMEPAD: return '(${(input.inputID : FlxGamepadInputID)})';
case device: throw 'unhandled device: $device';
}
}
public function getDialogueNameFromToken(token:String):String
{
return getDialogueName(getActionFromControl(Control.createByName(token.toUpperCase())));
}
function getActionFromControl(control:Control):FlxActionDigital
{
return switch (control)
{
case UI_UP: _ui_up;
case UI_DOWN: _ui_down;
case UI_LEFT: _ui_left;
case UI_RIGHT: _ui_right;
case NOTE_UP: _note_up;
case NOTE_DOWN: _note_down;
case NOTE_LEFT: _note_left;
case NOTE_RIGHT: _note_right;
case ACCEPT: _accept;
case BACK: _back;
case PAUSE: _pause;
case RESET: _reset;
#if CAN_CHEAT
case CHEAT: _cheat;
#end
}
}
static function init():Void
{
var actions = new FlxActionManager();
FlxG.inputs.add(actions);
}
/**
* Calls a function passing each action bound by the specified control
* @param control
* @param func
* @return ->Void)
*/
function forEachBound(control:Control, func:FlxActionDigital->FlxInputState->Void)
{
switch (control)
{
case UI_UP:
func(_ui_up, PRESSED);
func(_ui_upP, JUST_PRESSED);
func(_ui_upR, JUST_RELEASED);
case UI_LEFT:
func(_ui_left, PRESSED);
func(_ui_leftP, JUST_PRESSED);
func(_ui_leftR, JUST_RELEASED);
case UI_RIGHT:
func(_ui_right, PRESSED);
func(_ui_rightP, JUST_PRESSED);
func(_ui_rightR, JUST_RELEASED);
case UI_DOWN:
func(_ui_down, PRESSED);
func(_ui_downP, JUST_PRESSED);
func(_ui_downR, JUST_RELEASED);
case NOTE_UP:
func(_note_up, PRESSED);
func(_note_upP, JUST_PRESSED);
func(_note_upR, JUST_RELEASED);
case NOTE_LEFT:
func(_note_left, PRESSED);
func(_note_leftP, JUST_PRESSED);
func(_note_leftR, JUST_RELEASED);
case NOTE_RIGHT:
func(_note_right, PRESSED);
func(_note_rightP, JUST_PRESSED);
func(_note_rightR, JUST_RELEASED);
case NOTE_DOWN:
func(_note_down, PRESSED);
func(_note_downP, JUST_PRESSED);
func(_note_downR, JUST_RELEASED);
case ACCEPT:
func(_accept, JUST_PRESSED);
case BACK:
func(_back, JUST_PRESSED);
case PAUSE:
func(_pause, JUST_PRESSED);
case RESET:
func(_reset, JUST_PRESSED);
#if CAN_CHEAT
case CHEAT:
func(_cheat, JUST_PRESSED);
#end
}
}
public function replaceBinding(control:Control, device:Device, toAdd:Int, toRemove:Int)
{
if (toAdd == toRemove)
return;
switch (device)
{
case Keys:
forEachBound(control, function(action, _) replaceKey(action, toAdd, toRemove));
case Gamepad(id):
forEachBound(control, function(action, _) replaceButton(action, id, toAdd, toRemove));
}
}
function replaceKey(action:FlxActionDigital, toAdd:Int, toRemove:Int)
{
for (i in 0...action.inputs.length)
{
var input = action.inputs[i];
if (input.device == KEYBOARD && input.inputID == toRemove)
{
@:privateAccess
action.inputs[i].inputID = toAdd;
}
}
}
function replaceButton(action:FlxActionDigital, deviceID:Int, toAdd:Int, toRemove:Int)
{
for (i in 0...action.inputs.length)
{
var input = action.inputs[i];
if (isGamepad(input, deviceID) && input.inputID == toRemove)
{
@:privateAccess
action.inputs[i].inputID = toAdd;
}
}
}
public function copyFrom(controls:Controls, ?device:Device)
{
for (name in controls.byName.keys())
{
var action = controls.byName[name];
for (input in action.inputs)
{
if (device == null || isDevice(input, device))
byName[name].add(cast input);
}
}
switch (device)
{
case null:
// add all
for (gamepad in controls.gamepadsAdded)
if (gamepadsAdded.indexOf(gamepad) == -1)
gamepadsAdded.push(gamepad);
mergeKeyboardScheme(controls.keyboardScheme);
case Gamepad(id):
gamepadsAdded.push(id);
case Keys:
mergeKeyboardScheme(controls.keyboardScheme);
}
}
inline public function copyTo(controls:Controls, ?device:Device)
{
controls.copyFrom(this, device);
}
function mergeKeyboardScheme(scheme:KeyboardScheme):Void
{
if (scheme != None)
{
switch (keyboardScheme)
{
case None:
keyboardScheme = scheme;
default:
keyboardScheme = Custom;
}
}
}
/**
* Sets all actions that pertain to the binder to trigger when the supplied keys are used.
* If binder is a literal you can inline this
*/
public function bindKeys(control:Control, keys:Array<FlxKey>)
{
forEachBound(control, function(action, state) addKeys(action, keys, state));
}
/**
* Sets all actions that pertain to the binder to trigger when the supplied keys are used.
* If binder is a literal you can inline this
*/
public function unbindKeys(control:Control, keys:Array<FlxKey>)
{
forEachBound(control, function(action, _) removeKeys(action, keys));
}
inline static function addKeys(action:FlxActionDigital, keys:Array<FlxKey>, state:FlxInputState)
{
for (key in keys)
action.addKey(key, state);
}
static function removeKeys(action:FlxActionDigital, keys:Array<FlxKey>)
{
var i = action.inputs.length;
while (i-- > 0)
{
var input = action.inputs[i];
if (input.device == KEYBOARD && keys.indexOf(cast input.inputID) != -1)
action.remove(input);
}
}
public function setKeyboardScheme(scheme:KeyboardScheme, reset = true)
{
if (reset)
removeKeyboard();
keyboardScheme = scheme;
switch (scheme)
{
case Solo:
bindKeys(Control.UI_UP, [W, FlxKey.UP]);
bindKeys(Control.UI_DOWN, [S, FlxKey.DOWN]);
bindKeys(Control.UI_LEFT, [A, FlxKey.LEFT]);
bindKeys(Control.UI_RIGHT, [D, FlxKey.RIGHT]);
bindKeys(Control.NOTE_UP, [W, FlxKey.UP]);
bindKeys(Control.NOTE_DOWN, [S, FlxKey.DOWN]);
bindKeys(Control.NOTE_LEFT, [A, FlxKey.LEFT]);
bindKeys(Control.NOTE_RIGHT, [D, FlxKey.RIGHT]);
bindKeys(Control.ACCEPT, [Z, SPACE, ENTER]);
bindKeys(Control.BACK, [X, BACKSPACE, ESCAPE]);
bindKeys(Control.PAUSE, [P, ENTER, ESCAPE]);
bindKeys(Control.RESET, [R]);
case Duo(true):
bindKeys(Control.UI_UP, [W]);
bindKeys(Control.UI_DOWN, [S]);
bindKeys(Control.UI_LEFT, [A]);
bindKeys(Control.UI_RIGHT, [D]);
bindKeys(Control.NOTE_UP, [W]);
bindKeys(Control.NOTE_DOWN, [S]);
bindKeys(Control.NOTE_LEFT, [A]);
bindKeys(Control.NOTE_RIGHT, [D]);
bindKeys(Control.ACCEPT, [G, Z]);
bindKeys(Control.BACK, [H, X]);
bindKeys(Control.PAUSE, [ONE]);
bindKeys(Control.RESET, [R]);
case Duo(false):
bindKeys(Control.UI_UP, [FlxKey.UP]);
bindKeys(Control.UI_DOWN, [FlxKey.DOWN]);
bindKeys(Control.UI_LEFT, [FlxKey.LEFT]);
bindKeys(Control.UI_RIGHT, [FlxKey.RIGHT]);
bindKeys(Control.NOTE_UP, [FlxKey.UP]);
bindKeys(Control.NOTE_DOWN, [FlxKey.DOWN]);
bindKeys(Control.NOTE_LEFT, [FlxKey.LEFT]);
bindKeys(Control.NOTE_RIGHT, [FlxKey.RIGHT]);
bindKeys(Control.ACCEPT, [O]);
bindKeys(Control.BACK, [P]);
bindKeys(Control.PAUSE, [ENTER]);
bindKeys(Control.RESET, [BACKSPACE]);
case None: // nothing
case Custom: // nothing
}
}
function removeKeyboard()
{
for (action in this.digitalActions)
{
var i = action.inputs.length;
while (i-- > 0)
{
var input = action.inputs[i];
if (input.device == KEYBOARD)
action.remove(input);
}
}
}
public function addGamepadWithSaveData(id:Int, ?padData:Dynamic):Void
{
gamepadsAdded.push(id);
fromSaveData(padData, Gamepad(id));
}
inline function addGamepadLiteral(id:Int, ?buttonMap:Map<Control, Array<FlxGamepadInputID>>):Void
{
gamepadsAdded.push(id);
for (control in buttonMap.keys())
bindButtons(control, id, buttonMap[control]);
}
public function removeGamepad(deviceID:Int = FlxInputDeviceID.ALL):Void
{
for (action in this.digitalActions)
{
var i = action.inputs.length;
while (i-- > 0)
{
var input = action.inputs[i];
if (isGamepad(input, deviceID))
action.remove(input);
}
}
gamepadsAdded.remove(deviceID);
}
public function addDefaultGamepad(id):Void
{
addGamepadLiteral(id, [
Control.ACCEPT => [#if switch B #else A #end],
Control.BACK => [#if switch A #else B #end, FlxGamepadInputID.BACK],
Control.UI_UP => [DPAD_UP, LEFT_STICK_DIGITAL_UP],
Control.UI_DOWN => [DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN],
Control.UI_LEFT => [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT],
Control.UI_RIGHT => [DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT],
// don't swap A/B or X/Y for switch on these. A is always the bottom face button
Control.NOTE_UP => [DPAD_UP, Y, LEFT_STICK_DIGITAL_UP, RIGHT_STICK_DIGITAL_UP],
Control.NOTE_DOWN => [DPAD_DOWN, A, LEFT_STICK_DIGITAL_DOWN, RIGHT_STICK_DIGITAL_DOWN],
Control.NOTE_LEFT => [DPAD_LEFT, X, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT],
Control.NOTE_RIGHT => [DPAD_RIGHT, B, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT],
Control.PAUSE => [START],
Control.RESET => [Y]
#if CAN_CHEAT
,Control.CHEAT => [X]
#end
]);
}
/**
* Sets all actions that pertain to the binder to trigger when the supplied keys are used.
* If binder is a literal you can inline this
*/
public function bindButtons(control:Control, id, buttons)
{
forEachBound(control, function(action, state) addButtons(action, buttons, state, id));
}
/**
* Sets all actions that pertain to the binder to trigger when the supplied keys are used.
* If binder is a literal you can inline this
*/
public function unbindButtons(control:Control, gamepadID:Int, buttons)
{
forEachBound(control, function(action, _) removeButtons(action, gamepadID, buttons));
}
inline static function addButtons(action:FlxActionDigital, buttons:Array<FlxGamepadInputID>, state, id)
{
for (button in buttons)
action.addGamepad(button, state, id);
}
static function removeButtons(action:FlxActionDigital, gamepadID:Int, buttons:Array<FlxGamepadInputID>)
{
var i = action.inputs.length;
while (i-- > 0)
{
var input = action.inputs[i];
if (isGamepad(input, gamepadID) && buttons.indexOf(cast input.inputID) != -1)
action.remove(input);
}
}
public function getInputsFor(control:Control, device:Device, ?list:Array<Int>):Array<Int>
{
if (list == null)
list = [];
switch (device)
{
case Keys:
for (input in getActionFromControl(control).inputs)
{
if (input.device == KEYBOARD)
list.push(input.inputID);
}
case Gamepad(id):
for (input in getActionFromControl(control).inputs)
{
if (isGamepad(input, id))
list.push(input.inputID);
}
}
return list;
}
public function removeDevice(device:Device)
{
switch (device)
{
case Keys:
setKeyboardScheme(None);
case Gamepad(id):
removeGamepad(id);
}
}
public function fromSaveData(data:Dynamic, device:Device)
{
for (control in Control.createAll())
{
var inputs:Array<Int> = Reflect.field(data, control.getName());
if (inputs != null)
{
switch(device)
{
case Keys: bindKeys(control, inputs.copy());
case Gamepad(id): bindButtons(control, id, inputs.copy());
}
}
}
}
public function createSaveData(device:Device):Dynamic
{
var isEmpty = true;
var data = {};
for (control in Control.createAll())
{
var inputs = getInputsFor(control, device);
isEmpty = isEmpty && inputs.length == 0;
Reflect.setField(data, control.getName(), inputs);
}
return isEmpty ? null : data;
}
static function isDevice(input:FlxActionInput, device:Device)
{
return switch device
{
case Keys: input.device == KEYBOARD;
case Gamepad(id): isGamepad(input, id);
}
}
inline static function isGamepad(input:FlxActionInput, deviceID:Int)
{
return input.device == GAMEPAD && (deviceID == FlxInputDeviceID.ALL || input.deviceID == deviceID);
}
}
typedef SaveInputLists = {?keys:Array<Int>, ?pad:Array<Int>};

View File

@ -0,0 +1,361 @@
package game.state.menus.options.controls;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.group.FlxGroup;
import flixel.input.actions.FlxActionInput;
import flixel.input.gamepad.FlxGamepadInputID;
import flixel.input.keyboard.FlxKey;
import game.data.PlayerSettings;
import game.data.format.InputFormatter;
import game.state.subState.Prompt;
import game.ui.AtlasText;
import game.ui.MenuList;
import game.ui.TextMenuList;
import game.ui.TextMenuList.TextMenuItem;
import game.state.subState.Prompt;
import game.state.menus.options.OptionsState.Page;
import game.state.menus.options.controls.Controls.Device;
import game.state.menus.options.controls.Controls.Control;
class ControlsMenu extends OptionsState.Page
{
inline static public var COLUMNS = 2;
static var controlList = Control.createAll();
/*
* Defines groups of controls that cannot share inputs, like left and right. Say, if ACCEPT is Z, Back is X,
* if the player sets Back to Z it also set ACCEPT to X. This prevents the player from setting the controls in
* a way the prevents them from changing more controls or exiting the menu.
*/
static var controlGroups:Array<Array<Control>> = [
[NOTE_UP, NOTE_DOWN, NOTE_LEFT, NOTE_RIGHT],
[UI_UP, UI_DOWN, UI_LEFT, UI_RIGHT, ACCEPT, BACK]
];
var itemGroups:Array<Array<InputItem>> = [for (i in 0...controlGroups.length) []];
var controlGrid:MenuTypedList<InputItem>;
var deviceList:TextMenuList;
var menuCamera:FlxCamera;
var prompt:Prompt;
var camFollow:FlxObject;
var labels:FlxTypedGroup<AtlasText>;
var currentDevice:Device = Keys;
var deviceListSelected = false;
public function new()
{
super();
menuCamera = new FlxCamera();
FlxG.cameras.add(menuCamera, false);
menuCamera.bgColor = 0x0;
camera = menuCamera;
labels = new FlxTypedGroup<AtlasText>();
var headers = new FlxTypedGroup<AtlasText>();
controlGrid = new MenuTypedList(Columns(COLUMNS), Vertical);
add(labels);
add(headers);
add(controlGrid);
if (FlxG.gamepads.numActiveGamepads > 0)
{
var devicesBg = new FlxSprite();
devicesBg.makeGraphic(FlxG.width, 100, 0xFFfafd6d);
add(devicesBg);
deviceList = new TextMenuList(Horizontal, None);
add(deviceList);
deviceListSelected = true;
var item;
item = deviceList.createItem("Keyboard", Bold, selectDevice.bind(Keys));
item.x = FlxG.width / 2 - item.width - 30;
item.y = (devicesBg.height - item.height) / 2;
item = deviceList.createItem("Gamepad", Bold, selectDevice.bind(Gamepad(FlxG.gamepads.firstActive.id)));
item.x = FlxG.width / 2 + 30;
item.y = (devicesBg.height - item.height) / 2;
}
// FlxG.debugger.drawDebug = true;
var y = deviceList == null ? 30 : 120;
var spacer = 70;
var currentHeader:String = null;
// list order is determined by enum order
for (i in 0...controlList.length)
{
var control = controlList[i];
var name = control.getName();
if (currentHeader != "UI_" && name.indexOf("UI_") == 0)
{
currentHeader = "UI_";
headers.add(new BoldText(0, y, "UI")).screenCenter(X);
y += spacer;
}
else if (currentHeader != "NOTE_" && name.indexOf("NOTE_") == 0)
{
currentHeader = "NOTE_";
headers.add(new BoldText(0, y, "NOTES")).screenCenter(X);
y += spacer;
}
if (currentHeader != null && name.indexOf(currentHeader) == 0)
name = name.substr(currentHeader.length);
var label = labels.add(new BoldText(150, y, name));
label.alpha = 0.6;
for (i in 0...COLUMNS)
createItem(label.x + 400 + i * 300, y, control, i);
y += spacer;
}
camFollow = new FlxObject(FlxG.width / 2, 0, 70, 70);
if (deviceList != null)
{
camFollow.y = deviceList.selectedItem.y;
controlGrid.selectedItem.idle();
controlGrid.enabled = false;
}
else
camFollow.y = controlGrid.selectedItem.y;
menuCamera.follow(camFollow, null, 0.06);
var margin = 100;
menuCamera.deadzone.set(0, margin, menuCamera.width, menuCamera.height - margin * 2);
menuCamera.minScrollY = 0;
controlGrid.onChange.add(function(selected)
{
camFollow.y = selected.y;
labels.forEach((label) -> label.alpha = 0.6);
labels.members[Std.int(controlGrid.selectedIndex / COLUMNS)].alpha = 1.0;
});
prompt = new Prompt("\nPress any key to rebind\n\n\n\n Escape to cancel", None);
prompt.create();
prompt.createBgFromMargin(100, 0xFFfafd6d);
prompt.back.scrollFactor.set(0, 0);
prompt.exists = false;
add(prompt);
}
function createItem(x = 0.0, y = 0.0, control:Control, index:Int)
{
var item = new InputItem(x, y, currentDevice, control, index, onSelect);
for (i in 0...controlGroups.length)
{
if (controlGroups[i].contains(control))
itemGroups[i].push(item);
}
return controlGrid.addItem(item.name, item);
}
function onSelect():Void
{
controlGrid.enabled = false;
canExit = false;
prompt.exists = true;
}
function goToDeviceList()
{
controlGrid.selectedItem.idle();
labels.members[Std.int(controlGrid.selectedIndex / COLUMNS)].alpha = 0.6;
controlGrid.enabled = false;
deviceList.enabled = true;
canExit = true;
camFollow.y = deviceList.selectedItem.y;
deviceListSelected = true;
}
function selectDevice(device:Device)
{
currentDevice = device;
for (item in controlGrid.members)
item.updateDevice(currentDevice);
var inputName = device == Keys ? "key" : "button";
var cancel = device == Keys ? "Escape" : "Back";
// todo: alignment
if (device == Keys)
prompt.setText('\nPress any key to rebind\n\n\n\n $cancel to cancel');
else
prompt.setText('\nPress any button\n to rebind\n\n\n $cancel to cancel');
controlGrid.selectedItem.select();
labels.members[Std.int(controlGrid.selectedIndex / COLUMNS)].alpha = 1.0;
controlGrid.enabled = true;
deviceList.enabled = false;
deviceListSelected = false;
canExit = false;
}
override function update(elapsed:Float)
{
super.update(elapsed);
var controls = PlayerSettings.player1.controls;
if (controlGrid.enabled && deviceList != null && deviceListSelected == false && controls.BACK)
goToDeviceList();
if (prompt.exists)
{
switch (currentDevice)
{
case Keys:
{
// check released otherwise bugs can happen when you change the BACK key
var key = FlxG.keys.firstJustReleased();
if (key != NONE)
{
if (key != ESCAPE)
onInputSelect(key);
closePrompt();
}
}
case Gamepad(id):
{
var button = FlxG.gamepads.getByID(id).firstJustReleasedID();
if (button != NONE)
{
if (button != BACK)
onInputSelect(button);
closePrompt();
}
}
}
}
}
function onInputSelect(input:Int)
{
var item = controlGrid.selectedItem;
// check if that key is already set for this
var column0 = Math.floor(controlGrid.selectedIndex / 2) * 2;
for (i in 0...COLUMNS)
{
if (controlGrid.members[column0 + i].input == input)
return;
}
// Check if items in the same group already have the new input
for (group in itemGroups)
{
if (group.contains(item))
{
for (otherItem in group)
{
if (otherItem != item && otherItem.input == input)
{
// replace that input with this items old input.
PlayerSettings.player1.controls.replaceBinding(otherItem.control, currentDevice, item.input, otherItem.input);
// Don't use resetItem() since items share names/labels
otherItem.input = item.input;
otherItem.label.text = item.label.text;
}
}
}
}
PlayerSettings.player1.controls.replaceBinding(item.control, currentDevice, input, item.input);
// Don't use resetItem() since items share names/labels
item.input = input;
item.label.text = item.getLabel(input);
PlayerSettings.player1.saveControls();
}
function closePrompt()
{
prompt.exists = false;
controlGrid.enabled = true;
if (deviceList == null)
canExit = true;
}
override function destroy()
{
super.destroy();
itemGroups = null;
if (FlxG.cameras.list.contains(menuCamera))
FlxG.cameras.remove(menuCamera);
}
override function set_enabled(value:Bool)
{
if (value == false)
{
controlGrid.enabled = false;
if (deviceList != null)
deviceList.enabled = false;
}
else
{
controlGrid.enabled = !deviceListSelected;
if (deviceList != null)
deviceList.enabled = deviceListSelected;
}
return super.set_enabled(value);
}
}
class InputItem extends TextMenuItem
{
public var device(default, null):Device = Keys;
public var control:Control;
public var input:Int = -1;
public var index:Int = -1;
public function new(x = 0.0, y = 0.0, device, control, index, ?callback)
{
this.device = device;
this.control = control;
this.index = index;
this.input = getInput();
super(x, y, getLabel(input), Default, callback);
}
public function updateDevice(device:Device)
{
if (this.device != device)
{
this.device = device;
input = getInput();
label.text = getLabel(input);
}
}
function getInput()
{
var list = PlayerSettings.player1.controls.getInputsFor(control, device);
if (list.length > index)
{
if (list[index] != FlxKey.ESCAPE || list[index] != FlxGamepadInputID.BACK)
return list[index];
if (list.length > ControlsMenu.COLUMNS)
// Escape isn't mappable, show a third option, instead.
return list[ControlsMenu.COLUMNS];
}
return -1;
}
public function getLabel(input:Int)
{
return input == -1 ? "---" : InputFormatter.format(input, device);
}
}

View File

@ -0,0 +1,172 @@
package game.state.subState;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSubState;
import flixel.math.FlxPoint;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import haxe.display.Display.Package;
import game.data.backend.Conductor;
import game.data.debug.*;
import game.objects.*;
import game.state.menus.options.PreferencesMenu;
import game.state.*;
import game.state.menus.*;
class GameOverSubstate extends MusicBeatSubstate
{
var bf:Boyfriend;
var camFollow:FlxObject;
var stageSuffix:String = "";
var randomGameover:Int = 1;
public function new(x:Float, y:Float)
{
var daStage = PlayState.curStage;
var daBf:String = '';
switch (daStage)
{
case 'school' | 'schoolEvil':
stageSuffix = '-pixel';
daBf = 'bf-pixel-dead';
default:
daBf = 'bf';
}
var daSong = PlayState.SONG.song.toLowerCase();
switch (daSong)
{
case 'stress':
daBf = 'bf-holding-gf-dead';
}
super();
Conductor.songPosition = 0;
bf = new Boyfriend(x, y, daBf);
add(bf);
camFollow = new FlxObject(bf.getGraphicMidpoint().x, bf.getGraphicMidpoint().y, 1, 1);
add(camFollow);
FlxG.sound.play(Paths.sound('fnf_loss_sfx' + stageSuffix));
Conductor.changeBPM(100);
// FlxG.camera.followLerp = 1;
// FlxG.camera.focusOn(FlxPoint.get(FlxG.width / 2, FlxG.height / 2));
FlxG.camera.scroll.set();
FlxG.camera.target = null;
bf.playAnim('firstDeath');
var randomCensor:Array<Int> = [];
if (PreferencesMenu.getPref('censor-naughty'))
randomCensor = [1, 3, 8, 13, 17, 21];
randomGameover = FlxG.random.int(1, 25, randomCensor);
}
var playingDeathSound:Bool = false;
override function update(elapsed:Float)
{
// makes the lerp non-dependant on the framerate
// FlxG.camera.followLerp = CoolUtil.camLerpShit(0.01);
super.update(elapsed);
if (controls.ACCEPT)
{
endBullshit();
}
if (controls.BACK)
{
PlayState.deathCounter = 0;
PlayState.seenCutscene = false;
FlxG.sound.music.stop();
if (PlayState.isStoryMode)
FlxG.switchState(new StoryMenuState());
else
FlxG.switchState(new FreeplayState());
}
#if debug
if (FlxG.keys.justPressed.EIGHT)
FlxG.switchState(new AnimationDebug(bf.curCharacter));
#end
if (bf.animation.curAnim.name == 'firstDeath' && bf.animation.curAnim.curFrame == 12)
{
FlxG.camera.follow(camFollow, LOCKON, 0.01);
}
switch (PlayState.storyWeek)
{
case 7:
if (bf.animation.curAnim.name == 'firstDeath' && bf.animation.curAnim.finished && !playingDeathSound)
{
playingDeathSound = true;
bf.startedDeath = true;
coolStartDeath(0.2);
FlxG.sound.play(Paths.sound('jeffGameover/jeffGameover-' + randomGameover), 1, false, null, true, function()
{
if (!isEnding)
FlxG.sound.music.fadeIn(4, 0.2, 1);
});
}
default:
if (bf.animation.curAnim.name == 'firstDeath' && bf.animation.curAnim.finished)
{
bf.startedDeath = true;
coolStartDeath();
}
}
if (FlxG.sound.music.playing)
{
Conductor.songPosition = FlxG.sound.music.time;
}
}
private function coolStartDeath(?vol:Float = 1):Void
{
if (!isEnding)
FlxG.sound.playMusic(Paths.music('gameOver' + stageSuffix), vol);
}
override function beatHit()
{
super.beatHit();
FlxG.log.add('beat');
}
var isEnding:Bool = false;
function endBullshit():Void
{
if (!isEnding)
{
isEnding = true;
bf.playAnim('deathConfirm', true);
FlxG.sound.music.stop();
FlxG.sound.play(Paths.music('gameOverEnd' + stageSuffix));
new FlxTimer().start(0.7, function(tmr:FlxTimer)
{
FlxG.camera.fade(FlxColor.BLACK, 2, false, function()
{
LoadingState.loadAndSwitchState(new PlayState());
});
});
}
}
}

View File

@ -0,0 +1,65 @@
package game.state.subState;
import game.data.PlayerSettings;
import game.data.backend.Conductor;
import game.data.backend.Conductor.BPMChangeEvent;
import game.state.menus.options.controls.Controls;
import flixel.FlxG;
import flixel.FlxSubState;
class MusicBeatSubstate extends FlxSubState
{
public function new()
{
super();
}
private var curStep:Int = 0;
private var curBeat:Int = 0;
private var controls(get, never):Controls;
inline function get_controls():Controls
return PlayerSettings.player1.controls;
override function update(elapsed:Float)
{
//everyStep();
var oldStep:Int = curStep;
updateCurStep();
curBeat = Math.floor(curStep / 4);
if (oldStep != curStep && curStep >= 0)
stepHit();
super.update(elapsed);
}
private function updateCurStep():Void
{
var lastChange:BPMChangeEvent = {
stepTime: 0,
songTime: 0,
bpm: 0
}
for (i in 0...Conductor.bpmChangeMap.length)
{
if (Conductor.songPosition > Conductor.bpmChangeMap[i].songTime)
lastChange = Conductor.bpmChangeMap[i];
}
curStep = lastChange.stepTime + Math.floor((Conductor.songPosition - lastChange.songTime) / Conductor.stepCrochet);
}
public function stepHit():Void
{
if (curStep % 4 == 0)
beatHit();
}
public function beatHit():Void
{
//do literally nothing dumbass
}
}

View File

@ -0,0 +1,48 @@
package game.state.subState;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxSubState;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import lime.app.Application;
import game.state.MusicBeatState;
import game.state.menus.MainMenuState;
class OutdatedSubState extends MusicBeatState
{
public static var leftState:Bool = false;
override function create()
{
super.create();
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
add(bg);
var ver = "v" + Application.current.meta.get('version');
var txt:FlxText = new FlxText(0, 0, FlxG.width,
"HEY! You're running an outdated version of the game!\nCurrent version is "
+ ver
+ " while the most recent version is "
+ NGio.GAME_VER
+ "! Press Space to go to itch.io, or ESCAPE to ignore this!!",
32);
txt.setFormat("VCR OSD Mono", 32, FlxColor.WHITE, CENTER);
txt.screenCenter();
add(txt);
}
override function update(elapsed:Float)
{
if (controls.ACCEPT)
{
FlxG.openURL("https://ninja-muffin24.itch.io/funkin");
}
if (controls.BACK)
{
leftState = true;
FlxG.switchState(new MainMenuState());
}
super.update(elapsed);
}
}

View File

@ -0,0 +1,225 @@
package game.state.subState;
import game.state.menus.options.controls.Controls.Control;
import game.state.menus.*;
import game.data.backend.*;
import game.ui.Alphabet;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxSubState;
import flixel.addons.transition.FlxTransitionableState;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.input.keyboard.FlxKey;
import flixel.system.FlxSound;
import flixel.text.FlxText;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
class PauseSubState extends MusicBeatSubstate
{
var grpMenuShit:FlxTypedGroup<Alphabet>;
var pauseOG:Array<String> = [
'Resume',
'Restart Song',
'Change Difficulty',
'Toggle Practice Mode',
'Exit to menu'
];
var difficultyChoices:Array<String> = ['EASY', 'NORMAL', 'HARD', 'BACK'];
var menuItems:Array<String> = [];
var curSelected:Int = 0;
var pauseMusic:FlxSound;
var practiceText:FlxText;
public function new(x:Float, y:Float)
{
super();
menuItems = pauseOG;
pauseMusic = new FlxSound().loadEmbedded(Paths.music('breakfast'), true, true);
pauseMusic.volume = 0;
pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2)));
FlxG.sound.list.add(pauseMusic);
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
bg.alpha = 0;
bg.scrollFactor.set();
add(bg);
var levelInfo:FlxText = new FlxText(20, 15, 0, "", 32);
levelInfo.text += PlayState.SONG.song;
levelInfo.scrollFactor.set();
levelInfo.setFormat(Paths.font("vcr.ttf"), 32);
levelInfo.updateHitbox();
add(levelInfo);
var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, "", 32);
levelDifficulty.text += CoolUtil.difficultyString();
levelDifficulty.scrollFactor.set();
levelDifficulty.setFormat(Paths.font('vcr.ttf'), 32);
levelDifficulty.updateHitbox();
add(levelDifficulty);
var deathCounter:FlxText = new FlxText(20, 15 + 64, 0, "", 32);
deathCounter.text = "Blue balled: " + PlayState.deathCounter;
deathCounter.scrollFactor.set();
deathCounter.setFormat(Paths.font('vcr.ttf'), 32);
deathCounter.updateHitbox();
add(deathCounter);
practiceText = new FlxText(20, 15 + 64 + 32, 0, "PRACTICE MODE", 32);
practiceText.scrollFactor.set();
practiceText.setFormat(Paths.font('vcr.ttf'), 32);
practiceText.updateHitbox();
practiceText.x = FlxG.width - (practiceText.width + 20);
practiceText.visible = PlayState.practiceMode;
add(practiceText);
levelDifficulty.alpha = 0;
levelInfo.alpha = 0;
deathCounter.alpha = 0;
levelInfo.x = FlxG.width - (levelInfo.width + 20);
levelDifficulty.x = FlxG.width - (levelDifficulty.width + 20);
deathCounter.x = FlxG.width - (deathCounter.width + 20);
FlxTween.tween(bg, {alpha: 0.6}, 0.4, {ease: FlxEase.quartInOut});
FlxTween.tween(levelInfo, {alpha: 1, y: 20}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.3});
FlxTween.tween(levelDifficulty, {alpha: 1, y: levelDifficulty.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.5});
FlxTween.tween(deathCounter, {alpha: 1, y: deathCounter.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.7});
grpMenuShit = new FlxTypedGroup<Alphabet>();
add(grpMenuShit);
regenMenu();
// cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]];
}
private function regenMenu():Void
{
while (grpMenuShit.members.length > 0)
{
grpMenuShit.remove(grpMenuShit.members[0], true);
}
for (i in 0...menuItems.length)
{
var songText:Alphabet = new Alphabet(0, (70 * i) + 30, menuItems[i], true, false);
songText.isMenuItem = true;
songText.targetY = i;
grpMenuShit.add(songText);
}
curSelected = 0;
changeSelection();
}
override function update(elapsed:Float)
{
if (pauseMusic.volume < 0.5)
pauseMusic.volume += 0.01 * elapsed;
super.update(elapsed);
var upP = controls.UI_UP_P;
var downP = controls.UI_DOWN_P;
var accepted = controls.ACCEPT;
if (upP)
{
changeSelection(-1);
}
if (downP)
{
changeSelection(1);
}
if (accepted)
{
var daSelected:String = menuItems[curSelected];
switch (daSelected)
{
case "Resume":
close();
case "EASY" | 'NORMAL' | "HARD":
PlayState.SONG = Song.loadFromJson(Highscore.formatSong(PlayState.SONG.song.toLowerCase(), curSelected),
PlayState.SONG.song.toLowerCase());
PlayState.storyDifficulty = curSelected;
FlxG.resetState();
case 'Toggle Practice Mode':
PlayState.practiceMode = !PlayState.practiceMode;
practiceText.visible = PlayState.practiceMode;
case 'Change Difficulty':
menuItems = difficultyChoices;
regenMenu();
case 'BACK':
menuItems = pauseOG;
regenMenu();
case "Restart Song":
FlxG.resetState();
case "Exit to menu":
PlayState.seenCutscene = false;
PlayState.deathCounter = 0;
if (PlayState.isStoryMode)
FlxG.switchState(new StoryMenuState());
else
FlxG.switchState(new FreeplayState());
}
}
if (FlxG.keys.justPressed.J)
{
// for reference later!
// PlayerSettings.player1.controls.replaceBinding(Control.LEFT, Keys, FlxKey.J, null);
}
}
override function destroy()
{
pauseMusic.destroy();
super.destroy();
}
function changeSelection(change:Int = 0):Void
{
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
curSelected += change;
if (curSelected < 0)
curSelected = menuItems.length - 1;
if (curSelected >= menuItems.length)
curSelected = 0;
var bullShit:Int = 0;
for (item in grpMenuShit.members)
{
item.targetY = bullShit - curSelected;
bullShit++;
item.alpha = 0.6;
// item.setGraphicSize(Std.int(item.width * 0.8));
if (item.targetY == 0)
{
item.alpha = 1;
// item.setGraphicSize(Std.int(item.width));
}
}
}
}

View File

@ -0,0 +1,121 @@
package game.state.subState;
import game.ui.*;
import game.ui.AtlasText.BoldText;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.text.FlxText;
import flixel.util.FlxColor;
class Prompt extends flixel.FlxSubState
{
inline static var MARGIN = 100;
public var onYes:Void->Void;
public var onNo:Void->Void;
public var buttons:TextMenuList;
public var field:AtlasText;
public var back:FlxSprite;
var style:ButtonStyle;
public function new (text:String, style:ButtonStyle = Ok)
{
this.style = style;
super(0x80000000);
buttons = new TextMenuList(Horizontal);
field = new BoldText(text);
field.scrollFactor.set(0, 0);
}
override function create()
{
super.create();
field.y = MARGIN;
field.screenCenter(X);
add(field);
createButtons();
add(buttons);
}
public function createBg(width:Int, height:Int, color = 0xFF808080)
{
back = new FlxSprite();
back.makeGraphic(width, height, color, false, "prompt-bg");
back.screenCenter(XY);
add(back);
members.unshift(members.pop());// bring to front
}
public function createBgFromMargin(margin = MARGIN, color = 0xFF808080)
{
createBg(Std.int(FlxG.width - margin * 2), Std.int(FlxG.height - margin * 2), color);
}
public function setButtons(style:ButtonStyle)
{
if (this.style != style)
{
this.style = style;
createButtons();
}
}
function createButtons()
{
// destroy previous buttons
while(buttons.members.length > 0)
{
buttons.remove(buttons.members[0], true).destroy();
}
switch(style)
{
case Yes_No : createButtonsHelper("yes", "no");
case Ok : createButtonsHelper("ok");
case Custom(yes, no): createButtonsHelper(yes, no);
case None : buttons.exists = false;
};
}
function createButtonsHelper(yes:String, ?no:String)
{
buttons.exists = true;
// pass anonymous functions rather than the current callbacks, in case they change later
var yesButton = buttons.createItem(yes, function() onYes());
yesButton.screenCenter(X);
yesButton.y = FlxG.height - yesButton.height - MARGIN;
yesButton.scrollFactor.set(0, 0);
if (no != null)
{
// place right
yesButton.x = FlxG.width - yesButton.width - MARGIN;
var noButton = buttons.createItem(no, function() onNo());
noButton.x = MARGIN;
noButton.y = FlxG.height - noButton.height - MARGIN;
noButton.scrollFactor.set(0, 0);
}
}
public function setText(text:String)
{
field.text = text;
field.screenCenter(X);
}
}
enum ButtonStyle
{
Ok;
Yes_No;
Custom(yes:String, no:Null<String>);//Todo: more than 2
None;
}

310
source/game/ui/Alphabet.hx Normal file
View File

@ -0,0 +1,310 @@
package game.ui;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxSpriteGroup;
import flixel.math.FlxMath;
import flixel.util.FlxTimer;
using StringTools;
/**
* Loosley based on FlxTypeText lolol
*/
class Alphabet extends FlxSpriteGroup
{
public var delay:Float = 0.05;
public var paused:Bool = false;
// for menu shit
public var targetY:Float = 0;
public var targetX:Float = 0;
public var isMenuItem:Bool = false;
public var text:String = "";
var _finalText:String = "";
var _curText:String = "";
public var widthOfWords:Float = FlxG.width;
var yMulti:Float = 1;
// custom shit
// amp, backslash, question mark, apostrophy, comma, angry faic, period
var lastSprite:AlphaCharacter;
var xPosResetted:Bool = false;
var lastWasSpace:Bool = false;
var splitWords:Array<String> = [];
var isBold:Bool = false;
public function new(x:Float = 0.0, y:Float = 0.0, text:String = "", ?bold:Bool = false, typed:Bool = false)
{
super(x, y);
_finalText = text;
this.text = text;
isBold = bold;
if (text != "")
{
if (typed)
{
startTypedText();
}
else
{
addText();
}
}
}
public function addText()
{
doSplitWords();
var xPos:Float = 0;
for (character in splitWords)
{
// if (character.fastCodeAt() == " ")
// {
// }
if (character == " " || character == "-")
{
lastWasSpace = true;
}
if (AlphaCharacter.alphabet.indexOf(character.toLowerCase()) != -1)
// if (AlphaCharacter.alphabet.contains(character.toLowerCase()))
{
if (lastSprite != null)
{
xPos = lastSprite.x + lastSprite.width;
}
if (lastWasSpace)
{
xPos += 40;
lastWasSpace = false;
}
// var letter:AlphaCharacter = new AlphaCharacter(30 * loopNum, 0);
var letter:AlphaCharacter = new AlphaCharacter(xPos, 0);
if (isBold)
letter.createBold(character);
else
{
letter.createLetter(character);
}
add(letter);
lastSprite = letter;
}
// loopNum += 1;
}
}
function doSplitWords():Void
{
splitWords = _finalText.split("");
}
public var personTalking:String = 'gf';
public function startTypedText():Void
{
_finalText = text;
doSplitWords();
// trace(arrayShit);
var loopNum:Int = 0;
var xPos:Float = 0;
var curRow:Int = 0;
new FlxTimer().start(0.05, function(tmr:FlxTimer)
{
// trace(_finalText.fastCodeAt(loopNum) + " " + _finalText.charAt(loopNum));
if (_finalText.fastCodeAt(loopNum) == "\n".code)
{
yMulti += 1;
xPosResetted = true;
xPos = 0;
curRow += 1;
}
if (splitWords[loopNum] == " ")
{
lastWasSpace = true;
}
#if (haxe >= "4.0.0")
var isNumber:Bool = AlphaCharacter.numbers.contains(splitWords[loopNum]);
var isSymbol:Bool = AlphaCharacter.symbols.contains(splitWords[loopNum]);
#else
var isNumber:Bool = AlphaCharacter.numbers.indexOf(splitWords[loopNum]) != -1;
var isSymbol:Bool = AlphaCharacter.symbols.indexOf(splitWords[loopNum]) != -1;
#end
if (AlphaCharacter.alphabet.indexOf(splitWords[loopNum].toLowerCase()) != -1 || isNumber || isSymbol)
// if (AlphaCharacter.alphabet.contains(splitWords[loopNum].toLowerCase()) || isNumber || isSymbol)
{
if (lastSprite != null && !xPosResetted)
{
lastSprite.updateHitbox();
xPos += lastSprite.width + 3;
// if (isBold)
// xPos -= 80;
}
else
{
xPosResetted = false;
}
if (lastWasSpace)
{
xPos += 20;
lastWasSpace = false;
}
// trace(_finalText.fastCodeAt(loopNum) + " " + _finalText.charAt(loopNum));
// var letter:AlphaCharacter = new AlphaCharacter(30 * loopNum, 0);
var letter:AlphaCharacter = new AlphaCharacter(xPos, 55 * yMulti);
letter.row = curRow;
if (isBold)
{
letter.createBold(splitWords[loopNum]);
}
else
{
if (isNumber)
{
letter.createNumber(splitWords[loopNum]);
}
else if (isSymbol)
{
letter.createSymbol(splitWords[loopNum]);
}
else
{
letter.createLetter(splitWords[loopNum]);
}
letter.x += 90;
}
if (FlxG.random.bool(40))
{
var daSound:String = "GF_";
FlxG.sound.play(Paths.soundRandom(daSound, 1, 4));
}
add(letter);
lastSprite = letter;
}
loopNum += 1;
tmr.time = FlxG.random.float(0.04, 0.09);
}, splitWords.length);
}
override function update(elapsed:Float)
{
if (isMenuItem)
{
var scaledY = FlxMath.remapToRange(targetY, 0, 1, 0, 1.3);
y = CoolUtil.coolLerp(y, (scaledY * 120) + (FlxG.height * 0.48), 0.16);
x = CoolUtil.coolLerp(x, (targetY * 20) + 90, 0.16);
}
super.update(elapsed);
}
}
class AlphaCharacter extends FlxSprite
{
public static var alphabet:String = "abcdefghijklmnopqrstuvwxyz";
public static var numbers:String = "1234567890";
public static var symbols:String = "|~#$%()*+-:;<=>@[]^_.,'!?";
public var row:Int = 0;
public function new(x:Float, y:Float)
{
super(x, y);
var tex = Paths.getSparrowAtlas('alphabet');
frames = tex;
antialiasing = true;
}
public function createBold(letter:String)
{
animation.addByPrefix(letter, letter.toUpperCase() + " bold", 24);
animation.play(letter);
updateHitbox();
}
public function createLetter(letter:String):Void
{
var letterCase:String = "lowercase";
if (letter.toLowerCase() != letter)
{
letterCase = 'capital';
}
animation.addByPrefix(letter, letter + " " + letterCase, 24);
animation.play(letter);
updateHitbox();
FlxG.log.add('the row' + row);
y = (110 - height);
y += row * 60;
}
public function createNumber(letter:String):Void
{
animation.addByPrefix(letter, letter, 24);
animation.play(letter);
updateHitbox();
}
public function createSymbol(letter:String)
{
switch (letter)
{
case '.':
animation.addByPrefix(letter, 'period', 24);
animation.play(letter);
y += 50;
case "'":
animation.addByPrefix(letter, 'apostraphie', 24);
animation.play(letter);
y -= 0;
case "?":
animation.addByPrefix(letter, 'question mark', 24);
animation.play(letter);
case "!":
animation.addByPrefix(letter, 'exclamation point', 24);
animation.play(letter);
}
updateHitbox();
}
}

View File

@ -0,0 +1,80 @@
package game.ui;
import game.ui.MenuList;
import flixel.graphics.frames.FlxAtlasFrames;
typedef AtlasAsset = flixel.util.typeLimit.OneOfTwo<String, FlxAtlasFrames>;
class AtlasMenuList extends MenuTypedList<AtlasMenuItem>
{
public var atlas:FlxAtlasFrames;
public function new (atlas, navControls:NavControls = Vertical, ?wrapMode)
{
super(navControls, wrapMode);
if (Std.isOfType(atlas, String))
this.atlas = Paths.getSparrowAtlas(cast atlas);
else
this.atlas = cast atlas;
}
public function createItem(x = 0.0, y = 0.0, name, callback, fireInstantly = false)
{
var item = new AtlasMenuItem(x, y, name, atlas, callback);
item.fireInstantly = fireInstantly;
return addItem(name, item);
}
override function destroy()
{
super.destroy();
atlas = null;
}
}
class AtlasMenuItem extends MenuItem
{
var atlas:FlxAtlasFrames;
public function new (x = 0.0, y = 0.0, name:String, atlas:FlxAtlasFrames, callback)
{
this.atlas = atlas;
super(x, y, name, callback);
}
override function setData(name:String, ?callback:Void->Void)
{
frames = atlas;
animation.addByPrefix('idle', '$name idle', 24);
animation.addByPrefix('selected', '$name selected', 24);
super.setData(name, callback);
}
function changeAnim(animName:String)
{
animation.play(animName);
updateHitbox();
}
override function idle()
{
changeAnim('idle');
}
override function select()
{
changeAnim('selected');
}
override function get_selected()
{
return animation.curAnim != null && animation.curAnim.name == "selected";
}
override function destroy()
{
super.destroy();
atlas = null;
}
}

262
source/game/ui/AtlasText.hx Normal file
View File

@ -0,0 +1,262 @@
package game.ui;
import flixel.FlxSprite;
import flixel.group.FlxSpriteGroup;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.util.FlxStringUtil;
@:forward
abstract BoldText(AtlasText) from AtlasText to AtlasText
{
inline public function new (x = 0.0, y = 0.0, text:String)
{
this = new AtlasText(x, y, text, Bold);
}
}
/**
* Alphabet.hx has a ton of bugs and does a bunch of stuff I don't need, fuck that class
*/
class AtlasText extends FlxTypedSpriteGroup<AtlasChar>
{
static var fonts = new Map<AtlasFont, AtlasFontData>();
static var casesAllowed = new Map<AtlasFont, Case>();
public var text(default, set):String = "";
var font:AtlasFontData;
public var atlas(get, never):FlxAtlasFrames;
inline function get_atlas() return font.atlas;
public var caseAllowed(get, never):Case;
inline function get_caseAllowed() return font.caseAllowed;
public var maxHeight(get, never):Float;
inline function get_maxHeight() return font.maxHeight;
public function new (x = 0.0, y = 0.0, text:String, fontName:AtlasFont = Default)
{
if (!fonts.exists(fontName))
fonts[fontName] = new AtlasFontData(fontName);
font = fonts[fontName];
super(x, y);
this.text = text;
}
function set_text(value:String)
{
if (value == null)
value = "";
var caseValue = restrictCase(value);
var caseText = restrictCase(this.text);
this.text = value;
if (caseText == caseValue)
return value; // cancel redraw
if (caseValue.indexOf(caseText) == 0)
{
// new text is just old text with additions at the end, append the difference
appendTextCased(caseValue.substr(caseText.length));
return this.text;
}
value = caseValue;
group.kill();
if (value == "")
return this.text;
appendTextCased(caseValue);
return this.text;
}
/**
* Adds new characters, without needing to redraw the previous characters
* @param text The text to add.
* @throws String if `text` is null.
*/
public function appendText(text:String)
{
if (text == null)
throw "cannot append null";
if (text == "")
return;
this.text = this.text + text;
}
/**
* Converts all characters to fit the font's `allowedCase`.
* @param text
*/
function restrictCase(text:String)
{
return switch(caseAllowed)
{
case Both: text;
case Upper: text.toUpperCase();
case Lower: text.toLowerCase();
}
}
/**
* Adds new text on top of the existing text. Helper for other methods; DOESN'T CHANGE `this.text`.
* @param text The text to add, assumed to match the font's `caseAllowed`.
*/
function appendTextCased(text:String)
{
var charCount = group.countLiving();
var xPos:Float = 0;
var yPos:Float = 0;
// `countLiving` returns -1 if group is empty
if (charCount == -1)
charCount = 0;
else if (charCount > 0)
{
var lastChar = group.members[charCount - 1];
xPos = lastChar.x + lastChar.width - x;
yPos = lastChar.y + lastChar.height - maxHeight - y;
}
var splitValues = text.split("");
for (i in 0...splitValues.length)
{
switch(splitValues[i])
{
case " ":
{
xPos += 40;
}
case "\n":
{
xPos = 0;
yPos += maxHeight;
}
case char:
{
var charSprite:AtlasChar;
if (group.members.length <= charCount)
charSprite = new AtlasChar(atlas, char);
else
{
charSprite = group.members[charCount];
charSprite.revive();
charSprite.char = char;
charSprite.alpha = 1;//gets multiplied when added
}
charSprite.x = xPos;
charSprite.y = yPos + maxHeight - charSprite.height;
add(charSprite);
xPos += charSprite.width;
charCount++;
}
}
}
}
override function toString()
{
return "InputItem, " + FlxStringUtil.getDebugString(
[ LabelValuePair.weak("x", x)
, LabelValuePair.weak("y", y)
, LabelValuePair.weak("text", text)
]
);
}
}
class AtlasChar extends FlxSprite
{
public var char(default, set):String;
public function new(x = 0.0, y = 0.0, atlas:FlxAtlasFrames, char:String)
{
super(x, y);
frames = atlas;
this.char = char;
antialiasing = true;
}
function set_char(value:String)
{
if (this.char != value)
{
var prefix = getAnimPrefix(value);
animation.addByPrefix("anim", prefix, 24);
animation.play("anim");
updateHitbox();
}
return this.char = value;
}
function getAnimPrefix(char:String)
{
return switch (char)
{
case '-': '-dash-';
case '.': '-period-';
case ",": '-comma-';
case "'": '-apostraphie-';
case "?": '-question mark-';
case "!": '-exclamation point-';
case "\\": '-back slash-';
case "/": '-forward slash-';
case "*": '-multiply x-';
case "": '-start quote-';
case "": '-end quote-';
default: char;
}
}
}
private class AtlasFontData
{
static public var upperChar = ~/^[A-Z]\d+$/;
static public var lowerChar = ~/^[a-z]\d+$/;
public var atlas:FlxAtlasFrames;
public var maxHeight:Float = 0.0;
public var caseAllowed:Case = Both;
public function new (name:AtlasFont)
{
atlas = Paths.getSparrowAtlas("fonts/" + name.getName().toLowerCase());
atlas.parent.destroyOnNoUse = false;
atlas.parent.persist = true;
var containsUpper = false;
var containsLower = false;
for (frame in atlas.frames)
{
maxHeight = Math.max(maxHeight, frame.frame.height);
if (!containsUpper)
containsUpper = upperChar.match(frame.name);
if (!containsLower)
containsLower = lowerChar.match(frame.name);
}
if (containsUpper != containsLower)
caseAllowed = containsUpper ? Upper : Lower;
}
}
enum Case
{
Both;
Upper;
Lower;
}
enum AtlasFont
{
Default;
Bold;
}

View File

@ -0,0 +1,71 @@
package game.ui;
import flixel.FlxG;
import flixel.addons.effects.chainable.FlxEffectSprite;
import flixel.addons.effects.chainable.FlxOutlineEffect;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.util.FlxColor;
class ColorsMenu extends ui.OptionsState.Page
{
var curSelected:Int = 0;
var grpNotes:FlxTypedGroup<Note>;
public function new()
{
super();
grpNotes = new FlxTypedGroup<Note>();
add(grpNotes);
for (i in 0...4)
{
var note:Note = new Note(0, i);
note.x = (100 * i) + i;
note.screenCenter(Y);
var _effectSpr:FlxEffectSprite = new FlxEffectSprite(note, [new FlxOutlineEffect(FlxOutlineMode.FAST, FlxColor.WHITE, 4, 1)]);
add(_effectSpr);
_effectSpr.y = 0;
_effectSpr.x = i * 130;
_effectSpr.antialiasing = true;
_effectSpr.scale.x = _effectSpr.scale.y = 0.7;
// _effectSpr.setGraphicSize();
_effectSpr.height = note.height;
_effectSpr.width = note.width;
// _effectSpr.updateHitbox();
grpNotes.add(note);
}
}
override function update(elapsed:Float)
{
if (controls.UI_RIGHT_P)
curSelected += 1;
if (controls.UI_LEFT_P)
curSelected -= 1;
if (curSelected < 0)
curSelected = grpNotes.members.length - 1;
if (curSelected >= grpNotes.members.length)
curSelected = 0;
if (controls.UI_UP)
{
grpNotes.members[curSelected].colorSwap.update(elapsed * 0.3);
Note.arrowColors[curSelected] += elapsed * 0.3;
}
if (controls.UI_DOWN)
{
grpNotes.members[curSelected].colorSwap.update(-elapsed * 0.3);
Note.arrowColors[curSelected] += -elapsed * 0.3;
}
super.update(elapsed);
}
}

369
source/game/ui/MenuList.hx Normal file
View File

@ -0,0 +1,369 @@
package game.ui;
import flixel.math.FlxPoint;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.effects.FlxFlicker;
import flixel.group.FlxGroup;
import flixel.util.FlxSignal;
import game.data.PlayerSettings;
class MenuTypedList<T:MenuItem> extends FlxTypedGroup<T>
{
public var selectedIndex(default, null) = 0;
public var selectedItem(get, never):T;
/** Called when a new item is highlighted */
public var onChange(default, null) = new FlxTypedSignal<T->Void>();
/** Called when an item is accepted */
public var onAcceptPress(default, null) = new FlxTypedSignal<T->Void>();
/** The navigation control scheme to use */
public var navControls:NavControls;
/** Set to false to disable nav control */
public var enabled:Bool = true;
/** */
public var wrapMode:WrapMode = Both;
var byName = new Map<String, T>();
/** Set to true, internally to disable controls, without affecting vars like `enabled` */
public var busy(default, null):Bool = false;
// bit awkward because BACK is also a menu control and this doesn't affect that
public function new (navControls:NavControls = Vertical, ?wrapMode:WrapMode)
{
this.navControls = navControls;
if (wrapMode != null)
this.wrapMode = wrapMode;
else
this.wrapMode = switch (navControls)
{
case Horizontal: Horizontal;
case Vertical: Vertical;
default: Both;
}
super();
}
public function addItem(name:String, item:T):T
{
if (length == selectedIndex)
item.select();
byName[name] = item;
return add(item);
}
public function resetItem(oldName:String, newName:String, ?callback:Void->Void):T
{
if (!byName.exists(oldName))
throw "No item named:" + oldName;
var item = byName[oldName];
byName.remove(oldName);
byName[newName] = item;
item.setItem(newName, callback);
return item;
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (enabled && !busy)
updateControls();
}
inline function updateControls()
{
var controls = PlayerSettings.player1.controls;
var wrapX = wrapMode.match(Horizontal | Both);
var wrapY = wrapMode.match(Vertical | Both);
var newIndex = switch(navControls)
{
case Vertical : navList(controls.UI_UP_P , controls.UI_DOWN_P, wrapY);
case Horizontal : navList(controls.UI_LEFT_P, controls.UI_RIGHT_P, wrapX);
case Both : navList(controls.UI_LEFT_P || controls.UI_UP_P, controls.UI_RIGHT_P || controls.UI_DOWN_P, !wrapMode.match(None));
case Columns(num): navGrid(num, controls.UI_LEFT_P, controls.UI_RIGHT_P, wrapX, controls.UI_UP_P , controls.UI_DOWN_P , wrapY);
case Rows (num): navGrid(num, controls.UI_UP_P , controls.UI_DOWN_P , wrapY, controls.UI_LEFT_P, controls.UI_RIGHT_P, wrapX);
}
if (newIndex != selectedIndex)
{
FlxG.sound.play(Paths.sound('scrollMenu'));
selectItem(newIndex);
}
//Todo: bypass popup blocker on firefox
if (controls.ACCEPT)
accept();
}
function navAxis(index:Int, size:Int, prev:Bool, next:Bool, allowWrap:Bool):Int
{
if (prev == next)
return index;
if (prev)
{
if (index > 0)
index--;
else if (allowWrap)
index = size - 1;
}
else
{
if (index < size - 1)
index++;
else if (allowWrap)
index = 0;
}
return index;
}
/**
* Controls navigation on a linear list of items such as Vertical.
* @param prev
* @param next
* @param allowWrap
*/
inline function navList(prev:Bool, next:Bool, allowWrap:Bool)
{
return navAxis(selectedIndex, length, prev, next, allowWrap);
}
/**
* Controls navigation on a grid
* @param latSize The size of the fixed axis of the grid, or the "lateral axis"
* @param latPrev Whether the 'prev' key is pressed along the fixed-lengthed axis. eg: "left" in Column mode
* @param latNext Whether the 'next' key is pressed along the fixed-lengthed axis. eg: "right" in Column mode
* @param prev Whether the 'prev' key is pressed along the variable-lengthed axis. eg: "up" in Column mode
* @param next Whether the 'next' key is pressed along the variable-lengthed axis. eg: "down" in Column mode
* @param allowWrap unused
*/
function navGrid(latSize:Int, latPrev:Bool, latNext:Bool, latAllowWrap:Bool, prev:Bool, next:Bool, allowWrap:Bool):Int
{
// The grid lenth along the variable-length axis
var size = Math.ceil(length / latSize);
// The selected position along the variable-length axis
var index = Math.floor(selectedIndex / latSize);
// The selected position along the fixed axis
var latIndex = selectedIndex % latSize;
latIndex = navAxis(latIndex, latSize, latPrev, latNext, latAllowWrap);
index = navAxis(index, size, prev, next, allowWrap);
return Std.int(Math.min(length - 1, index * latSize + latIndex));
}
public function accept()
{
var selected = members[selectedIndex];
onAcceptPress.dispatch(selected);
if (selected.fireInstantly)
selected.callback();
else
{
busy = true;
FlxG.sound.play(Paths.sound('confirmMenu'));
FlxFlicker.flicker(selected, 1, 0.06, true, false, function(_)
{
busy = false;
selected.callback();
});
}
}
public function selectItem(index:Int)
{
members[selectedIndex].idle();
selectedIndex = index;
var selected = members[selectedIndex];
selected.select();
onChange.dispatch(selected);
}
public function has(name:String)
{
return byName.exists(name);
}
public function getItem(name:String)
{
return byName[name];
}
override function destroy()
{
super.destroy();
byName.clear();
onChange.removeAll();
onAcceptPress.removeAll();
}
inline function get_selectedItem():T
{
return members[selectedIndex];
}
}
class MenuItem extends FlxSprite
{
public var callback:Void->Void;
public var name:String;
/**
* Set to true for things like opening URLs otherwise, it may it get blocked.
*/
public var fireInstantly = false;
public var selected(get, never):Bool;
function get_selected() return alpha == 1.0;
public function new (x = 0.0, y = 0.0, name:String, callback)
{
super(x, y);
antialiasing = true;
setData(name, callback);
idle();
}
function setData(name:String, ?callback:Void->Void)
{
this.name = name;
if (callback != null)
this.callback = callback;
}
/**
* Calls setData and resets/redraws the state of the item
* @param name the label.
* @param callback Unchanged if null.
*/
public function setItem(name:String, ?callback:Void->Void)
{
setData(name, callback);
if (selected)
select();
else
idle();
}
public function idle()
{
alpha = 0.6;
}
public function select()
{
alpha = 1.0;
}
}
class MenuTypedItem<T:FlxSprite> extends MenuItem
{
public var label(default, set):T;
public function new (x = 0.0, y = 0.0, label:T, name:String, callback)
{
super(x, y, name, callback);
// set label after super otherwise setters fuck up
this.label = label;
}
/**
* Use this when you only want to show the label
*/
function setEmptyBackground()
{
var oldWidth = width;
var oldHeight = height;
makeGraphic(1, 1, 0x0);
width = oldWidth;
height = oldHeight;
}
function set_label(value:T)
{
if (value != null)
{
value.x = x;
value.y = y;
value.alpha = alpha;
}
return this.label = value;
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (label != null)
label.update(elapsed);
}
override function draw()
{
super.draw();
if (label != null)
{
label.cameras = cameras;
label.scrollFactor.copyFrom(scrollFactor);
label.draw();
}
}
override function set_alpha(value:Float):Float
{
super.set_alpha(value);
if (label != null)
label.alpha = alpha;
return alpha;
}
override function set_x(value:Float):Float
{
super.set_x(value);
if (label != null)
label.x = x;
return x;
}
override function set_y(Value:Float):Float
{
super.set_y(Value);
if (label != null)
label.y = y;
return y;
}
}
enum NavControls
{
Horizontal;
Vertical;
Both;
Columns(num:Int);
Rows(num:Int);
}
enum WrapMode
{
Horizontal;
Vertical;
Both;
None;
}

159
source/game/ui/ModMenu.hx Normal file
View File

@ -0,0 +1,159 @@
package game.ui;
import flixel.FlxG;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.text.FlxText;
import flixel.util.FlxColor;
#if cpp
import polymod.Polymod;
import sys.FileSystem;
#end
import game.state.menus.options.OptionsState;
import game.state.menus.options.OptionsState.Page;
class ModMenu extends OptionsState.Page
{
var grpMods:FlxTypedGroup<ModMenuItem>;
var enabledMods:Array<String> = [];
var modFolders:Array<String> = [];
var curSelected:Int = 0;
public function new():Void
{
super();
grpMods = new FlxTypedGroup<ModMenuItem>();
add(grpMods);
refreshModList();
}
override function update(elapsed:Float)
{
if (FlxG.keys.justPressed.R)
refreshModList();
selections();
if (controls.UI_UP_P)
selections(-1);
if (controls.UI_DOWN_P)
selections(1);
if (FlxG.keys.justPressed.SPACE)
grpMods.members[curSelected].modEnabled = !grpMods.members[curSelected].modEnabled;
if (FlxG.keys.justPressed.I && curSelected != 0)
{
var oldOne = grpMods.members[curSelected - 1];
grpMods.members[curSelected - 1] = grpMods.members[curSelected];
grpMods.members[curSelected] = oldOne;
selections(-1);
}
if (FlxG.keys.justPressed.K && curSelected < grpMods.members.length - 1)
{
var oldOne = grpMods.members[curSelected + 1];
grpMods.members[curSelected + 1] = grpMods.members[curSelected];
grpMods.members[curSelected] = oldOne;
selections(1);
}
super.update(elapsed);
}
private function selections(change:Int = 0):Void
{
curSelected += change;
if (curSelected >= modFolders.length)
curSelected = 0;
if (curSelected < 0)
curSelected = modFolders.length - 1;
for (txt in 0...grpMods.length)
{
if (txt == curSelected)
{
grpMods.members[txt].color = FlxColor.YELLOW;
}
else
grpMods.members[txt].color = FlxColor.WHITE;
}
organizeByY();
}
inline static var MOD_PATH = "./mods";
private function refreshModList():Void
{
while (grpMods.members.length > 0)
{
grpMods.remove(grpMods.members[0], true);
}
#if desktop
var modList = [];
modFolders = [];
trace("mods path:" + FileSystem.absolutePath(MOD_PATH));
if (!FileSystem.exists(MOD_PATH))
{
FlxG.log.warn("missing mods folder, expected: " + FileSystem.absolutePath(MOD_PATH));
return;
}
for (file in FileSystem.readDirectory(MOD_PATH))
{
if (FileSystem.isDirectory(MOD_PATH + file))
modFolders.push(file);
}
enabledMods = [];
modList = Polymod.scan(MOD_PATH);
trace(modList);
var loopNum:Int = 0;
for (i in modFolders)
{
var txt:ModMenuItem = new ModMenuItem(0, 10 + (40 * loopNum), 0, i, 32);
txt.text = i;
grpMods.add(txt);
loopNum++;
}
#end
}
private function organizeByY():Void
{
for (i in 0...grpMods.length)
{
grpMods.members[i].y = 10 + (40 * i);
}
}
}
class ModMenuItem extends FlxText
{
public var modEnabled:Bool = false;
public var daMod:String;
public function new(x:Float, y:Float, w:Float, str:String, size:Int)
{
super(x, y, w, str, size);
}
override function update(elapsed:Float)
{
if (modEnabled)
alpha = 1;
else
alpha = 0.5;
super.update(elapsed);
}
}

View File

@ -0,0 +1,58 @@
package game.ui;
import game.ui.AtlasText.AtlasFont;
import game.ui.MenuList.MenuTypedItem;
import game.ui.MenuList.MenuTypedList;
import game.ui.MenuList.NavControls;
class TextMenuList extends MenuTypedList<TextMenuItem>
{
public function new(navControls:NavControls = Vertical, ?wrapMode)
{
super(navControls, wrapMode);
}
public function createItem(x = 0.0, y = 0.0, name:String, font:AtlasFont = Bold, callback, fireInstantly = false)
{
var item = new TextMenuItem(x, y, name, font, callback);
item.fireInstantly = fireInstantly;
return addItem(name, item);
}
}
class TextMenuItem extends TextTypedMenuItem<AtlasText>
{
public function new(x = 0.0, y = 0.0, name:String, font:AtlasFont = Bold, callback)
{
super(x, y, new AtlasText(0, 0, name, font), name, callback);
setEmptyBackground();
}
}
class TextTypedMenuItem<T:AtlasText> extends MenuTypedItem<T>
{
public function new(x = 0.0, y = 0.0, label:T, name:String, callback)
{
super(x, y, label, name, callback);
}
override function setItem(name:String, ?callback:Void->Void)
{
if (label != null)
{
label.text = name;
label.alpha = alpha;
width = label.width;
height = label.height;
}
super.setItem(name, callback);
}
override function set_label(value:T):T
{
super.set_label(value);
setItem(name, callback);
return value;
}
}

View File

@ -0,0 +1,277 @@
package game.ui.gameplay;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.text.FlxTypeText;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxSpriteGroup;
import flixel.input.FlxKeyManager;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import game.state.*;
using StringTools;
class DialogueBox extends FlxSpriteGroup
{
var box:FlxSprite;
var curCharacter:String = '';
var dialogue:Alphabet;
var dialogueList:Array<String> = [];
// SECOND DIALOGUE FOR THE PIXEL SHIT INSTEAD???
var swagDialogue:FlxTypeText;
var dropText:FlxText;
public var finishThing:Void->Void;
var portraitLeft:FlxSprite;
var portraitRight:FlxSprite;
var handSelect:FlxSprite;
var bgFade:FlxSprite;
public function new(talkingRight:Bool = true, ?dialogueList:Array<String>)
{
super();
switch (PlayState.SONG.song.toLowerCase())
{
case 'senpai':
FlxG.sound.playMusic(Paths.music('Lunchbox'), 0);
FlxG.sound.music.fadeIn(1, 0, 0.8);
case 'thorns':
FlxG.sound.playMusic(Paths.music('LunchboxScary'), 0);
FlxG.sound.music.fadeIn(1, 0, 0.8);
}
bgFade = new FlxSprite(-200, -200).makeGraphic(Std.int(FlxG.width * 1.3), Std.int(FlxG.height * 1.3), 0xFFB3DFd8);
bgFade.scrollFactor.set();
bgFade.alpha = 0;
add(bgFade);
new FlxTimer().start(0.83, function(tmr:FlxTimer)
{
bgFade.alpha += (1 / 5) * 0.7;
if (bgFade.alpha > 0.7)
bgFade.alpha = 0.7;
}, 5);
portraitLeft = new FlxSprite(-20, 40);
portraitLeft.frames = Paths.getSparrowAtlas('weeb/senpaiPortrait');
portraitLeft.animation.addByPrefix('enter', 'Senpai Portrait Enter', 24, false);
portraitLeft.setGraphicSize(Std.int(portraitLeft.width * PlayState.daPixelZoom * 0.9));
portraitLeft.updateHitbox();
portraitLeft.scrollFactor.set();
add(portraitLeft);
portraitLeft.visible = false;
portraitRight = new FlxSprite(0, 40);
portraitRight.frames = Paths.getSparrowAtlas('weeb/bfPortrait');
portraitRight.animation.addByPrefix('enter', 'Boyfriend portrait enter', 24, false);
portraitRight.setGraphicSize(Std.int(portraitRight.width * PlayState.daPixelZoom * 0.9));
portraitRight.updateHitbox();
portraitRight.scrollFactor.set();
add(portraitRight);
portraitRight.visible = false;
box = new FlxSprite(-20, 45);
var hasDialog = false;
switch (PlayState.SONG.song.toLowerCase())
{
case 'senpai':
hasDialog = true;
box.frames = Paths.getSparrowAtlas('weeb/pixelUI/dialogueBox-pixel');
box.animation.addByPrefix('normalOpen', 'Text Box Appear', 24, false);
box.animation.addByIndices('normal', 'Text Box Appear', [4], "", 24);
case 'roses':
hasDialog = true;
FlxG.sound.play(Paths.sound('ANGRY_TEXT_BOX'));
box.frames = Paths.getSparrowAtlas('weeb/pixelUI/dialogueBox-senpaiMad');
box.animation.addByPrefix('normalOpen', 'SENPAI ANGRY IMPACT SPEECH', 24, false);
box.animation.addByIndices('normal', 'SENPAI ANGRY IMPACT SPEECH', [4], "", 24);
case 'thorns':
hasDialog = true;
box.frames = Paths.getSparrowAtlas('weeb/pixelUI/dialogueBox-evil');
box.animation.addByPrefix('normalOpen', 'Spirit Textbox spawn', 24, false);
box.animation.addByIndices('normal', 'Spirit Textbox spawn', [11], "", 24);
var face:FlxSprite = new FlxSprite(320, 170).loadGraphic(Paths.image('weeb/spiritFaceForward'));
face.setGraphicSize(Std.int(face.width * 6));
add(face);
}
this.dialogueList = dialogueList;
if (!hasDialog)
return;
box.animation.play('normalOpen');
box.setGraphicSize(Std.int(box.width * PlayState.daPixelZoom * 0.9));
box.updateHitbox();
add(box);
box.screenCenter(X);
portraitLeft.screenCenter(X);
handSelect = new FlxSprite(1042, 590).loadGraphic(Paths.image('weeb/pixelUI/hand_textbox'));
handSelect.setGraphicSize(Std.int(handSelect.width * PlayState.daPixelZoom * 0.9));
handSelect.updateHitbox();
handSelect.visible = false;
add(handSelect);
if (!talkingRight)
{
// box.flipX = true;
}
dropText = new FlxText(242, 502, Std.int(FlxG.width * 0.6), "", 32);
dropText.font = 'Pixel Arial 11 Bold';
dropText.color = 0xFFD89494;
add(dropText);
swagDialogue = new FlxTypeText(240, 500, Std.int(FlxG.width * 0.6), "", 32);
swagDialogue.font = 'Pixel Arial 11 Bold';
swagDialogue.color = 0xFF3F2021;
swagDialogue.sounds = [FlxG.sound.load(Paths.sound('pixelText'), 0.6)];
add(swagDialogue);
dialogue = new Alphabet(0, 80, "", false, true);
// dialogue.x = 90;
// add(dialogue);
}
var dialogueOpened:Bool = false;
var dialogueStarted:Bool = false;
var dialogueEnded:Bool = false;
override function update(elapsed:Float)
{
// HARD CODING CUZ IM STUPDI
if (PlayState.SONG.song.toLowerCase() == 'roses')
portraitLeft.visible = false;
if (PlayState.SONG.song.toLowerCase() == 'thorns')
{
portraitLeft.color = FlxColor.BLACK;
swagDialogue.color = FlxColor.WHITE;
dropText.color = FlxColor.BLACK;
}
dropText.text = swagDialogue.text;
if (box.animation.curAnim != null)
{
if (box.animation.curAnim.name == 'normalOpen' && box.animation.curAnim.finished)
{
box.animation.play('normal');
dialogueOpened = true;
}
}
if (dialogueOpened && !dialogueStarted)
{
startDialogue();
dialogueStarted = true;
}
if (FlxG.keys.justPressed.ANY && dialogueEnded)
{
remove(dialogue);
FlxG.sound.play(Paths.sound('clickText'), 0.8);
if (dialogueList[1] == null && dialogueList[0] != null)
{
if (!isEnding)
{
isEnding = true;
if (PlayState.SONG.song.toLowerCase() == 'senpai' || PlayState.SONG.song.toLowerCase() == 'thorns')
FlxG.sound.music.fadeOut(2.2, 0);
new FlxTimer().start(0.2, function(tmr:FlxTimer)
{
box.alpha -= 1 / 5;
bgFade.alpha -= 1 / 5 * 0.7;
portraitLeft.visible = false;
portraitRight.visible = false;
swagDialogue.alpha -= 1 / 5;
handSelect.alpha -= 1 / 5;
dropText.alpha = swagDialogue.alpha;
}, 5);
new FlxTimer().start(1.2, function(tmr:FlxTimer)
{
finishThing();
kill();
});
}
}
else
{
dialogueList.remove(dialogueList[0]);
startDialogue();
}
}
else if (FlxG.keys.justPressed.ANY && dialogueStarted)
swagDialogue.skip();
super.update(elapsed);
}
var isEnding:Bool = false;
function startDialogue():Void
{
cleanDialog();
// var theDialog:Alphabet = new Alphabet(0, 70, dialogueList[0], false, true);
// dialogue = theDialog;
// add(theDialog);
// swagDialogue.text = ;
swagDialogue.resetText(dialogueList[0]);
swagDialogue.start(0.04);
swagDialogue.completeCallback = function()
{
trace("dialogue finish");
handSelect.visible = true;
dialogueEnded = true;
};
handSelect.visible = false;
dialogueEnded = false;
switch (curCharacter)
{
case 'dad':
portraitRight.visible = false;
if (!portraitLeft.visible)
{
portraitLeft.visible = true;
portraitLeft.animation.play('enter');
}
case 'bf':
portraitLeft.visible = false;
if (!portraitRight.visible)
{
portraitRight.visible = true;
portraitRight.animation.play('enter');
}
}
}
function cleanDialog():Void
{
var splitName:Array<String> = dialogueList[0].split(":");
curCharacter = splitName[1];
dialogueList[0] = dialogueList[0].substr(splitName[1].length + 2).trim();
}
}

View File

@ -0,0 +1,169 @@
package game.ui.gameplay;
import flixel.FlxG;
import flixel.FlxBasic;
import flixel.FlxSprite;
import flixel.text.FlxText;
import flixel.math.FlxMath;
import flixel.ui.FlxBar;
import flixel.util.FlxColor;
import flixel.group.FlxGroup.FlxTypedGroup;
import game.state.PlayState;
import game.state.menus.options.PreferencesMenu;
using StringTools;
/*
Class For The Games UI.
Yet another Forever Engine Moment
- Zyflx
*/
class GameUI extends FlxTypedGroup<FlxBasic>
{
var scoreTxt:FlxText;
var watermark:FlxText;
var healthBarBG:FlxSprite;
var healthBar:FlxBar;
var iconP1:HealthIcon;
var iconP2:HealthIcon;
var Song = PlayState.SONG.song;
// var health = PlayState.health;
// Accuracy Shit
var notesHit:Float = 0.0;
var notesPlayed:Int = 0;
var accuracy:Float;
var rankStr:String = 'N/A';
var rankArray:Array<Dynamic> = [
[100, 'SS'],
[95, 'S'],
[90, 'A'],
[85, 'B'],
[80, 'C'],
[75, 'D'],
[70, 'E'],
[65, 'F']
];
public var ratingMap:Map<String, Float> = [
'sick' => 1,
'good' => 0.67,
'bad' => 0.34,
'shit' => 0
];
public function new()
{
super();
healthBarBG = new FlxSprite(0, FlxG.height * 0.9).loadGraphic(Paths.image('healthBar'));
healthBarBG.screenCenter(X);
healthBarBG.scrollFactor.set();
add(healthBarBG);
if (PreferencesMenu.getPref('downscroll')) healthBarBG.y = FlxG.height * 0.1;
healthBar = new FlxBar(healthBarBG.x + 4, healthBarBG.y + 4, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), PlayState,
'health', 0, 2);
healthBar.scrollFactor.set();
healthBar.createFilledBar(0xFFFF0000, 0xFF66FF33);
add(healthBar);
iconP1 = new HealthIcon(PlayState.SONG.player1, true);
iconP1.y = healthBar.y - (iconP1.height / 2);
add(iconP1);
iconP2 = new HealthIcon(PlayState.SONG.player2, false);
iconP2.y = healthBar.y - (iconP2.height / 2);
add(iconP2);
scoreTxt = new FlxText(0, healthBarBG.y + 40, FlxG.width, "", 20);
scoreTxt.setFormat(Paths.font("vcr.ttf"), 20, FlxColor.WHITE, CENTER, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
scoreTxt.scrollFactor.set();
scoreTxt.borderSize = 1.2;
add(scoreTxt);
updateScoreTxt();
var songName = Song.replace('-', " ");
var diffName = CoolUtil.difficultyString();
watermark = new FlxText(0, (PreferencesMenu.getPref('downscroll') ? FlxG.height - 40 : 10), 0, '', 30);
watermark.setFormat(Paths.font('vcr.ttf'), 30, FlxColor.WHITE);
watermark.setBorderStyle(OUTLINE, FlxColor.BLACK, 1.4);
watermark.text = '~ $songName - ($diffName) ~';
watermark.screenCenter(X);
add(watermark);
}
override public function update(elapsed:Float)
{
// healthBar.percent = health;
if (FlxG.keys.justPressed.NINE) iconP1.swapOldIcon();
iconP1.scale.set(FlxMath.lerp(1, iconP1.scale.x, CoolUtil.boundTo(1 - (elapsed * 11), 0, 1)), FlxMath.lerp(1, iconP1.scale.y, CoolUtil.boundTo(1 - (elapsed * 11), 0, 1)));
iconP2.scale.set(FlxMath.lerp(1, iconP2.scale.x, CoolUtil.boundTo(1 - (elapsed * 11), 0, 1)), FlxMath.lerp(1, iconP2.scale.y, CoolUtil.boundTo(1 - (elapsed * 11), 0, 1)));
iconP1.updateHitbox();
iconP2.updateHitbox();
var iconOffset:Int = 26;
iconP1.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 100, 0) * 0.01) - iconOffset);
iconP2.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 100, 0) * 0.01)) - (iconP2.width - iconOffset);
iconP1.animation.curAnim.curFrame = (healthBar.percent < 20 ? 1 : 0);
iconP2.animation.curAnim.curFrame = (healthBar.percent > 80 ? 1 : 0);
super.update(elapsed);
}
public function updateScoreTxt()
{
var acc:Float = Math.floor(accuracy * 10000) / 100;
updateRank(acc);
scoreTxt.text = 'Score: ' + PlayState.songScore + ' - Misses: ' + PlayState.songMisses +
' - Accuracy: [$acc% | $rankStr]';
}
// Accuracy Shit Part 2
public function updateAcc(rating:Float, ?isMiss:Bool = false)
{
if (!isMiss) notesHit += rating;
notesPlayed++;
accuracy = Math.min(1, Math.max(0, notesHit / notesPlayed));
updateScoreTxt();
}
function updateRank(accuracy:Float)
{
for (i in 0...rankArray.length)
{
if (rankArray[i][0] <= accuracy)
{
rankStr = rankArray[i][1];
break;
}
}
}
public function iconBeat()
{
iconP1.setGraphicSize(Std.int(iconP1.width + 30));
iconP2.setGraphicSize(Std.int(iconP2.width + 30));
iconP1.updateHitbox();
iconP2.updateHitbox();
}
}

View File

@ -0,0 +1,65 @@
package game.ui.gameplay;
import game.state.PlayState;
import flixel.FlxSprite;
using StringTools;
class HealthIcon extends FlxSprite
{
/**
* Used for FreeplayState! If you use it elsewhere, prob gonna annoying
*/
public var sprTracker:FlxSprite;
var char:String = '';
var isPlayer:Bool = false;
public function new(char:String = 'bf', isPlayer:Bool = false)
{
super();
this.isPlayer = isPlayer;
changeIcon(char);
antialiasing = true;
scrollFactor.set();
}
public var isOldIcon:Bool = false;
public function swapOldIcon():Void
{
isOldIcon = !isOldIcon;
if (isOldIcon)
changeIcon('bf-old');
else
changeIcon(PlayState.SONG.player1);
}
public function changeIcon(newChar:String):Void
{
if (newChar != 'bf-pixel' && newChar != 'bf-old')
newChar = newChar.split('-')[0].trim();
if (newChar != char)
{
if (animation.getByName(newChar) == null)
{
loadGraphic(Paths.image('icons/icon-' + newChar), true, 150, 150);
animation.add(newChar, [0, 1], 0, false, isPlayer);
}
animation.play(newChar);
char = newChar;
}
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (sprTracker != null)
setPosition(sprTracker.x + sprTracker.width + 10, sprTracker.y - 30);
}
}

View File

@ -0,0 +1,241 @@
package game.ui.gameplay.note;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.math.FlxMath;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import game.objects.shaders.ColorSwap;
import game.state.menus.options.PreferencesMenu;
import game.state.PlayState;
import game.data.backend.Conductor;
using StringTools;
#if polymod
import polymod.format.ParseRules.TargetSignatureElement;
#end
class Note extends FlxSprite
{
public var strumTime:Float = 0;
public var mustPress:Bool = false;
public var noteData:Int = 0;
public var canBeHit:Bool = false;
public var tooLate:Bool = false;
public var wasGoodHit:Bool = false;
public var prevNote:Note;
private var willMiss:Bool = false;
public var altNote:Bool = false;
public var invisNote:Bool = false;
public var sustainLength:Float = 0;
public var isSustainNote:Bool = false;
public var colorSwap:ColorSwap;
public var noteScore:Float = 1;
public static var swagWidth:Float = 160 * 0.7;
public static var PURP_NOTE:Int = 0;
public static var GREEN_NOTE:Int = 2;
public static var BLUE_NOTE:Int = 1;
public static var RED_NOTE:Int = 3;
public static var arrowColors:Array<Float> = [1, 1, 1, 1];
public function new(strumTime:Float, noteData:Int, ?prevNote:Note, ?sustainNote:Bool = false)
{
super();
if (prevNote == null)
prevNote = this;
this.prevNote = prevNote;
isSustainNote = sustainNote;
x += 98.5;
// MAKE SURE ITS DEFINITELY OFF SCREEN?
y -= 2000;
this.strumTime = strumTime;
this.noteData = noteData;
if (PlayState.isPixel)
{
loadGraphic(Paths.image('weeb/pixelUI/arrows-pixels'), true, 17, 17);
animation.add('greenScroll', [6]);
animation.add('redScroll', [7]);
animation.add('blueScroll', [5]);
animation.add('purpleScroll', [4]);
if (isSustainNote)
{
loadGraphic(Paths.image('weeb/pixelUI/arrowEnds'), true, 7, 6);
animation.add('purpleholdend', [4]);
animation.add('greenholdend', [6]);
animation.add('redholdend', [7]);
animation.add('blueholdend', [5]);
animation.add('purplehold', [0]);
animation.add('greenhold', [2]);
animation.add('redhold', [3]);
animation.add('bluehold', [1]);
}
setGraphicSize(Std.int(width * PlayState.daPixelZoom));
updateHitbox();
}
else
{
frames = Paths.getSparrowAtlas('NOTE_assets');
animation.addByPrefix('greenScroll', 'green instance');
animation.addByPrefix('redScroll', 'red instance');
animation.addByPrefix('blueScroll', 'blue instance');
animation.addByPrefix('purpleScroll', 'purple instance');
animation.addByPrefix('purpleholdend', 'pruple end hold');
animation.addByPrefix('greenholdend', 'green hold end');
animation.addByPrefix('redholdend', 'red hold end');
animation.addByPrefix('blueholdend', 'blue hold end');
animation.addByPrefix('purplehold', 'purple hold piece');
animation.addByPrefix('greenhold', 'green hold piece');
animation.addByPrefix('redhold', 'red hold piece');
animation.addByPrefix('bluehold', 'blue hold piece');
setGraphicSize(Std.int(width * 0.7));
updateHitbox();
antialiasing = true;
// colorSwap.colorToReplace = 0xFFF9393F;
// colorSwap.newColor = 0xFF00FF00;
// color = FlxG.random.color();
// color.saturation *= 4;
// replaceColor(0xFFC1C1C1, FlxColor.RED);
}
colorSwap = new ColorSwap();
shader = colorSwap.shader;
updateColors();
switch (noteData)
{
case 0:
x += swagWidth * 0;
animation.play('purpleScroll');
case 1:
x += swagWidth * 1;
animation.play('blueScroll');
case 2:
x += swagWidth * 2;
animation.play('greenScroll');
case 3:
x += swagWidth * 3;
animation.play('redScroll');
}
// trace(prevNote);
if (isSustainNote && prevNote != null)
{
noteScore * 0.2;
alpha = 0.6;
if (PreferencesMenu.getPref('downscroll'))
angle = 180;
x += width / 2;
switch (noteData)
{
case 2:
animation.play('greenholdend');
case 3:
animation.play('redholdend');
case 1:
animation.play('blueholdend');
case 0:
animation.play('purpleholdend');
}
updateHitbox();
x -= width / 2;
if (PlayState.isPixel) x += 30;
if (prevNote.isSustainNote)
{
switch (prevNote.noteData)
{
case 0:
prevNote.animation.play('purplehold');
case 1:
prevNote.animation.play('bluehold');
case 2:
prevNote.animation.play('greenhold');
case 3:
prevNote.animation.play('redhold');
}
prevNote.scale.y *= Conductor.stepCrochet / 100 * 1.5 * PlayState.SONG.speed;
prevNote.updateHitbox();
// prevNote.setGraphicSize();
}
}
}
public function updateColors():Void
{
colorSwap.update(arrowColors[noteData]);
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (mustPress)
{
// miss on the NEXT frame so lag doesnt make u miss notes
if (willMiss && !wasGoodHit)
{
tooLate = true;
canBeHit = false;
}
else
{
if (strumTime > Conductor.songPosition - Conductor.safeZoneOffset)
{ // The * 0.5 is so that it's easier to hit them too late, instead of too early
if (strumTime < Conductor.songPosition + (Conductor.safeZoneOffset * 0.5))
canBeHit = true;
}
else
{
canBeHit = true;
willMiss = true;
}
}
}
else
{
canBeHit = false;
if (strumTime <= Conductor.songPosition)
wasGoodHit = true;
}
if (tooLate)
{
if (alpha > 0.3)
alpha = 0.3;
}
}
}

View File

@ -0,0 +1,45 @@
package game.ui.gameplay.note;
import flixel.FlxG;
import flixel.FlxSprite;
class NoteSplash extends FlxSprite
{
public function new(x:Float, y:Float, noteData:Int = 0):Void
{
super(x, y);
frames = Paths.getSparrowAtlas('noteSplashes');
animation.addByPrefix('note1-0', 'note impact 1 blue', 24, false);
animation.addByPrefix('note2-0', 'note impact 1 green', 24, false);
animation.addByPrefix('note0-0', 'note impact 1 purple', 24, false);
animation.addByPrefix('note3-0', 'note impact 1 red', 24, false);
animation.addByPrefix('note1-1', 'note impact 2 blue', 24, false);
animation.addByPrefix('note2-1', 'note impact 2 green', 24, false);
animation.addByPrefix('note0-1', 'note impact 2 purple', 24, false);
animation.addByPrefix('note3-1', 'note impact 2 red', 24, false);
setupNoteSplash(x, y, noteData);
// alpha = 0.75;
}
public function setupNoteSplash(x:Float, y:Float, noteData:Int = 0)
{
setPosition(x, y);
alpha = 0.6;
animation.play('note' + noteData + '-' + FlxG.random.int(0, 1), true);
animation.curAnim.frameRate = 24 + FlxG.random.int(-2, 2);
updateHitbox();
offset.set(width * 0.3, height * 0.3);
}
override function update(elapsed:Float)
{
if (animation.curAnim.finished) kill();
super.update(elapsed);
}
}

View File

@ -0,0 +1,120 @@
package game.ui.gameplay.note;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import game.state.PlayState;
class StaticNote extends FlxSprite
{
public var animReset:Float = 0;
public function new(x:Float, y:Float, data:Int, player:Int)
{
super(x, y);
loadStaticArrow(data);
scrollFactor.set();
}
function loadStaticArrow(data:Int)
{
if (PlayState.isPixel)
{
loadGraphic(Paths.image('weeb/pixelUI/arrows-pixels'), true, 17, 17);
animation.add('green', [6]);
animation.add('red', [7]);
animation.add('blue', [5]);
animation.add('purplel', [4]);
setGraphicSize(Std.int(width * PlayState.daPixelZoom));
updateHitbox();
antialiasing = false;
switch (Math.abs(data) % 4)
{
case 0:
x += Note.swagWidth * 0;
animation.add('static', [0]);
animation.add('pressed', [4, 8], 12, false);
animation.add('confirm', [12, 16], 24, false);
case 1:
x += Note.swagWidth * 1;
animation.add('static', [1]);
animation.add('pressed', [5, 9], 12, false);
animation.add('confirm', [13, 17], 24, false);
case 2:
x += Note.swagWidth * 2;
animation.add('static', [2]);
animation.add('pressed', [6, 10], 12, false);
animation.add('confirm', [14, 18], 12, false);
case 3:
x += Note.swagWidth * 3;
animation.add('static', [3]);
animation.add('pressed', [7, 11], 12, false);
animation.add('confirm', [15, 19], 24, false);
}
}
else
{
frames = Paths.getSparrowAtlas('NOTE_assets');
animation.addByPrefix('green', 'arrowUP');
animation.addByPrefix('blue', 'arrowDOWN');
animation.addByPrefix('purple', 'arrowLEFT');
animation.addByPrefix('red', 'arrowRIGHT');
antialiasing = true;
setGraphicSize(Std.int(width * 0.7));
switch (Math.abs(data) % 4)
{
case 0:
x += Note.swagWidth * 0;
animation.addByPrefix('static', 'arrow static instance 1');
animation.addByPrefix('pressed', 'left press', 24, false);
animation.addByPrefix('confirm', 'left confirm', 24, false);
case 1:
x += Note.swagWidth * 1;
animation.addByPrefix('static', 'arrow static instance 2');
animation.addByPrefix('pressed', 'down press', 24, false);
animation.addByPrefix('confirm', 'down confirm', 24, false);
case 2:
x += Note.swagWidth * 2;
animation.addByPrefix('static', 'arrow static instance 4');
animation.addByPrefix('pressed', 'up press', 24, false);
animation.addByPrefix('confirm', 'up confirm', 24, false);
case 3:
x += Note.swagWidth * 3;
animation.addByPrefix('static', 'arrow static instance 3');
animation.addByPrefix('pressed', 'right press', 24, false);
animation.addByPrefix('confirm', 'right confirm', 24, false);
}
}
updateHitbox();
playStrumAnim('static', true);
}
override function update(elapsed:Float)
{
if (animReset > 0) {
animReset -= elapsed;
if (animReset <= 0) {
playStrumAnim('static', true);
animReset = 0;
}
}
super.update(elapsed);
}
public function playStrumAnim(anim:String, ?forced:Bool = false):Void
{
animation.play(anim, forced);
if (anim == 'confirm' && !PlayState.isPixel)
{
centerOffsets();
offset.x -= 13;
offset.y -= 13;
}
else
centerOffsets();
}
}

View File

@ -0,0 +1,34 @@
package game.ui.menu;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
class MenuCharacter extends FlxSprite
{
public var character:String;
public function new(x:Float, character:String = 'bf')
{
super(x);
this.character = character;
var tex = Paths.getSparrowAtlas('campaign_menu_UI_characters');
frames = tex;
animation.addByPrefix('bf', "BF idle dance white", 24);
animation.addByPrefix('bfConfirm', 'BF HEY!!', 24, false);
animation.addByPrefix('gf', "GF Dancing Beat WHITE", 24);
animation.addByPrefix('dad', "Dad idle dance BLACK LINE", 24);
animation.addByPrefix('spooky', "spooky dance idle BLACK LINES", 24);
animation.addByPrefix('pico', "Pico Idle Dance", 24);
animation.addByPrefix('mom', "Mom Idle BLACK LINES", 24);
animation.addByPrefix('parents-christmas', "Parent Christmas Idle", 24);
animation.addByPrefix('senpai', "SENPAI idle Black Lines", 24);
animation.addByPrefix('tankman', "Tankman Menu BLACK", 24);
// Parent Christmas Idle
animation.play(character);
updateHitbox();
}
}

View File

@ -0,0 +1,49 @@
package game.ui.menu;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxSpriteGroup;
import flixel.math.FlxMath;
import flixel.util.FlxColor;
class MenuItem extends FlxSpriteGroup
{
public var targetY:Float = 0;
public var week:FlxSprite;
public var flashingInt:Int = 0;
public function new(x:Float, y:Float, weekNum:Int = 0)
{
super(x, y);
week = new FlxSprite().loadGraphic(Paths.image('storymenu/week' + weekNum));
add(week);
}
private var isFlashing:Bool = false;
public function startFlashing():Void
{
isFlashing = true;
}
// if it runs at 60fps, fake framerate will be 6
// if it runs at 144 fps, fake framerate will be like 14, and will update the graphic every 0.016666 * 3 seconds still???
// so it runs basically every so many seconds, not dependant on framerate??
// I'm still learning how math works thanks whoever is reading this lol
var fakeFramerate:Int = Math.round((1 / FlxG.elapsed) / 10);
override function update(elapsed:Float)
{
super.update(elapsed);
y = CoolUtil.coolLerp(y, (targetY * 120) + 480, 0.17);
if (isFlashing)
flashingInt += 1;
if (flashingInt % fakeFramerate >= Math.floor(fakeFramerate / 2))
week.color = 0xFF33ffff;
else
week.color = FlxColor.WHITE;
}
}

View File

@ -0,0 +1,11 @@
package;
import flixel.FlxSubState;
class ButtonRemapSubstate extends FlxSubState
{
public function new()
{
super();
}
}

View File

@ -0,0 +1,80 @@
package;
import flixel.util.FlxStringUtil;
using StringTools;
class ChartParser
{
static public function parse(songName:String, section:Int):Array<Dynamic>
{
var IMG_WIDTH:Int = 8;
var regex:EReg = new EReg("[ \t]*((\r\n)|\r|\n)[ \t]*", "g");
var csvData = FlxStringUtil.imageToCSV(Paths.file('data/' + songName + '/' + songName + '_section' + section + '.png'));
var lines:Array<String> = regex.split(csvData);
var rows:Array<String> = lines.filter(function(line) return line != "");
csvData.replace("\n", ',');
var heightInTiles = rows.length;
var widthInTiles = 0;
var row:Int = 0;
// LMAOOOO STOLE ALL THIS FROM FLXBASETILEMAP LOLOL
var dopeArray:Array<Int> = [];
while (row < heightInTiles)
{
var rowString = rows[row];
if (rowString.endsWith(","))
rowString = rowString.substr(0, rowString.length - 1);
var columns = rowString.split(",");
if (columns.length == 0)
{
heightInTiles--;
continue;
}
if (widthInTiles == 0)
{
widthInTiles = columns.length;
}
var column = 0;
var pushedInColumn:Bool = false;
while (column < widthInTiles)
{
// the current tile to be added:
var columnString = columns[column];
var curTile = Std.parseInt(columnString);
if (curTile == null)
throw 'String in row $row, column $column is not a valid integer: "$columnString"';
if (curTile == 1)
{
if (column < 4)
dopeArray.push(column + 1);
else
{
var tempCol = (column + 1) * -1;
tempCol += 4;
dopeArray.push(tempCol);
}
pushedInColumn = true;
}
column++;
}
if (!pushedInColumn)
dopeArray.push(0);
row++;
}
return dopeArray;
}
}

View File

@ -0,0 +1,12 @@
package;
import flixel.FlxSprite;
import flixel.FlxSubState;
class ControlsSubState extends FlxSubState
{
public function new()
{
super();
}
}

View File

@ -0,0 +1,74 @@
package;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.text.FlxText;
class LatencyState extends FlxState
{
var offsetText:FlxText;
var noteGrp:FlxTypedGroup<Note>;
var strumLine:FlxSprite;
override function create()
{
FlxG.sound.playMusic(Paths.sound('soundTest'));
noteGrp = new FlxTypedGroup<Note>();
add(noteGrp);
for (i in 0...32)
{
var note:Note = new Note(Conductor.crochet * i, 1);
noteGrp.add(note);
}
offsetText = new FlxText();
offsetText.screenCenter();
add(offsetText);
strumLine = new FlxSprite(FlxG.width / 2, 100).makeGraphic(FlxG.width, 5);
add(strumLine);
Conductor.changeBPM(120);
super.create();
}
override function update(elapsed:Float)
{
offsetText.text = "Offset: " + Conductor.offset + "ms";
Conductor.songPosition = FlxG.sound.music.time - Conductor.offset;
var multiply:Float = 1;
if (FlxG.keys.pressed.SHIFT)
multiply = 10;
if (FlxG.keys.justPressed.RIGHT)
Conductor.offset += 1 * multiply;
if (FlxG.keys.justPressed.LEFT)
Conductor.offset -= 1 * multiply;
if (FlxG.keys.justPressed.SPACE)
{
FlxG.sound.music.stop();
FlxG.resetState();
}
noteGrp.forEach(function(daNote:Note)
{
daNote.y = (strumLine.y - (Conductor.songPosition - daNote.strumTime) * 0.45);
daNote.x = strumLine.x + 30;
if (daNote.y < strumLine.y)
daNote.kill();
});
super.update(elapsed);
}
}

1288
source/game/unused/Snd.hx Normal file

File diff suppressed because it is too large Load Diff

332
source/game/unused/SndTV.hx Normal file
View File

@ -0,0 +1,332 @@
import h2d.Tweenie.TType;
//praise delahee, i'll figure out what this shit means later!
enum TVVar{
TVVVolume;
TVVPan;
}
@:publicFields
class TweenV {
static var GUID = 0;
var uid = 0;
var man : SndTV;
var parent : Snd;
var n : Float;
var ln : Float;
var speed : Float;
var from : Float;
var to : Float;
var type : TType;
var plays : Int; // -1 = infini, 1 et plus = nombre d'exécutions (1 par défaut)
var varType : TVVar;
var onUpdate : Null<TweenV->Void>;
var onEnd : Null<TweenV->Void>;
var isDebug = false;
public inline function new (
parent:Snd ,
n:Float ,
ln:Float ,
varType:TVVar,
speed:Float ,
from:Float ,
to:Float ,
type:h2d.Tweenie.TType ,
plays ,
onUpdate ,
onEnd
) {
this.parent = parent ;
this.n = n ;
this.ln = ln ;
this.varType = varType ;
this.speed = speed ;
this.from = from ;
this.to = to ;
this.type = type ;
this.plays = plays ;
this.onUpdate = onUpdate ;
this.onEnd = onEnd ;
}
public inline function reset(
parent:Snd ,
n:Float ,
ln:Float ,
varType:TVVar,
speed:Float ,
from:Float ,
to:Float ,
type:TType ,
plays:Int ,
onUpdate ,
onEnd
) {
this.parent = parent ;
this.n = n ;
this.ln = ln ;
this.speed = speed ;
this.from = from ;
this.to = to ;
this.type = type ;
this.plays = plays ;
this.onUpdate = onUpdate ;
this.onEnd = onEnd ;
this.varType = varType ;
isDebug = false;
uid = GUID++;
}
public function clear(){
n = 0.0;
ln = 0.0;
speed = 0.0;
plays = 0;
from = 0.0;
to = 0.0;
parent = null;
onEnd = null;
onUpdate = null;
isDebug = false;
uid = GUID++;
}
public
inline
function apply( val ) {
switch(varType){
case TVVVolume: {
parent.volume = val;
#if debug
if( isDebug )
trace("tv:" + val);
#end
}
case TVVPan: parent.pan = val;
}
}
public inline function kill( withCbk = true ) {
if ( withCbk )
man.terminateTween( this );
else
man.forceTerminateTween( this) ;
}
}
/**
* tween order is not respected
*/
class SndTV {
static var DEFAULT_DURATION = DateTools.seconds(1);
public var fps = 60.0;
public var isDebug = false;
var tlist : hxd.Stack<TweenV>;
public function new() {
tlist = new hxd.Stack<TweenV>();
tlist.reserve(8);
}
function onError(e) {
trace(e);
}
public function count() {
return tlist.length;
}
public inline function create(parent:Snd, vartype:TVVar, to:Float, ?tp:h2d.Tweenie.TType, ?duration_ms:Float) : TweenV{
return create_(parent, vartype, to, tp, duration_ms);
}
public function exists(p:Snd) {
for (t in tlist)
if (t.parent == p )
return true;
return false;
}
public var pool : hxd.Stack<TweenV> = new hxd.Stack();
function create_(p:Snd, vartype:TVVar,to:Float, ?tp:h2d.Tweenie.TType, ?duration_ms:Float) : TweenV{
if ( duration_ms==null )
duration_ms = DEFAULT_DURATION;
#if debug
if ( p == null ) trace("tween2 creation failed to:"+to+" tp:"+tp);
#end
if ( tp==null ) tp = TEase;
{
// on supprime les tweens précédents appliqués à la même variable
for(t in tlist.backWardIterator())
if(t.parent==p && t.varType == vartype) {
forceTerminateTween(t);
}
}
var from = switch( vartype ){
case TVVVolume : p.volume;
case TVVPan : p.pan;
}
var t : TweenV;
if (pool.length == 0){
t = new TweenV(
p,
0.0,
0.0,
vartype,
1 / ( duration_ms*fps/1000 ), // une seconde
from,
to,
tp,
1,
null,
null
);
}
else {
t = pool.pop();
t.reset(
p,
0.0,
0.0,
vartype,
1 / ( duration_ms*fps/1000 ), // une seconde
from,
to,
tp,
1,
null,
null
);
}
if( t.from==t.to )
t.ln = 1; // tweening inutile : mais on s'assure ainsi qu'un update() et un end() seront bien appelés
t.man = this;
tlist.push(t);
return t;
}
public static inline
function fastPow2(n:Float):Float {
return n*n;
}
public static inline
function fastPow3(n:Float):Float {
return n*n*n;
}
public static inline
function bezier(t:Float, p0:Float, p1:Float,p2:Float, p3:Float) {
return
fastPow3(1-t)*p0 +
3*( t*fastPow2(1-t)*p1 + fastPow2(t)*(1-t)*p2 ) +
fastPow3(t)*p3;
}
// suppression du tween sans aucun appel aux callbacks onUpdate, onUpdateT et onEnd (!)
public function killWithoutCallbacks(parent:Snd) {
for (t in tlist.backWardIterator())
if (t.parent==parent ){
forceTerminateTween(t);
return true;
}
return false;
}
public function terminate(parent:Snd) {
for (t in tlist.backWardIterator())
if (t.parent==parent){
forceTerminateTween(t);
}
}
public function forceTerminateTween(t:TweenV) {
var tOk = tlist.remove(t);
if( tOk ){
t.clear();
pool.push(t);
}
}
public function terminateTween(t:TweenV, ?fl_allowLoop=false) {
var v = t.from + (t.to - t.from) * h2d.Tweenie.interp(t.type, 1);
t.apply(v);
onUpdate(t, 1);
var ouid = t.uid;
onEnd(t);
if( ouid == t.uid ){
if( fl_allowLoop && (t.plays==-1 || t.plays>1) ) {
if( t.plays!=-1 )
t.plays--;
t.n = t.ln = 0;
}
else {
forceTerminateTween(t);
}
}
}
public function terminateAll() {
for(t in tlist)
t.ln = 1;
update();
}
inline
function onUpdate(t:TweenV, n:Float) {
if ( t.onUpdate!=null )
t.onUpdate(t);
}
inline
function onEnd(t:TweenV) {
if ( t.onEnd!=null )
t.onEnd(t);
}
public function update(?tmod = 1.0) {
if ( tlist.length > 0 ) {
for (t in tlist.backWardIterator() ) {
var dist = t.to-t.from;
if (t.type==TRand)
t.ln+=if(Std.random(100)<33) t.speed * tmod else 0;
else
t.ln += t.speed * tmod;
t.n = h2d.Tweenie.interp(t.type, t.ln);
if ( t.ln<1 ) {
// en cours...
var val = t.from + t.n*dist;
t.apply(val);
onUpdate(t, t.ln);
}
else // fini !
{
terminateTween(t, true);
}
}
}
}
}

1
source/import.hx Normal file
View File

@ -0,0 +1 @@
import Paths;