package; import flixel.FlxG; import flixel.FlxSprite; import flixel.animation.FlxBaseAnimation; import flixel.graphics.frames.FlxAtlasFrames; import flixel.tweens.FlxTween; import flixel.util.FlxSort; import Section.SwagSection; #if MODS_ALLOWED import sys.io.File; import sys.FileSystem; #end import openfl.utils.Assets; import haxe.Json; import haxe.format.JsonParser; using StringTools; typedef CharacterFile = { var animations:Array; var image:String; var scale:Float; var sing_duration:Float; var healthicon:String; var position:Array; var camera_position:Array; var flip_x:Bool; var no_antialiasing:Bool; var healthbar_colors:Array; } typedef AnimArray = { var anim:String; var name:String; var fps:Int; var loop:Bool; var indices:Array; var offsets:Array; } class Character extends FlxSprite { public var animOffsets:Map>; public var debugMode:Bool = false; public var isPlayer:Bool = false; public var curCharacter:String = DEFAULT_CHARACTER; public var colorTween:FlxTween; public var holdTimer:Float = 0; public var heyTimer:Float = 0; public var specialAnim:Bool = false; public var animationNotes:Array = []; public var stunned:Bool = false; public var singDuration:Float = 4; //Multiplier of how long a character holds the sing pose public var idleSuffix:String = ''; public var danceIdle:Bool = false; //Character use "danceLeft" and "danceRight" instead of "idle" public var healthIcon:String = 'face'; public var animationsArray:Array = []; public var positionArray:Array = [0, 0]; public var cameraPosition:Array = [0, 0]; //Used on Character Editor public var imageFile:String = ''; public var jsonScale:Float = 1; public var noAntialiasing:Bool = false; public var originalFlipX:Bool = false; public var healthColorArray:Array = [255, 0, 0]; public var alreadyLoaded:Bool = true; //Used by "Change Character" event public static var DEFAULT_CHARACTER:String = 'bf'; //In case a character is missing, it will use BF on its place public function new(x:Float, y:Float, ?character:String = 'bf', ?isPlayer:Bool = false) { super(x, y); #if (haxe >= "4.0.0") animOffsets = new Map(); #else animOffsets = new Map>(); #end curCharacter = character; this.isPlayer = isPlayer; antialiasing = ClientPrefs.globalAntialiasing; var library:String = null; switch (curCharacter) { //case 'your character name in case you want to hardcode him instead': default: var characterPath:String = 'characters/' + curCharacter + '.json'; #if MODS_ALLOWED var path:String = Paths.modFolders(characterPath); if (!FileSystem.exists(path)) { path = Paths.getPreloadPath(characterPath); } if (!FileSystem.exists(path)) #else var path:String = Paths.getPreloadPath(characterPath); if (!Assets.exists(path)) #end { path = Paths.getPreloadPath('characters/' + DEFAULT_CHARACTER + '.json'); //If a character couldn't be found, change him to BF just to prevent a crash } #if MODS_ALLOWED var rawJson = File.getContent(path); #else var rawJson = Assets.getText(path); #end var json:CharacterFile = cast Json.parse(rawJson); if(Assets.exists(Paths.getPath('images/' + json.image + '.txt', TEXT))) { frames = Paths.getPackerAtlas(json.image); } else { frames = Paths.getSparrowAtlas(json.image); } imageFile = json.image; if(json.scale != 1) { jsonScale = json.scale; setGraphicSize(Std.int(width * jsonScale)); updateHitbox(); } positionArray = json.position; cameraPosition = json.camera_position; healthIcon = json.healthicon; singDuration = json.sing_duration; flipX = !!json.flip_x; if(json.no_antialiasing) { antialiasing = false; noAntialiasing = true; } if(json.healthbar_colors != null && json.healthbar_colors.length > 2) healthColorArray = json.healthbar_colors; antialiasing = !noAntialiasing; if(!ClientPrefs.globalAntialiasing) antialiasing = false; animationsArray = json.animations; if(animationsArray != null && animationsArray.length > 0) { for (anim in animationsArray) { var animAnim:String = '' + anim.anim; var animName:String = '' + anim.name; var animFps:Int = anim.fps; var animLoop:Bool = !!anim.loop; //Bruh var animIndices:Array = anim.indices; if(animIndices != null && animIndices.length > 0) { animation.addByIndices(animAnim, animName, animIndices, "", animFps, animLoop); } else { animation.addByPrefix(animAnim, animName, animFps, animLoop); } if(anim.offsets != null && anim.offsets.length > 1) { addOffset(anim.anim, anim.offsets[0], anim.offsets[1]); } } } else { quickAnimAdd('idle', 'BF idle dance'); } //trace('Loaded file to character ' + curCharacter); } originalFlipX = flipX; recalculateDanceIdle(); dance(); if (isPlayer) { flipX = !flipX; /*// Doesn't flip for BF, since his are already in the right place??? if (!curCharacter.startsWith('bf')) { // var animArray if(animation.getByName('singLEFT') != null && animation.getByName('singRIGHT') != null) { 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('singLEFTmiss') != null && animation.getByName('singRIGHTmiss') != null) { var oldMiss = animation.getByName('singRIGHTmiss').frames; animation.getByName('singRIGHTmiss').frames = animation.getByName('singLEFTmiss').frames; animation.getByName('singLEFTmiss').frames = oldMiss; } }*/ } } override function update(elapsed:Float) { if(!debugMode && animation.curAnim != null) { if(heyTimer > 0) { heyTimer -= elapsed; if(heyTimer <= 0) { if(specialAnim && animation.curAnim.name == 'hey' || animation.curAnim.name == 'cheer') { specialAnim = false; dance(); } heyTimer = 0; } } else if(specialAnim && animation.curAnim.finished) { specialAnim = false; dance(); } if (!isPlayer) { if (animation.curAnim.name.startsWith('sing')) { holdTimer += elapsed; } if (holdTimer >= Conductor.stepCrochet * 0.001 * singDuration) { dance(); holdTimer = 0; } } if(animation.curAnim.finished && animation.getByName(animation.curAnim.name + '-loop') != null) { playAnim(animation.curAnim.name + '-loop'); } } super.update(elapsed); } public var danced:Bool = false; /** * FOR GF DANCING SHIT */ public function dance() { if (!debugMode && !specialAnim) { if(danceIdle) { danced = !danced; if (danced) playAnim('danceRight' + idleSuffix); else playAnim('danceLeft' + idleSuffix); } else if(animation.getByName('idle' + idleSuffix) != null) { playAnim('idle' + idleSuffix); } } } public function playAnim(AnimName:String, Force:Bool = false, Reversed:Bool = false, Frame:Int = 0):Void { specialAnim = false; 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.startsWith('gf')) { if (AnimName == 'singLEFT') { danced = true; } else if (AnimName == 'singRIGHT') { danced = false; } if (AnimName == 'singUP' || AnimName == 'singDOWN') { danced = !danced; } } } public function recalculateDanceIdle() { danceIdle = (animation.getByName('danceLeft' + idleSuffix) != null && animation.getByName('danceRight' + idleSuffix) != null); } public function addOffset(name:String, x:Float = 0, y:Float = 0) { animOffsets[name] = [x, y]; } public function quickAnimAdd(name:String, anim:String) { animation.addByPrefix(name, anim, 24, false); } }