diff --git a/assets/preload/sounds/nothing.ogg b/assets/preload/sounds/nothing.ogg deleted file mode 100644 index 9c92313..0000000 Binary files a/assets/preload/sounds/nothing.ogg and /dev/null differ diff --git a/mods/skins/characterSelect.json b/mods/global characters/characterSelect.json similarity index 100% rename from mods/skins/characterSelect.json rename to mods/global characters/characterSelect.json diff --git a/mods/skins/readme.txt b/mods/global characters/readme.txt similarity index 100% rename from mods/skins/readme.txt rename to mods/global characters/readme.txt diff --git a/mods/test/Icon.png b/mods/test/Icon.png index 47604f8..870f8c0 100644 Binary files a/mods/test/Icon.png and b/mods/test/Icon.png differ diff --git a/mods/test/data/characterSelect.json b/mods/test/data/characterSelect.json index 8124509..48cc447 100644 --- a/mods/test/data/characterSelect.json +++ b/mods/test/data/characterSelect.json @@ -3,10 +3,10 @@ { "newCharacter": [ { - "playername": "bf-pixel", - "thecharactername": "Test", + "playername": "Example", + "thecharactername": "Example", "thenotems": [1, 1, 1, 1], - "notestyle": "" + "notestyle": "3D" } ], "mainName": "testtwo", diff --git a/mods/test/data/characters/Example.json b/mods/test/data/characters/Example.json new file mode 100644 index 0000000..aa2e21c --- /dev/null +++ b/mods/test/data/characters/Example.json @@ -0,0 +1,49 @@ +{ + "animations": [ + { + "animName": "idle", + "anim": "idle", + "fps": 24, + "loop": true + }, + { + "animName": "singUP", + "anim": "up", + "fps": 24, + "loop": false + + }, + { + "animName": "singLEFT", + "anim": "left", + "fps": 24, + "loop": false + + }, + { + "animName": "singRIGHT", + "anim": "right", + "fps": 24, + "loop": false + }, + { + "animName": "singDOWN", + "anim": "down", + "fps": 24, + "loop": false + } + ], + "globalOffset": [-480, -700], + "isPlayable": false, + "skins": [], + "barcolor": { + "red": 0, + "green": 215, + "blue": 0 + }, + "antialiasing": true, + "nativelyPlayable": true, + "flipX": true, + "updateHitbox": true, + "setGraphicSize": "" +} diff --git a/mods/test/images/characters/Example.png b/mods/test/images/characters/Example.png new file mode 100644 index 0000000..fe60809 Binary files /dev/null and b/mods/test/images/characters/Example.png differ diff --git a/mods/test/images/characters/Example.xml b/mods/test/images/characters/Example.xml new file mode 100644 index 0000000..b1b24b4 --- /dev/null +++ b/mods/test/images/characters/Example.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mods/test/images/icons/Example.png b/mods/test/images/icons/Example.png new file mode 100644 index 0000000..dfc4fc7 Binary files /dev/null and b/mods/test/images/icons/Example.png differ diff --git a/mods/test/offsets/Example.txt b/mods/test/offsets/Example.txt new file mode 100644 index 0000000..c95ca27 --- /dev/null +++ b/mods/test/offsets/Example.txt @@ -0,0 +1,5 @@ +idle 0 0 +singUP 0 0 +singRIGHT 0 0 +singLEFT 0 0 +singDOWN 0 0 \ No newline at end of file diff --git a/source/Character.hx b/source/Character.hx index b3cd89e..943503c 100644 --- a/source/Character.hx +++ b/source/Character.hx @@ -1,6 +1,7 @@ package; import sys.FileSystem; +import sys.io.File; import flixel.math.FlxPoint; import flixel.util.FlxColor; import flixel.addons.effects.chainable.FlxEffectSprite; @@ -9,9 +10,45 @@ import flixel.FlxSprite; import flixel.animation.FlxBaseAnimation; import flixel.graphics.frames.FlxAtlasFrames; import haxe.Json; +import haxe.format.JsonParser; using StringTools; +typedef CharacterFile = +{ + var animations:Array; + var globalOffset:Array; + var isPlayable:Bool; + var skins:Array; + var barcolor:RGB; + var antialiasing:Bool; + var nativelyPlayable:Bool; + var flipX:Bool; + var updateHitbox:Bool; + var setGraphicSize:String; +} + +typedef Anim = +{ + var animName:String; + var anim:String; + var fps:Int; + var loop:Bool; +} + +typedef SkinSet = +{ + var type:String; + var replacement:String; +} + +typedef RGB = +{ + var red:Int; + var green:Int; + var blue:Int; +} + class Character extends FlxSprite { public var animOffsets:Map>; @@ -33,6 +70,8 @@ class Character extends FlxSprite public var canSing:Bool = true; public var skins:Map = new Map(); + public var rawJsonCustom:String; + public var jsonCustom:CharacterFile; public function new(x:Float, y:Float, ?character:String = "bf", ?isPlayer:Bool = false) { @@ -1144,6 +1183,135 @@ class Character extends FlxSprite loadOffsetFile(curCharacter); playAnim('firstDeath'); + + default: + if (FileSystem.exists(TitleState.modFolder + '/data/characters/${curCharacter}.json')) { + + rawJsonCustom = File.getContent((TitleState.modFolder + '/data/characters/${curCharacter}.json')); + jsonCustom = cast Json.parse(rawJsonCustom); + + frames = Paths.getCustomSparrowAtlas(TitleState.modFolder + '/images/characters/' + curCharacter); + + for (i in jsonCustom.animations) { + animation.addByPrefix(i.animName, i.anim, i.fps, i.loop); + } + + if (!jsonCustom.isPlayable) { + loadCustomOffsetFile(curCharacter); + } else { + loadCustomOffsetFile(curCharacter + (isPlayer ? '-playable' : '')); + } + + globalOffset = jsonCustom.globalOffset; + + for (i in jsonCustom.skins) { + skins.set(i.type, i.replacement); + } + + barColor = FlxColor.fromRGB(jsonCustom.barcolor.red, jsonCustom.barcolor.green, jsonCustom.barcolor.blue); + + if (jsonCustom.setGraphicSize != '') + { + var thing = jsonCustom.setGraphicSize; + setGraphicSize(Std.int(width * Reflect.field(PlayState, thing))); + } + + if (jsonCustom.updateHitbox) + { + updateHitbox(); + } + + nativelyPlayable = jsonCustom.nativelyPlayable; + + antialiasing = jsonCustom.antialiasing; + + + + flipX = jsonCustom.flipX; + + playAnim('idle'); + } else if (FileSystem.exists('mods/global characters/characters/${curCharacter}.json')) { + + rawJsonCustom = File.getContent(('mods/global characters/characters/${curCharacter}.json')); + jsonCustom = cast Json.parse(rawJsonCustom); + + frames = Paths.getCustomSparrowAtlas('mods/global characters/images/' + curCharacter); + + for (i in jsonCustom.animations) { + animation.addByPrefix(i.animName, i.anim, i.fps, i.loop); + } + + if (!jsonCustom.isPlayable) { + loadCustomOffsetFile(curCharacter); + } else { + loadCustomOffsetFile(curCharacter + (isPlayer ? '-playable' : '')); + } + + globalOffset = jsonCustom.globalOffset; + + for (i in jsonCustom.skins) { + skins.set(i.type, i.replacement); + } + + barColor = FlxColor.fromRGB(jsonCustom.barcolor.red, jsonCustom.barcolor.green, jsonCustom.barcolor.blue); + + if (jsonCustom.setGraphicSize != '') + { + var thing = jsonCustom.setGraphicSize; + setGraphicSize(Std.int(width * Reflect.field(PlayState, thing))); + } + + if (jsonCustom.updateHitbox) + { + updateHitbox(); + } + + nativelyPlayable = jsonCustom.nativelyPlayable; + + antialiasing = jsonCustom.antialiasing; + + + + flipX = jsonCustom.flipX; + + playAnim('idle'); + + } else { + + frames = Paths.getSparrowAtlas('characters/BOYFRIEND', 'shared'); + + animation.addByPrefix('idle', 'BF idle dance', 24, false); + animation.addByPrefix('singUP', 'BF NOTE UP0', 24, false); + animation.addByPrefix('singLEFT', 'BF NOTE LEFT0', 24, false); + animation.addByPrefix('singRIGHT', 'BF NOTE RIGHT0', 24, false); + animation.addByPrefix('singDOWN', 'BF NOTE DOWN0', 24, false); + animation.addByPrefix('singUPmiss', 'BF NOTE UP MISS', 24, false); + animation.addByPrefix('singLEFTmiss', 'BF NOTE LEFT MISS', 24, false); + animation.addByPrefix('singRIGHTmiss', 'BF NOTE RIGHT MISS', 24, false); + animation.addByPrefix('singDOWNmiss', 'BF NOTE DOWN MISS', 24, false); + animation.addByPrefix('hey', 'BF HEY', 24, false); + + animation.addByPrefix('firstDeath', "BF dies", 24, false); + animation.addByPrefix('deathLoop', "BF Dead Loop", 24, true); + animation.addByPrefix('deathConfirm', "BF Dead confirm", 24, false); + animation.addByPrefix('dodge', "boyfriend dodge", 24, false); + animation.addByPrefix('scared', 'BF idle shaking', 24); + animation.addByPrefix('hit', 'BF hit', 24, false); + + loadOffsetFile('bf'); + + skins.set('gfSkin', 'gf'); + skins.set('3d', 'bf-3d'); + + barColor = FlxColor.fromRGB(49, 176, 209); + + + playAnim('idle'); + + nativelyPlayable = true; + + flipX = true; + } } dance(); @@ -1165,6 +1333,17 @@ class Character extends FlxSprite } } + function loadCustomOffsetFile(character:String) + { + var offsetStuffs:Array = CoolUtil.coolTextFile(TitleState.modFolder + '/offsets/' + character + '.txt'); + + for (offsetText in offsetStuffs) + { + var offsetInfo:Array = offsetText.split(' '); + + addOffset(offsetInfo[0], Std.parseFloat(offsetInfo[1]), Std.parseFloat(offsetInfo[2])); + } + } override function update(elapsed:Float) { if (animation == null) diff --git a/source/CharacterSelectState.hx b/source/CharacterSelectState.hx index 0509c57..224c96d 100644 --- a/source/CharacterSelectState.hx +++ b/source/CharacterSelectState.hx @@ -174,7 +174,7 @@ class CharacterSelectState extends MusicBeatState } rawJson = File.getContent(Paths.json('characterSelect')); json = cast Json.parse(rawJson); - rawJsonCustom = File.getContent(('mods/skins/characterSelect.json')); + rawJsonCustom = File.getContent(('mods/global characters/characterSelect.json')); jsonCustom = cast Json.parse(rawJsonCustom); if (FileSystem.exists(TitleState.modFolder + '/data/characterSelect.json')) { rawJsonCustom2 = File.getContent((TitleState.modFolder + '/data/characterSelect.json')); @@ -194,7 +194,7 @@ class CharacterSelectState extends MusicBeatState characters.push(new CharacterInSelect(mainName, thehotemsithink, newCharacterForms)); } - if (FileSystem.exists('mods/skins/characterSelect.json')) { + if (FileSystem.exists('mods/global characters/characterSelect.json')) { for (character in jsonCustom.characters) { // For Globle Characters var mainName:String = character.mainName; var thehotemsithink:Array = character.mainnotems; diff --git a/source/CreditsPopUp.hx b/source/CreditsPopUp.hx index c16aa89..bfdbfea 100644 --- a/source/CreditsPopUp.hx +++ b/source/CreditsPopUp.hx @@ -162,7 +162,7 @@ class CreditsPopUp extends FlxSpriteGroup bg.loadGraphic(Paths.image(headingPath.path)); } else { trace('nae'); - bg.loadGraphic(Paths.customImage('images/' + headingPath.path)); + bg.loadGraphic(Paths.customImage(TitleState.modFolder + '/images/' + headingPath.path)); } } else @@ -181,7 +181,7 @@ class CreditsPopUp extends FlxSpriteGroup rescaleIcon(); add(funnyIcon); } else { - funnyIcon = new FlxSprite(0, 0, Paths.customImage('images/songCreators/' + songCreator)); + funnyIcon = new FlxSprite(0, 0, Paths.customImage(TitleState.modFolder + '/images/songCreators/' + songCreator)); rescaleIcon(); add(funnyIcon); } diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index a344ce4..73255fc 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -230,7 +230,7 @@ class FreeplayState extends MusicBeatState titles.push(NameAlpha); } else { trace('nae'); - var CurrentSongIcon:FlxSprite = new FlxSprite(0,0).loadGraphic(Paths.customImage('Icon')); + var CurrentSongIcon:FlxSprite = new FlxSprite(0,0).loadGraphic(Paths.customImage(TitleState.modFolder + '/Icon')); CurrentSongIcon.centerOffsets(false); CurrentSongIcon.x = (1000 * i + 1) + (512 - CurrentSongIcon.width); CurrentSongIcon.y = (FlxG.height / 2) - 256; diff --git a/source/HealthIcon.hx b/source/HealthIcon.hx index bb61e2e..7a60589 100644 --- a/source/HealthIcon.hx +++ b/source/HealthIcon.hx @@ -1,5 +1,6 @@ package; +import sys.FileSystem; import flixel.FlxSprite; import flixel.math.FlxMath; import flixel.graphics.FlxGraphic; @@ -37,7 +38,15 @@ class HealthIcon extends FlxSprite if (this.char != char) { if (char != "none") + if (FileSystem.exists('assets/images/ui/iconGrid/' + char + '.png')) { loadGraphic(FlxGraphic.fromBitmapData(BitmapData.fromFile(Paths.image('ui/iconGrid/' + char, 'preload'))), true, 150, 150); + } else if (FileSystem.exists('mods/global characters/icons/' + char + '.png')) { + loadGraphic(Paths.customImage('mods/global characters/images/icons/' + char), true, 150, 150); + } else if (FileSystem.exists(TitleState.modFolder + '/images/icons/' + char + '.png')) { + loadGraphic(Paths.customImage(TitleState.modFolder + '/images/icons/' + char), true, 150, 150); + } else { + loadGraphic(Paths.image('blank', 'shared')); + } else loadGraphic(Paths.image('blank', 'shared')); diff --git a/source/Paths.hx b/source/Paths.hx index 943e413..339b7e1 100644 --- a/source/Paths.hx +++ b/source/Paths.hx @@ -8,6 +8,7 @@ import openfl.utils.AssetType; import openfl.utils.Assets as OpenFlAssets; #if sys import sys.FileSystem; #end import flash.media.Sound; +import sys.io.File; class Paths { @@ -88,6 +89,13 @@ class Paths } } + inline static public function customFile(file:String) + { + var defaultReturnPath = File.getContent(file); + + return defaultReturnPath; + } + inline static public function txt(key:String, ?library:String) { var defaultReturnPath = getPath('data/$key.txt', TEXT, library); @@ -158,7 +166,7 @@ class Paths inline static public function customImage(key:String) { - return (FlxGraphic.fromBitmapData(BitmapData.fromFile(TitleState.modFolder + '/${key}.png'))); + return (FlxGraphic.fromBitmapData(BitmapData.fromFile('${key}.png'))); } inline static public function music(key:String, ?library:String) { @@ -287,14 +295,24 @@ class Paths inline static public function getSparrowAtlas(key:String, ?library:String) { - return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library)); + return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library)); } + inline static public function getCustomSparrowAtlas(key:String) + { + return FlxAtlasFrames.fromSparrow(customImage(key), customFile('$key.xml')); + } + inline static public function getPackerAtlas(key:String, ?library:String) { return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library)); } + inline static public function getCustomPackerAtlas(key:String) + { + return FlxAtlasFrames.fromSpriteSheetPacker(customImage(key), customFile('$key.txt')); + } + inline static public function video(key:String, ?library:String) { return getPath('videos/$key.mp4', BINARY, library); diff --git a/source/TitleState.hx b/source/TitleState.hx index 3a53ea5..b5bb453 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -127,7 +127,7 @@ class TitleState extends MusicBeatState if(FileSystem.exists('mods')) { for (folder in FileSystem.readDirectory('mods')){ - if (FileSystem.isDirectory('mods/' + folder) && !mods.contains(folder) && folder != 'skins') + if (FileSystem.isDirectory('mods/' + folder) && !mods.contains(folder) && folder != 'global characters') mods.push(folder); } }