diff --git a/Error b/Error new file mode 100644 index 0000000..e69de29 diff --git a/ModCharts.md b/ModCharts.md index 908c9c1..571443c 100644 --- a/ModCharts.md +++ b/ModCharts.md @@ -1,4 +1,4 @@ -# Kade Engine Lua Mod Chart Documentation +Kade Engine Lua Mod Chart Documentation In the latest version of Kade Engine we introduced Mod Charts. Mod Charts are a way of changing gameplay without hard coded values, this is achieved by using the Lua Scripting language to create script files that run during runtime. @@ -20,10 +20,10 @@ end function update (elapsed) -- example https://twitter.com/KadeDeveloper/status/1382178179184422918 local currentBeat = (songPos / 1000)*(bpm/60) - for i=0,7 do - _G['strum'..i..'X'] = _G['defaultStrum'..i..'X'] + 32 * math.sin((currentBeat + i*0.25) * math.pi) - _G['strum'..i..'Y'] = _G['defaultStrum'..i..'Y'] + 32 * math.cos((currentBeat + i*0.25) * math.pi) - end + for i=0,7 do + setActorX(_G['defaultStrum'..i..'X'] + 32 * math.sin((currentBeat + i*0.25) * math.pi), i) + setActorY(_G['defaultStrum'..i..'Y'] + 32 * math.cos((currentBeat + i*0.25) * math.pi), i) + end end function beatHit (beat) @@ -31,7 +31,7 @@ function beatHit (beat) end function stepHit (step) - -- do nothing + -- do nothing end print("Mod Chart script loaded :)") @@ -41,9 +41,9 @@ Spinning Receptor Example ```lua function update (elapsed) - for i=0,7 do - _G['strum'..i..'Angle'] = _G['strum'..i..'Angle'] + 15 - end + for i=0,7 do + setActorAngle(getActorAngle(i) + 15, i) + end end ``` @@ -62,13 +62,15 @@ function update (elapsed) if curStep >= 352 and curStep < 400 then local currentBeat = (songPos / 1000)*(bpm/60) for i=0,7 do - _G['strum'..i..'X'] = _G['defaultStrum'..i..'X'] + 32 * math.sin((currentBeat + i*0.25) * math.pi) - _G['strum'..i..'Y'] = _G['defaultStrum'..i..'Y'] + 32 * math.cos((currentBeat + i*0.25) * math.pi) + setActorX(_G['defaultStrum'..i..'X'] + 32 * math.sin((currentBeat + i*0.25) * math.pi), i) + setActorY(_G['defaultStrum'..i..'Y'] + 32 * math.cos((currentBeat + i*0.25) * math.pi), i) end else - _G['strum'..i..'X'] = _G['defaultStrum'..i..'X'] - _G['strum'..i..'Y'] = _G['defaultStrum'..i..'Y'] - end + for i=0,7 do + setActorX(_G['defaultStrum'..i..'X'],i) + setActorX(_G['defaultStrum'..i..'Y'],i) + end + end end ``` @@ -77,10 +79,20 @@ Showing/Hiding receptors/the hud ```lua function start (song) showOnlyStrums = true -- remove all hud elements besides notes and strums - _G['strumLine1Visible'] = false -- remove the first line of strums (the ai notes) + for i=0,3 do -- fade out the first 4 receptors (the ai receptors) + tweenFadeIn(i,0,0.6) + end end ``` +Looping through all of the rendered notes + +```lua + for i = 0, getRenderedNotes() do -- sets all of the rendered notes to 0 0 on the x and y axsis + setRenderedNotePos(0,0,i) + end +``` + ### Available Hooks @@ -105,8 +117,6 @@ Kade Engine provides a list of global variables to be used in the lua scripting | bpm | Float | The current BPM of the song | | fpsCap | Int | The current FPS Cap (set by the player) | | downscroll | Bool | Whether the player is in downscroll or not | -| hudZoom | Float | The amount of zoom the Hud should be zoomed in/out | -| cameraZoom | Float | The amount of zoom the Main Camera should be zoomed in/out | | cameraAngle | Float | The angle that the Main Camera should be rotated | | camHudAngle | Float | The angle that the Hud should be rotated | | followXOffset | Float | The x offset to be added when the camera moves between a character | @@ -114,10 +124,227 @@ Kade Engine provides a list of global variables to be used in the lua scripting | showOnlyStrums | Bool | Whether to show the Hud and Strums or only the Strums | | strumLine1Visible | Bool | Whether to show the first strum line or not | | strumLine2Visible | Bool | Whether to show the secondstrum line or not | -| strum0-7X | Float | (0-7 is strum0,strum1,strum2,etc) get/set the X coordinate for the strum | -| strum0-7Y | Float | (0-7 is strum0,strum1,strum2,etc) get/set the Y coordinate for the strum | -| strum0-7Angle | Float | (0-7 is strum0,strum1,strum2,etc) get/set the Angle for the strum | | defaultStrum0-7X | Float | (0-7 is strum0,strum1,strum2,etc) get the default X coordinate for the strum | | defaultStrum0-7Y | Float | (0-7 is strum0,strum1,strum2,etc) get the default Y coordinate for the strum | | defaultStrum0-7Angle | Float | (0-7 is strum0,strum1,strum2,etc) get the default Angle for the strum | +| screenWidth | Int | The width of the current gamespace | +| screenHeight | Int | The height of the current gamespace | +| hudWidth | Int | The width of the hud | +| hudHeight | Int | The height of the hud | + + +## Functions + +Kade Engine exposes a lot of functions that let you modify elements in the game field. + + + +To get started every sprite has an id, and there are some id's that are accessible without creating one. + +These premade id's are the following: + +| Sprite Id | Value | +| :--------: | :--------------------------------------: | +| 0-7 | Represents Receptor 0-7 | +| boyfriend | Represents the Boyfriend Actor (player1) | +| dad | Represents the Dad Actor (player2) | +| girlfriend | Represents the Girlfriend Actor | + + + +### Sprites + +##### makeSprite(string SpritePath,string SpriteId,bool DrawBehind) + +Creates a sprite out of the specified image, returns the id you gave it. + +*Note: Sprite Path is normally the FILE NAME so if you have a file name of Image it'll go to assets/data/songName/Image.png so don't include the extension* + +### Hud/Camera + +##### setHudPosition(int x, int y) + +Set's the game hud's position in space. + +##### getHudX() + +Returns the hud's x position + +##### getHudY() + +Returns the hud's y position + +##### setCamPosition(int x, int y) + +Set's the current camera's position in space + +##### getCamX() + +Returns the current camera's x position + +##### getCamY() + +Returns the current camera's y position + +##### setCamZoom(int zoomAmount) + +Set's the current camera's zoom + +##### setHudZoom(int zoomAmount) + +Set's the hud's zoom + +### Actor's + +##### getRenderedNotes() + +Returns the amount of rendered notes. + +##### getRenderedNoteX(int id) + +Return's the x position of the rendered note id + +*Note: Rendered Notes id's are special in the way that they act. 0 = closest note to any receptor, last index = the farthest away from any receptor.* + +##### getRenderedNoteY(int id) + +Return's the y position of the rendered note id + +*Note: Rendered Notes id's are special in the way that they act. 0 = closest note to any receptor, last index = the farthest away from any receptor.* + +##### getRenderedNoteScaleX(int id) + +Return's the scale x of the rendered note id + +*Note: Rendered Notes id's are special in the way that they act. 0 = closest note to any receptor, last index = the farthest away from any receptor.* + +##### getRenderedNoteScaleY(int id) + +Return's the scale y of the rendered note id + +*Note: Rendered Notes id's are special in the way that they act. 0 = closest note to any receptor, last index = the farthest away from any receptor.* + +##### getRenderedNoteAlpha(int id) + +Return's the alpha of the rendered note id + +*Note: Rendered Notes id's are special in the way that they act. 0 = closest note to any receptor, last index = the farthest away from any receptor.* + +##### setRenderedNotePos(int x, int y, int id) + +Set's the position of the rendered note id + +*Note: Setting a Rendered Note's property will stop the note from updating it's alpha & x properties* + +##### setRenderedNoteAlpha(float alpha, int id) + +Set's the alpha of the rendered note id + +*Note: Setting a Rendered Note's property will stop the note from updating it's alpha & x properties* + +##### setRenderedNoteScale(float scale, int id) + +Set's the scale of the rendered note id + +*Note: Setting a Rendered Note's property will stop the note from updating it's alpha & x properties* + +##### setRenderedNoteScaleX(float scale, int id) + +Set's the scale x of the rendered note id + +*Note: Setting a Rendered Note's property will stop the note from updating it's alpha & x properties* + +##### setRenderedNoteScaleY(float scale, int id) + +Set's the scale y of the rendered note id + +*Note: Setting a Rendered Note's property will stop the note from updating it's alpha & x properties* + +##### getActorX(string/int id) + +Returns the x position for the sprite id + +##### getActorY(string/int id) + +Returns the y position for the sprite id + +##### getActorScaleX(string/int id) + +Returns the scale x for the sprite id + +##### getActorScaleY(string/int id) + +Returns the scale y for the sprite id + +##### getActorAlpha(string/int id) + +Returns the alpha for the sprite id + +##### getActorAngle(string/int id) + +Returns the angle for the sprite id + +##### setActorX(int x, string/int id) + +Set's the x position for the sprite id + +##### setActorY(int y, string/int id) + +Set's the y position for the sprite id + +##### setActorAlpha(float alpha, string/int id) + +Set's the alpha for the sprite id + +##### setActorAngle(int alpha, string/int id) + +Set's the angle for the sprite id + +##### setActorScale(float scale, string/int id) + +Set's the scale for the sprite id + +##### setActorScaleX(float x, string/int id) + +Set's the scale x for the sprite id + +##### setActorScaleY(float y, string/int id) + +Set's the scale y for the sprite id + +##### getActorWidth(string/int id) + +Returns the width for the sprite id + +##### getActorHeight(string/int id) + +Returns the height for the sprite id + +### Tweens + +*Note, On Complete functions are based by the function name (and they also well get called when the tween completes)* + +##### tweenPos(string/int id, int toX, int toY, float time, string onComplete) + +Smoothly tween into a x and y position + +##### tweenPosXAngle(string/int id, int toX, float toAngle, float time, string onComplete) + +Smoothly tween into a x position and angle + +##### tweenPosYAngle(string/int id, int toY, float toAngle, float time, string onComplete) + +Smoothly tween into a y position and angle + +##### tweenAngle(string/int id, float toAngle, float time, string onComplete) + +Smoothly tween into a angle + +##### tweenFadeIn(string/int id, float toAlpha, float time, string onComplete) + +Smoothly fade in to an alpha + +##### tweenFadeOut(string/int id, float toAlpha, float time, string onComplete) + +Smoothly fade out to an alpha \ No newline at end of file diff --git a/Project.xml b/Project.xml index 2b74dfc..e50ead4 100644 --- a/Project.xml +++ b/Project.xml @@ -2,7 +2,7 @@ - + @@ -117,6 +117,8 @@ + + diff --git a/source/ChartingState.hx b/source/ChartingState.hx index 6346c88..1ea9650 100644 --- a/source/ChartingState.hx +++ b/source/ChartingState.hx @@ -82,6 +82,9 @@ class ChartingState extends MusicBeatState var gridBlackLine:FlxSprite; var vocals:FlxSound; + var player2:Character = new Character(0,0, "dad"); + var player1:Boyfriend = new Boyfriend(0,0, "bf"); + var leftIcon:HealthIcon; var rightIcon:HealthIcon; @@ -365,6 +368,18 @@ class ChartingState extends MusicBeatState tab_group_note.add(applyLength); UI_box.addGroup(tab_group_note); + + /*player2 = new Character(0,gridBG.y, _song.player2); + player1 = new Boyfriend(player2.width * 0.2,gridBG.y + player2.height, _song.player1); + + player1.y = player1.y - player1.height; + + player2.setGraphicSize(Std.int(player2.width * 0.2)); + player1.setGraphicSize(Std.int(player1.width * 0.2)); + + UI_box.add(player1); + UI_box.add(player2);*/ + } function loadSong(daSong:String):Void @@ -559,6 +574,77 @@ class ChartingState extends MusicBeatState strumLine.y = getYfromStrum((Conductor.songPosition - sectionStartTime()) % (Conductor.stepCrochet * _song.notes[curSection].lengthInSteps)); + + /*curRenderedNotes.forEach(function(note:Note) { + if (strumLine.overlaps(note) && strumLine.y == note.y) // yandere dev type shit + { + if (_song.notes[curSection].mustHitSection) + { + trace('must hit ' + Math.abs(note.noteData)); + if (note.noteData < 4) + { + switch (Math.abs(note.noteData)) + { + case 2: + player1.playAnim('singUP', true); + case 3: + player1.playAnim('singRIGHT', true); + case 1: + player1.playAnim('singDOWN', true); + case 0: + player1.playAnim('singLEFT', true); + } + } + if (note.noteData >= 4) + { + switch (note.noteData) + { + case 6: + player2.playAnim('singUP', true); + case 7: + player2.playAnim('singRIGHT', true); + case 5: + player2.playAnim('singDOWN', true); + case 4: + player2.playAnim('singLEFT', true); + } + } + } + else + { + trace('hit ' + Math.abs(note.noteData)); + if (note.noteData < 4) + { + switch (Math.abs(note.noteData)) + { + case 2: + player2.playAnim('singUP', true); + case 3: + player2.playAnim('singRIGHT', true); + case 1: + player2.playAnim('singDOWN', true); + case 0: + player2.playAnim('singLEFT', true); + } + } + if (note.noteData >= 4) + { + switch (note.noteData) + { + case 6: + player1.playAnim('singUP', true); + case 7: + player1.playAnim('singRIGHT', true); + case 5: + player1.playAnim('singDOWN', true); + case 4: + player1.playAnim('singLEFT', true); + } + } + } + } + });*/ + if (curBeat % 4 == 0 && curStep >= 16 * (curSection + 1)) { trace(curStep); @@ -783,6 +869,18 @@ class ChartingState extends MusicBeatState updateGrid(); } + override function beatHit() + { + trace('beat'); + + super.beatHit(); + if (!player2.animation.curAnim.name.startsWith("sing")) + { + player2.playAnim('idle'); + } + player1.dance(); + } + function recalculateSteps():Int { var lastChange:BPMChangeEvent = { diff --git a/source/Main.hx b/source/Main.hx index 97d4320..48f0fc3 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -29,6 +29,9 @@ class Main extends Sprite public static function main():Void { + + // quick checks + Lib.current.addChild(new Main()); } @@ -82,6 +85,7 @@ class Main extends Sprite fpsCounter = new FPS(10, 3, 0xFFFFFF); addChild(fpsCounter); toggleFPS(FlxG.save.data.fps); + #end } diff --git a/source/Note.hx b/source/Note.hx index 699b9bc..72124eb 100644 --- a/source/Note.hx +++ b/source/Note.hx @@ -1,5 +1,6 @@ package; +import flixel.addons.effects.FlxSkewedSprite; import flixel.FlxG; import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; @@ -11,7 +12,7 @@ import polymod.format.ParseRules.TargetSignatureElement; using StringTools; -class Note extends FlxSprite +class Note extends FlxSkewedSprite { public var strumTime:Float = 0; @@ -21,7 +22,7 @@ class Note extends FlxSprite public var tooLate:Bool = false; public var wasGoodHit:Bool = false; public var prevNote:Note; - + public var modifiedByLua:Bool = false; public var sustainLength:Float = 0; public var isSustainNote:Bool = false; @@ -172,7 +173,7 @@ class Note extends FlxSprite prevNote.animation.play('redhold'); } - prevNote.scale.y *= Conductor.stepCrochet / 100 * 1.8 * FlxG.save.data.scrollSpeed; + prevNote.scale.y *= Conductor.stepCrochet / 50 * 1.5 * FlxG.save.data.scrollSpeed; prevNote.updateHitbox(); // prevNote.setGraphicSize(); } diff --git a/source/Paths.hx b/source/Paths.hx index dcd1477..9902b71 100644 --- a/source/Paths.hx +++ b/source/Paths.hx @@ -55,6 +55,16 @@ class Paths return getPath(file, type, library); } + inline static public function lua(key:String,?library:String) + { + return getPath('data/$key.lua', TEXT, library); + } + + inline static public function luaImage(key:String, ?library:String) + { + return getPath('data/$key.png', IMAGE, library); + } + inline static public function txt(key:String, ?library:String) { return getPath('data/$key.txt', TEXT, library); diff --git a/source/PauseSubState.hx b/source/PauseSubState.hx index 3533fe0..a335ffe 100644 --- a/source/PauseSubState.hx +++ b/source/PauseSubState.hx @@ -1,5 +1,6 @@ package; +import llua.Lua; import Controls.Control; import flixel.FlxG; import flixel.FlxSprite; @@ -179,6 +180,11 @@ class PauseSubState extends MusicBeatSubstate FlxG.resetState(); case "Exit to menu": PlayState.loadRep = false; + if (PlayState.lua != null) + { + Lua.close(PlayState.lua); + PlayState.lua = null; + } if (PlayState.offsetTesting) { PlayState.offsetTesting = false; diff --git a/source/PlayState.hx b/source/PlayState.hx index 3af5232..3cb3d8b 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -1,5 +1,20 @@ package; +import openfl.geom.Matrix; +import openfl.display.BitmapData; +import openfl.utils.AssetType; +import lime.graphics.Image; +import flixel.graphics.FlxGraphic; +import openfl.utils.AssetManifest; +import openfl.utils.AssetLibrary; +import flixel.system.FlxAssets; +import llua.Convert; +import llua.Lua; +import llua.State; +import llua.LuaL; +import lime.app.Application; +import lime.media.AudioContext; +import lime.media.AudioManager; import openfl.Lib; import Section.SwagSection; import Song.SwagSong; @@ -43,6 +58,7 @@ import openfl.filters.ShaderFilter; #if desktop import Discord.DiscordClient; import Sys; +import sys.FileSystem; #end using StringTools; @@ -72,6 +88,7 @@ class PlayState extends MusicBeatState var halloweenLevel:Bool = false; var songLength:Float = 0; + var kadeEngineWatermark:FlxText; #if windows // Discord RPC variables @@ -129,7 +146,6 @@ class PlayState extends MusicBeatState public static var offsetTesting:Bool = false; - var notesHitArray:Array = []; var currentFrames:Int = 0; @@ -184,6 +200,8 @@ class PlayState extends MusicBeatState // Per song additive offset public static var songOffset:Float = 0; + private var executeModchart = false; + override public function create() { @@ -200,6 +218,15 @@ class PlayState extends MusicBeatState repPresses = 0; repReleases = 0; + #if sys + executeModchart = FileSystem.exists(Paths.lua(PlayState.SONG.song.toLowerCase() + "/modchart")); + #end + #if !cpp + executeModchart = false; // FORCE disable for non cpp targets + #end + + trace('Mod chart: ' + executeModchart + " - " + Paths.lua(PlayState.SONG.song.toLowerCase() + "/modchart")); + #if windows // Making difficulty text for Discord Rich Presence. switch (storyDifficulty) @@ -823,7 +850,7 @@ class PlayState extends MusicBeatState add(healthBar); // Add Kade Engine watermark - var kadeEngineWatermark = new FlxText(4,healthBarBG.y + 50,0,SONG.song + " " + (storyDifficulty == 2 ? "Hard" : storyDifficulty == 1 ? "Normal" : "Easy") + (Main.watermarks ? " - KE " + MainMenuState.kadeEngineVer : ""), 16); + kadeEngineWatermark = new FlxText(4,healthBarBG.y + 50,0,SONG.song + " " + (storyDifficulty == 2 ? "Hard" : storyDifficulty == 1 ? "Normal" : "Easy") + (Main.watermarks ? " - KE " + MainMenuState.kadeEngineVer : ""), 16); kadeEngineWatermark.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); kadeEngineWatermark.scrollFactor.set(); add(kadeEngineWatermark); @@ -1140,6 +1167,198 @@ class PlayState extends MusicBeatState var lastReportedPlayheadPosition:Int = 0; var songTime:Float = 0; + // LUA SHIT + + public static var lua:State = null; + + function callLua(func_name : String, args : Array, ?type : String) : Dynamic + { + var result : Any = null; + + Lua.getglobal(lua, func_name); + + for( arg in args ) { + Convert.toLua(lua, arg); + } + + result = Lua.pcall(lua, args.length, 1, 0); + + if( result == null) { + return null; + } else { + return convert(result, type); + } + + } + + function getType(l, type):Any + { + return switch Lua.type(l,type) { + case t if (t == Lua.LUA_TNIL): null; + case t if (t == Lua.LUA_TNUMBER): Lua.tonumber(l, type); + case t if (t == Lua.LUA_TSTRING): (Lua.tostring(l, type):String); + case t if (t == Lua.LUA_TBOOLEAN): Lua.toboolean(l, type); + case t: throw 'you don goofed up. lua type error ($t)'; + } + } + + function getReturnValues(l) { + var lua_v:Int; + var v:Any = null; + while((lua_v = Lua.gettop(l)) != 0) { + var type:String = getType(l,lua_v); + v = convert(lua_v, type); + Lua.pop(l, 1); + } + return v; + } + + + private function convert(v : Any, type : String) : Dynamic { // I didn't write this lol + if( Std.is(v, String) && type != null ) { + var v : String = v; + if( type.substr(0, 4) == 'array' ) { + if( type.substr(4) == 'float' ) { + var array : Array = v.split(','); + var array2 : Array = new Array(); + + for( vars in array ) { + array2.push(Std.parseFloat(vars)); + } + + return array2; + } else if( type.substr(4) == 'int' ) { + var array : Array = v.split(','); + var array2 : Array = new Array(); + + for( vars in array ) { + array2.push(Std.parseInt(vars)); + } + + return array2; + } else { + var array : Array = v.split(','); + return array; + } + } else if( type == 'float' ) { + return Std.parseFloat(v); + } else if( type == 'int' ) { + return Std.parseInt(v); + } else if( type == 'bool' ) { + if( v == 'true' ) { + return true; + } else { + return false; + } + } else { + return v; + } + } else { + return v; + } + } + + function getLuaErrorMessage(l) { + var v:String = Lua.tostring(l, -1); + Lua.pop(l, 1); + return v; + } + + public function setVar(var_name : String, object : Dynamic){ + // trace('setting variable ' + var_name + ' to ' + object); + + Lua.pushnumber(lua,object); + Lua.setglobal(lua, var_name); + } + + public function getVar(var_name : String, type : String) : Dynamic { + var result : Any = null; + + // trace('getting variable ' + var_name + ' with a type of ' + type); + + Lua.getglobal(lua, var_name); + result = Convert.fromLua(lua,-1); + Lua.pop(lua,1); + + if( result == null ) { + return null; + } else { + var result = convert(result, type); + //trace(var_name + ' result: ' + result); + return result; + } + } + + function getActorByName(id:String):Dynamic + { + // pre defined names + switch(id) + { + case 'boyfriend': + return boyfriend; + case 'girlfriend': + return gf; + case 'dad': + return dad; + } + // lua objects or what ever + if (luaSprites.get(id) == null) + return strumLineNotes.members[Std.parseInt(id)]; + return luaSprites.get(id); + } + + public static var luaSprites:Map = []; + + + + function makeLuaSprite(spritePath:String,toBeCalled:String, drawBehind:Bool) + { + #if sys + var data:BitmapData = BitmapData.fromFile(Sys.getCwd() + "assets/data/" + PlayState.SONG.song.toLowerCase() + '/' + spritePath + ".png"); + + var sprite:FlxSprite = new FlxSprite(0,0); + var imgWidth:Float = FlxG.width / data.width; + var imgHeight:Float = FlxG.height / data.height; + var scale:Float = imgWidth <= imgHeight ? imgWidth : imgHeight; + + // Cap the scale at x1 + if (scale > 1) + { + scale = 1; + } + + sprite.makeGraphic(Std.int(data.width * scale),Std.int(data.width * scale),FlxColor.TRANSPARENT); + + var data2:BitmapData = sprite.pixels.clone(); + var matrix:Matrix = new Matrix(); + matrix.identity(); + matrix.scale(scale, scale); + data2.fillRect(data2.rect, FlxColor.TRANSPARENT); + data2.draw(data, matrix, null, null, null, true); + sprite.pixels = data2; + + luaSprites.set(toBeCalled,sprite); + // and I quote: + // shitty layering but it works! + if (drawBehind) + { + remove(gf); + remove(boyfriend); + remove(dad); + } + add(sprite); + if (drawBehind) + { + add(gf); + add(boyfriend); + add(dad); + } + #end + return toBeCalled; + } + + // LUA SHIT + function startSong():Void { startingSong = false; @@ -1148,8 +1367,257 @@ class PlayState extends MusicBeatState lastReportedPlayheadPosition = 0; if (!paused) + { FlxG.sound.playMusic(Paths.inst(PlayState.SONG.song), 1, false); - + } + + + if (executeModchart) // dude I hate lua (jkjkjkjk) + { + trace('opening a lua state (because we are cool :))'); + lua = LuaL.newstate(); + LuaL.openlibs(lua); + trace("Lua version: " + Lua.version()); + trace("LuaJIT version: " + Lua.versionJIT()); + Lua.init_callbacks(lua); + + var result = LuaL.dofile(lua, Paths.lua(PlayState.SONG.song.toLowerCase() + "/modchart")); // execute le file + + if (result != 0) + trace('COMPILE ERROR\n' + getLuaErrorMessage(lua)); + + // get some fukin globals up in here bois + + setVar("bpm", Conductor.bpm); + setVar("fpsCap", FlxG.save.data.fpsCap); + setVar("downscroll", FlxG.save.data.downscroll); + + setVar("curStep", 0); + setVar("curBeat", 0); + + setVar("hudZoom", camHUD.zoom); + setVar("cameraZoom", FlxG.camera.zoom); + + setVar("cameraAngle", FlxG.camera.angle); + setVar("camHudAngle", camHUD.angle); + + setVar("followXOffset",0); + setVar("followYOffset",0); + + setVar("showOnlyStrums", false); + setVar("strumLine1Visible", true); + setVar("strumLine2Visible", true); + + setVar("screenWidth",FlxG.width); + setVar("screenHeight",FlxG.height); + setVar("hudWidth", camHUD.width); + setVar("hudHeight", camHUD.height); + + // callbacks + + // sprites + + trace(Lua_helper.add_callback(lua,"makeSprite", makeLuaSprite)); + + Lua_helper.add_callback(lua,"destroySprite", function(id:String) { + var sprite = luaSprites.get(id); + if (sprite == null) + return false; + remove(sprite); + return true; + }); + + // hud/camera + + trace(Lua_helper.add_callback(lua,"setHudPosition", function (x:Int, y:Int) { + camHUD.x = x; + camHUD.y = y; + })); + + trace(Lua_helper.add_callback(lua,"getHudX", function () { + return camHUD.x; + })); + + trace(Lua_helper.add_callback(lua,"getHudY", function () { + return camHUD.y; + })); + + trace(Lua_helper.add_callback(lua,"setCamPosition", function (x:Int, y:Int) { + FlxG.camera.x = x; + FlxG.camera.y = y; + })); + + trace(Lua_helper.add_callback(lua,"getCameraX", function () { + return FlxG.camera.x; + })); + + trace(Lua_helper.add_callback(lua,"getCameraY", function () { + return FlxG.camera.y; + })); + + trace(Lua_helper.add_callback(lua,"setCamZoom", function(zoomAmount:Int) { + FlxG.camera.zoom = zoomAmount; + })); + + trace(Lua_helper.add_callback(lua,"setHudZoom", function(zoomAmount:Int) { + camHUD.zoom = zoomAmount; + })); + + // actors + + trace(Lua_helper.add_callback(lua,"getRenderedNotes", function() { + return notes.length; + })); + + trace(Lua_helper.add_callback(lua,"getRenderedNoteX", function(id:Int) { + return notes.members[id].x; + })); + + trace(Lua_helper.add_callback(lua,"getRenderedNoteY", function(id:Int) { + return notes.members[id].y; + })); + + trace(Lua_helper.add_callback(lua,"getRenderedNoteScaleX", function(id:Int) { + return notes.members[id].scale.x; + })); + + trace(Lua_helper.add_callback(lua,"getRenderedNoteScaleY", function(id:Int) { + return notes.members[id].scale.y; + })); + + trace(Lua_helper.add_callback(lua,"getRenderedNoteAlpha", function(id:Int) { + return notes.members[id].alpha; + })); + + trace(Lua_helper.add_callback(lua,"setRenderedNotePos", function(x:Int,y:Int, id:Int) { + notes.members[id].modifiedByLua = true; + notes.members[id].x = x; + notes.members[id].y = y; + })); + + trace(Lua_helper.add_callback(lua,"setRenderedNoteAlpha", function(alpha:Float, id:Int) { + notes.members[id].modifiedByLua = true; + notes.members[id].alpha = alpha; + })); + + trace(Lua_helper.add_callback(lua,"setRenderedNoteScale", function(scale:Float, id:Int) { + notes.members[id].modifiedByLua = true; + notes.members[id].setGraphicSize(Std.int(notes.members[id].width * scale)); + })); + + trace(Lua_helper.add_callback(lua,"setRenderedNoteScaleX", function(scale:Float, id:Int) { + notes.members[id].modifiedByLua = true; + notes.members[id].scale.x = scale; + })); + + trace(Lua_helper.add_callback(lua,"setRenderedNoteScaleY", function(scale:Float, id:Int) { + notes.members[id].modifiedByLua = true; + notes.members[id].scale.y = scale; + })); + + trace(Lua_helper.add_callback(lua,"setActorX", function(x:Int,id:String) { + getActorByName(id).x = x; + })); + + trace(Lua_helper.add_callback(lua,"setActorAlpha", function(alpha:Int,id:String) { + getActorByName(id).alpha = alpha; + })); + + trace(Lua_helper.add_callback(lua,"setActorY", function(y:Int,id:String) { + getActorByName(id).y = y; + })); + + trace(Lua_helper.add_callback(lua,"setActorAngle", function(angle:Int,id:String) { + getActorByName(id).angle = angle; + })); + + trace(Lua_helper.add_callback(lua,"setActorScale", function(scale:Float,id:String) { + getActorByName(id).setGraphicSize(Std.int(getActorByName(id).width * scale)); + })); + + trace(Lua_helper.add_callback(lua,"setActorScaleX", function(scale:Float,id:String) { + getActorByName(id).scale.x = scale; + })); + + trace(Lua_helper.add_callback(lua,"setActorScaleY", function(scale:Float,id:String) { + getActorByName(id).scale.y = scale; + })); + + trace(Lua_helper.add_callback(lua,"getActorWidth", function (id:String) { + return getActorByName(id).width; + })); + + trace(Lua_helper.add_callback(lua,"getActorHeight", function (id:String) { + return getActorByName(id).height; + })); + + trace(Lua_helper.add_callback(lua,"getActorAlpha", function(id:String) { + return getActorByName(id).alpha; + })); + + trace(Lua_helper.add_callback(lua,"getActorAngle", function(id:String) { + return getActorByName(id).angle; + })); + + trace(Lua_helper.add_callback(lua,"getActorX", function (id:String) { + return getActorByName(id).x; + })); + + trace(Lua_helper.add_callback(lua,"getActorY", function (id:String) { + return getActorByName(id).y; + })); + + trace(Lua_helper.add_callback(lua,"getActorScaleX", function (id:String) { + return getActorByName(id).scale.x; + })); + + trace(Lua_helper.add_callback(lua,"getActorScaleY", function (id:String) { + return getActorByName(id).scale.y; + })); + + // tweens + + Lua_helper.add_callback(lua,"tweenPos", function(id:String, toX:Int, toY:Int, time:Float, onComplete:String) { + FlxTween.tween(getActorByName(id), {x: toX, y: toY}, time, {ease: FlxEase.cubeIn, onComplete: function(flxTween:FlxTween) { if (onComplete != '' && onComplete != null) {callLua(onComplete,[id]);}}}); + }); + + Lua_helper.add_callback(lua,"tweenPosXAngle", function(id:String, toX:Int, toAngle:Float, time:Float, onComplete:String) { + FlxTween.tween(getActorByName(id), {x: toX, angle: toAngle}, time, {ease: FlxEase.cubeIn, onComplete: function(flxTween:FlxTween) { if (onComplete != '' && onComplete != null) {callLua(onComplete,[id]);}}}); + }); + + Lua_helper.add_callback(lua,"tweenPosYAngle", function(id:String, toY:Int, toAngle:Float, time:Float, onComplete:String) { + FlxTween.tween(getActorByName(id), {y: toY, angle: toAngle}, time, {ease: FlxEase.cubeIn, onComplete: function(flxTween:FlxTween) { if (onComplete != '' && onComplete != null) {callLua(onComplete,[id]);}}}); + }); + + Lua_helper.add_callback(lua,"tweenAngle", function(id:String, toAngle:Int, time:Float, onComplete:String) { + FlxTween.tween(getActorByName(id), {angle: toAngle}, time, {ease: FlxEase.cubeIn, onComplete: function(flxTween:FlxTween) { if (onComplete != '' && onComplete != null) {callLua(onComplete,[id]);}}}); + }); + + Lua_helper.add_callback(lua,"tweenFadeIn", function(id:String, toAlpha:Int, time:Float, onComplete:String) { + FlxTween.tween(getActorByName(id), {alpha: toAlpha}, time, {ease: FlxEase.circIn, onComplete: function(flxTween:FlxTween) { if (onComplete != '' && onComplete != null) {callLua(onComplete,[id]);}}}); + }); + + Lua_helper.add_callback(lua,"tweenFadeOut", function(id:String, toAlpha:Int, time:Float, onComplete:String) { + FlxTween.tween(getActorByName(id), {alpha: toAlpha}, time, {ease: FlxEase.circOut, onComplete: function(flxTween:FlxTween) { if (onComplete != '' && onComplete != null) {callLua(onComplete,[id]);}}}); + }); + + for (i in 0...strumLineNotes.length) { + var member = strumLineNotes.members[i]; + trace(strumLineNotes.members[i].x + " " + strumLineNotes.members[i].y + " " + strumLineNotes.members[i].angle + " | strum" + i); + //setVar("strum" + i + "X", Math.floor(member.x)); + setVar("defaultStrum" + i + "X", Math.floor(member.x)); + //setVar("strum" + i + "Y", Math.floor(member.y)); + setVar("defaultStrum" + i + "Y", Math.floor(member.y)); + //setVar("strum" + i + "Angle", Math.floor(member.angle)); + setVar("defaultStrum" + i + "Angle", Math.floor(member.angle)); + trace("Adding strum" + i); + } + + trace('calling start function'); + + trace('return: ' + Lua.tostring(lua,callLua('start', [PlayState.SONG.song]))); + } + FlxG.sound.music.onComplete = endSong; vocals.play(); @@ -1249,7 +1717,6 @@ class PlayState extends MusicBeatState } } #end - var daBeats:Int = 0; // Not exactly representative of 'daBeats' lol, just how much it has looped for (section in noteData) { @@ -1604,6 +2071,53 @@ class PlayState extends MusicBeatState perfectMode = false; #end + if (executeModchart && lua != null) + { + setVar('songPos',Conductor.songPosition); + setVar('hudZoom', camHUD.zoom); + setVar('cameraZoom',FlxG.camera.zoom); + callLua('update', [elapsed]); + + /*for (i in 0...strumLineNotes.length) { + var member = strumLineNotes.members[i]; + member.x = getVar("strum" + i + "X", "float"); + member.y = getVar("strum" + i + "Y", "float"); + member.angle = getVar("strum" + i + "Angle", "float"); + }*/ + + FlxG.camera.angle = getVar('cameraAngle', 'float'); + camHUD.angle = getVar('camHudAngle','float'); + + if (getVar("showOnlyStrums",'bool')) + { + healthBarBG.visible = false; + kadeEngineWatermark.visible = false; + healthBar.visible = false; + iconP1.visible = false; + iconP2.visible = false; + scoreTxt.visible = false; + } + else + { + healthBarBG.visible = true; + kadeEngineWatermark.visible = true; + healthBar.visible = true; + iconP1.visible = true; + iconP2.visible = true; + scoreTxt.visible = true; + } + + var p1 = getVar("strumLine1Visible",'bool'); + var p2 = getVar("strumLine2Visible",'bool'); + + for (i in 0...4) + { + strumLineNotes.members[i].visible = p1; + if (i <= playerStrums.length) + playerStrums.members[i].visible = p2; + } + } + if (currentFrames == FlxG.save.data.fpsCap) { for(i in 0...notesHitArray.length) @@ -1683,6 +2197,11 @@ class PlayState extends MusicBeatState DiscordClient.changePresence("Chart Editor", null, null, true); #end FlxG.switchState(new ChartingState()); + if (lua != null) + { + Lua.close(lua); + lua = null; + } } // FlxG.watch.addQuick('VOL', vocals.amplitudeLeft); @@ -1717,7 +2236,15 @@ class PlayState extends MusicBeatState #if debug if (FlxG.keys.justPressed.EIGHT) + { FlxG.switchState(new AnimationDebug(SONG.player2)); + if (lua != null) + { + Lua.close(lua); + lua = null; + } + } + #end if (startingSong) @@ -1857,7 +2384,7 @@ class PlayState extends MusicBeatState if (camFollow.x != dad.getMidpoint().x + 150 && !PlayState.SONG.notes[Std.int(curStep / 16)].mustHitSection) { - camFollow.setPosition(dad.getMidpoint().x + 150, dad.getMidpoint().y - 100); + camFollow.setPosition(dad.getMidpoint().x + 150 + (lua != null ? getVar("followXOffset", "float") : 0), dad.getMidpoint().y - 100 + (lua != null ? getVar("followYOffset", "float") : 0)); // camFollow.setPosition(lucky.getMidpoint().x - 120, lucky.getMidpoint().y + 210); switch (dad.curCharacter) @@ -1883,7 +2410,7 @@ class PlayState extends MusicBeatState if (PlayState.SONG.notes[Std.int(curStep / 16)].mustHitSection && camFollow.x != boyfriend.getMidpoint().x - 100) { - camFollow.setPosition(boyfriend.getMidpoint().x - 100, boyfriend.getMidpoint().y - 100); + camFollow.setPosition(boyfriend.getMidpoint().x - 100 + (lua != null ? getVar("followXOffset", "float") : 0), boyfriend.getMidpoint().y - 100 + (lua != null ? getVar("followYOffset", "float") : 0)); switch (curStage) { @@ -2003,7 +2530,7 @@ class PlayState extends MusicBeatState { if (SONG.song != 'Tutorial') camZooming = true; - + var altAnim:String = ""; if (SONG.notes[Math.floor(curStep / 16)] != null) @@ -2029,6 +2556,8 @@ class PlayState extends MusicBeatState if (SONG.needsVoices) vocals.volume = 1; + daNote.active = false; + daNote.kill(); notes.remove(daNote, true); daNote.destroy(); @@ -2038,6 +2567,29 @@ class PlayState extends MusicBeatState daNote.y = (strumLine.y - (Conductor.songPosition - daNote.strumTime) * (-0.45 * FlxMath.roundDecimal(FlxG.save.data.scrollSpeed == 1 ? SONG.speed : FlxG.save.data.scrollSpeed, 2))); else daNote.y = (strumLine.y - (Conductor.songPosition - daNote.strumTime) * (0.45 * FlxMath.roundDecimal(FlxG.save.data.scrollSpeed == 1 ? SONG.speed : FlxG.save.data.scrollSpeed, 2))); + + if (daNote.mustPress && !daNote.modifiedByLua) + { + daNote.visible = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].visible; + daNote.x = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].x; + if (!daNote.isSustainNote) + daNote.angle = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].angle; + daNote.alpha = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].alpha; + } + else if (!daNote.wasGoodHit && !daNote.modifiedByLua) + { + daNote.visible = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].visible; + daNote.x = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].x; + if (!daNote.isSustainNote) + daNote.angle = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].angle; + daNote.alpha = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].alpha; + } + + + + if (daNote.isSustainNote) + daNote.x += daNote.width / 2 + 7; + //trace(daNote.y); // WIP interpolation shit? Need to fix the pause issue // daNote.y = (strumLine.y - (songTime - daNote.strumTime) * (0.45 * PlayState.SONG.speed)); @@ -2084,6 +2636,12 @@ class PlayState extends MusicBeatState if (!loadRep) rep.SaveReplay(); + if (executeModchart) + { + Lua.close(lua); + lua = null; + } + canPause = false; FlxG.sound.music.volume = 0; vocals.volume = 0; @@ -2118,6 +2676,12 @@ class PlayState extends MusicBeatState FlxG.switchState(new StoryMenuState()); + if (lua != null) + { + Lua.close(lua); + lua = null; + } + // if () StoryMenuState.weekUnlocked[Std.int(Math.min(storyWeek + 1, StoryMenuState.weekUnlocked.length - 1))] = true; @@ -3136,6 +3700,12 @@ class PlayState extends MusicBeatState resyncVocals(); } + if (executeModchart && lua != null) + { + setVar('curStep',curStep); + callLua('stepHit',[curStep]); + } + if (dad.curCharacter == 'spooky' && curStep % 4 == 2) { // dad.dance(); @@ -3167,6 +3737,12 @@ class PlayState extends MusicBeatState notes.sort(FlxSort.byY, FlxSort.DESCENDING); } + if (executeModchart && lua != null) + { + setVar('curBeat',curBeat); + callLua('beatHit',[curBeat]); + } + if (SONG.notes[Math.floor(curStep / 16)] != null) { if (SONG.notes[Math.floor(curStep / 16)].changeBPM) diff --git a/source/TitleState.hx b/source/TitleState.hx index def04db..3afcf92 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -59,6 +59,10 @@ class TitleState extends MusicBeatState sys.FileSystem.createDirectory(Sys.getCwd() + "/assets/replays"); #end + @:privateAccess + { + trace("Loaded " + openfl.Assets.getLibrary("default").assetsLoaded + " assets (DEFAULT)"); + } PlayerSettings.init();