316 lines
8 KiB
Haxe
316 lines
8 KiB
Haxe
|
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<AnimArray>;
|
||
|
var image:String;
|
||
|
var scale:Float;
|
||
|
var sing_duration:Float;
|
||
|
var healthicon:String;
|
||
|
|
||
|
var position:Array<Float>;
|
||
|
var camera_position:Array<Float>;
|
||
|
|
||
|
var flip_x:Bool;
|
||
|
var no_antialiasing:Bool;
|
||
|
var healthbar_colors:Array<Int>;
|
||
|
}
|
||
|
|
||
|
typedef AnimArray = {
|
||
|
var anim:String;
|
||
|
var name:String;
|
||
|
var fps:Int;
|
||
|
var loop:Bool;
|
||
|
var indices:Array<Int>;
|
||
|
var offsets:Array<Int>;
|
||
|
}
|
||
|
|
||
|
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 = 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<Dynamic> = [];
|
||
|
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<AnimArray> = [];
|
||
|
|
||
|
public var positionArray:Array<Float> = [0, 0];
|
||
|
public var cameraPosition:Array<Float> = [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<Int> = [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<String, Array<Dynamic>>();
|
||
|
#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<Int> = 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);
|
||
|
}
|
||
|
}
|