diff --git a/source/editors/CharacterEditorState.hx b/source/editors/CharacterEditorState.hx index 250d5ad6d4e..c9d52dda9b5 100644 --- a/source/editors/CharacterEditorState.hx +++ b/source/editors/CharacterEditorState.hx @@ -1,6 +1,5 @@ package editors; -import animateatlas.AtlasFrameMaker; import flixel.FlxG; import flixel.FlxObject; import flixel.FlxSprite; @@ -10,6 +9,7 @@ import flixel.input.keyboard.FlxKey; import flixel.addons.display.FlxGridOverlay; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxAtlasFrames; import flixel.text.FlxText; import flixel.util.FlxColor; import flixel.addons.ui.FlxInputText; @@ -18,6 +18,7 @@ import flixel.addons.ui.FlxUI; import flixel.addons.ui.FlxUICheckBox; import flixel.addons.ui.FlxUIInputText; import flixel.addons.ui.FlxUINumericStepper; +import flixel.addons.ui.FlxUISlider; import flixel.addons.ui.FlxUITabMenu; import flixel.addons.ui.FlxUITooltip.FlxUITooltipStyle; import flixel.ui.FlxButton; @@ -44,14 +45,17 @@ class CharacterEditorState extends MusicBeatState { var music:EditingMusic; var char:Character; - var ghostChar:Character; - var textAnim:FlxText; + var ghostChar:FlxSprite; + var animateGhost:FlxAnimate; + var animateGhostImage:String; var bgLayer:FlxTypedGroup; var charLayer:FlxTypedGroup; - var dumbTexts:FlxTypedGroup; - var animList:Array = []; + var ghostLayer:FlxTypedGroup; + var animsTxt:FlxText; + var frameAdvanceText:FlxText; + var animList:Array = null; var curAnim:Int = 0; - var daAnim:String = 'spooky'; + var _char:String = 'spooky'; var goToPlayState:Bool = true; var camFollow:FlxObject; @@ -65,16 +69,21 @@ class CharacterEditorState extends MusicBeatState */ var checkifChanged:Array = []; - public function new(daAnim:String = 'spooky', goToPlayState:Bool = true) + public function new(_char:String = 'spooky', goToPlayState:Bool = true) { super(); - this.daAnim = daAnim; + this._char = _char; this.goToPlayState = goToPlayState; } + var helpBg:FlxSprite; + var helpTexts:FlxSpriteGroup; + var UI_box:FlxUITabMenu; var UI_characterbox:FlxUITabMenu; + var selectedFormat:FlxTextFormat = new FlxTextFormat(FlxColor.LIME); + private var camEditor:FlxCamera; private var camHUD:FlxCamera; private var camMenu:FlxCamera; @@ -103,6 +112,8 @@ class CharacterEditorState extends MusicBeatState add(bgLayer); charLayer = new FlxTypedGroup(); add(charLayer); + ghostLayer = new FlxTypedGroup(); + add(ghostLayer); var pointer:FlxGraphic = FlxGraphic.fromClass(GraphicCursorCross); cameraFollowPointer = new FlxSprite().loadGraphic(pointer); @@ -118,7 +129,8 @@ class CharacterEditorState extends MusicBeatState }); changeBGbutton.cameras = [camMenu]; - loadChar(!daAnim.startsWith('bf'), false); + addCharacter(); + reloadBGs(); healthBarBG = new FlxSprite(30, FlxG.height - 75).loadGraphic(Paths.image('editorHealthBar')); healthBarBG.scrollFactor.set(); @@ -130,53 +142,44 @@ class CharacterEditorState extends MusicBeatState add(leHealthIcon); leHealthIcon.cameras = [camHUD]; - dumbTexts = new FlxTypedGroup(); - add(dumbTexts); - dumbTexts.cameras = [camHUD]; + ghostChar = new FlxSprite(); + ghostChar.visible = false; + ghostChar.alpha = ghostAlpha; + ghostLayer.add(ghostChar); - textAnim = new FlxText(300, 16); - textAnim.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK); - textAnim.borderSize = 1; - textAnim.size = 32; - textAnim.scrollFactor.set(); - textAnim.cameras = [camHUD]; - add(textAnim); + animsTxt = new FlxText(10, 32, 400, ''); + animsTxt.setFormat(null, 16, FlxColor.WHITE, LEFT, OUTLINE_FAST, FlxColor.BLACK); + animsTxt.scrollFactor.set(); + animsTxt.borderSize = 1; + animsTxt.cameras = [camHUD]; + add(animsTxt); - genBoyOffsets(); + updateText(); camFollow = new FlxObject(0, 0, 2, 2); camFollow.screenCenter(); add(camFollow); - var tipTextArray:Array = "E/Q - Camera Zoom In/Out - \nR - Reset Camera Zoom - \nJKLI - Move Camera - \nW/S - Previous/Next Animation - \nSpace - Play Animation - \nArrow Keys/RMB - Move Offset - \nT - Reset Current Offset - \nHold Shift to Move 10x faster\n".split('\n'); - - for (i in 0...tipTextArray.length-1) - { - var tipText:FlxText = new FlxText(FlxG.width - 320, FlxG.height - 10 - 11 * (tipTextArray.length - i), 300, tipTextArray[i], 10); - tipText.cameras = [camHUD]; - tipText.setFormat(null, 10, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE_FAST, FlxColor.BLACK); - tipText.scrollFactor.set(); - tipText.borderSize = 1; - add(tipText); - } + var tipText:FlxText = new FlxText(FlxG.width - 300, FlxG.height - 24, 300, "Press F1 for Help", 20); + tipText.cameras = [camHUD]; + tipText.setFormat(null, 16, FlxColor.WHITE, RIGHT, OUTLINE_FAST, FlxColor.BLACK); + tipText.borderColor = FlxColor.BLACK; + tipText.scrollFactor.set(); + tipText.borderSize = 1; + tipText.active = false; + add(tipText); FlxG.camera.follow(camFollow, null, 999); var tabs = [ + {name: 'Ghost', label: 'Ghost'}, {name: 'Settings', label: 'Settings'}, ]; UI_box = new FlxUITabMenu(null, tabs, true); UI_box.cameras = [camMenu]; - UI_box.resize(250, 100); + UI_box.resize(250, 120); UI_box.x = FlxG.width - 275; UI_box.y = 25; UI_box.scrollFactor.set(); @@ -198,18 +201,75 @@ class CharacterEditorState extends MusicBeatState add(changeBGbutton); addSettingsUI(); - + addGhostUI(); addCharacterUI(); addAnimationsUI(); addMiscUI(); + + UI_box.selected_tab_id = 'Settings'; UI_characterbox.selected_tab_id = 'Character'; + frameAdvanceText = new FlxText(0, 75, 350, ''); + frameAdvanceText.setFormat(null, 16, FlxColor.WHITE, CENTER, OUTLINE_FAST, FlxColor.BLACK); + frameAdvanceText.scrollFactor.set(); + frameAdvanceText.borderSize = 1; + frameAdvanceText.screenCenter(X); + frameAdvanceText.cameras = [camHUD]; + add(frameAdvanceText); + + addHelpScreen(); FlxG.mouse.visible = true; reloadCharacterOptions(); super.create(); } + function addHelpScreen() + { + var str:Array = ["CAMERA", + "E/Q - Camera Zoom In/Out", + "J/K/L/I - Move Camera", + "R - Reset Camera Zoom", + "", + "CHARACTER", + "T - Reset Current Offset", + "W/S - Previous/Next Animation", + "Space - Replay Animation", + "Arrow Keys/Mouse & Right Click - Move Offset", + "A/D - Frame Advance (Back/Forward)", + "", + "OTHER", + "Hold Shift - Move Offsets 10x faster and Camera 4x faster"]; + + helpBg = new FlxSprite().makeGraphic(1, 1, FlxColor.BLACK); + helpBg.scale.set(FlxG.width, FlxG.height); + helpBg.updateHitbox(); + helpBg.alpha = 0.6; + helpBg.cameras = [camMenu]; + helpBg.active = helpBg.visible = false; + add(helpBg); + + helpTexts = new FlxSpriteGroup(); + helpTexts.cameras = [camMenu]; + for (i => txt in str) + { + if(txt.length < 1) continue; + + var helpText:FlxText = new FlxText(0, 0, 600, txt, 16); + helpText.setFormat(null, 16, FlxColor.WHITE, CENTER, OUTLINE_FAST, FlxColor.BLACK); + helpText.borderColor = FlxColor.BLACK; + helpText.scrollFactor.set(); + helpText.borderSize = 1; + helpText.screenCenter(); + add(helpText); + helpText.y += ((i - str.length/2) * 32) + 16; + helpText.active = false; + helpTexts.add(helpText); + } + helpTexts.active = helpTexts.visible = false; + add(helpTexts); + } + var barToUse:Int = 1; var onPixelBG:Bool = false; var OFFSET_X:Float = 300; @@ -360,6 +420,134 @@ class CharacterEditorState extends MusicBeatState "vocals_file": null }'; + function addCharacter(reload:Bool = false) + { + var pos:Int = -1; + if(char != null) + { + pos = members.indexOf(char); + remove(char); + char.destroy(); + } + + var isPlayer = (reload ? char.isPlayer : !predictCharacterIsNotPlayer(_char)); + char = new Character(0, 0, _char, isPlayer); + if(!reload && char.editorIsPlayer != null && isPlayer != char.editorIsPlayer) + { + char.isPlayer = !char.isPlayer; + char.flipX = (char.originalFlipX != char.isPlayer); + if(check_player != null) check_player.checked = char.isPlayer; + } + char.debugMode = true; + + char.setPosition(char.positionArray[0] + OFFSET_X + 100, char.positionArray[1]); + + if(pos > -1) charLayer.insert(pos, char); + else charLayer.add(char); + updateCharacterPositions(); + reloadCharacterOptions(); + try { reloadAnimList(); } catch(e) {} + if(healthBarBG != null && leHealthIcon != null) resetHealthBarColor(); + } + + var ghostAlpha:Float = 0.6; + function addGhostUI() + { + var tab_group = new FlxUI(null, UI_box); + tab_group.name = "Ghost"; + + //var hideGhostButton:FlxButton = null; + var makeGhostButton:FlxButton = new FlxButton(25, 15, "Make Ghost", function() { + var anim = animList[curAnim]; + if(!char.isAnimationNull()) + { + var myAnim = animList[curAnim]; + if(!char.isAnimateAtlas) + { + ghostChar.loadGraphic(char.graphic); + ghostChar.frames.frames = char.frames.frames; + ghostChar.animation.copyFrom(char.animation); + ghostChar.animation.play(char.animation.curAnim.name, true, false, char.animation.curAnim.curFrame); + ghostChar.animation.pause(); + } + else if(myAnim != null) //This is VERY unoptimized and bad, I hope to find a better replacement that loads only a specific frame as bitmap in the future. + { + if(animateGhost == null) //If I created the animateGhost on create() and you didn't load an atlas, it would crash the game on destroy, so we create it here + { + animateGhost = new FlxAnimate(ghostChar.x, ghostChar.y); + animateGhost.showPivot = false; + insert(members.indexOf(ghostChar), animateGhost); + animateGhost.active = false; + } + + if(animateGhost == null || animateGhostImage != char.imageFile) + Paths.loadAnimateAtlas(animateGhost, char.imageFile); + + if(myAnim.indices != null && myAnim.indices.length > 0) + animateGhost.anim.addBySymbolIndices('anim', myAnim.name, myAnim.indices, 0, false); + else + animateGhost.anim.addBySymbol('anim', myAnim.name, 0, false); + + animateGhost.anim.play('anim', true, false, char.atlas.anim.curFrame); + animateGhost.anim.pause(); + + animateGhostImage = char.imageFile; + } + + var spr:FlxSprite = !char.isAnimateAtlas ? ghostChar : animateGhost; + if(spr != null) + { + spr.setPosition(char.x, char.y); + spr.antialiasing = char.antialiasing; + spr.flipX = char.flipX; + spr.alpha = ghostAlpha; + + spr.scale.set(char.scale.x, char.scale.y); + spr.updateHitbox(); + + spr.offset.set(char.offset.x, char.offset.y); + spr.visible = true; + + var otherSpr:FlxSprite = (spr == animateGhost) ? ghostChar : animateGhost; + if(otherSpr != null) otherSpr.visible = false; + } + /*hideGhostButton.active = true; + hideGhostButton.alpha = 1;*/ + trace('created ghost image'); + } + }); + + var highlightGhost:FlxUICheckBox = new FlxUICheckBox(20 + makeGhostButton.x + makeGhostButton.width, makeGhostButton.y, null, null, "Highlight Ghost", 100); + highlightGhost.callback = function() + { + var value = highlightGhost.checked ? 125 : 0; + ghostChar.colorTransform.redOffset = value; + ghostChar.colorTransform.greenOffset = value; + ghostChar.colorTransform.blueOffset = value; + if(animateGhost != null) + { + animateGhost.colorTransform.redOffset = value; + animateGhost.colorTransform.greenOffset = value; + animateGhost.colorTransform.blueOffset = value; + } + }; + + var ghostAlphaSlider:FlxUISlider = new FlxUISlider(this, 'ghostAlpha', 10, makeGhostButton.y + 25, 0, 1, 210, null, 5, FlxColor.WHITE, FlxColor.BLACK); + ghostAlphaSlider.nameLabel.text = 'Opacity:'; + ghostAlphaSlider.decimals = 2; + ghostAlphaSlider.callback = function(relativePos:Float) { + ghostChar.alpha = ghostAlpha; + if(animateGhost != null) animateGhost.alpha = ghostAlpha; + }; + ghostAlphaSlider.value = ghostAlpha; + + tab_group.add(makeGhostButton); + //tab_group.add(hideGhostButton); + tab_group.add(highlightGhost); + tab_group.add(ghostAlphaSlider); + UI_box.addGroup(tab_group); + } + var charDropDown:FlxUIDropDownMenuCustom; var check_player:FlxUICheckBox; function addSettingsUI() { @@ -367,7 +555,7 @@ class CharacterEditorState extends MusicBeatState tab_group.name = "Settings"; check_player = new FlxUICheckBox(10, 60, null, null, "Playable Character", 100); - check_player.checked = daAnim.startsWith('bf'); + check_player.checked = _char.startsWith('bf'); check_player.callback = function() { char.isPlayer = !char.isPlayer; @@ -379,56 +567,63 @@ class CharacterEditorState extends MusicBeatState charDropDown = new FlxUIDropDownMenuCustom(10, 30, FlxUIDropDownMenuCustom.makeStrIdLabelArray([''], true), function(character:String) { - daAnim = characterList[Std.parseInt(character)]; - check_player.checked = daAnim.startsWith('bf'); - loadChar(!check_player.checked); + _char = characterList[Std.parseInt(character)]; + check_player.checked = _char.startsWith('bf'); + addCharacter(true); updatePresence(); reloadCharacterDropDown(); }); - charDropDown.selectedLabel = daAnim; + charDropDown.selectedLabel = _char; reloadCharacterDropDown(); var reloadCharacter:FlxButton = new FlxButton(140, 20, "Reload Char", function() { - loadChar(!check_player.checked); + addCharacter(true); reloadCharacterDropDown(); }); var templateCharacter:FlxButton = new FlxButton(140, 50, "Load Template", function() { - var parsedJson:CharacterFile = cast Json.parse(TemplateCharacter); - var characters:Array = [char, ghostChar]; - for (character in characters) + final _template:CharacterFile = { - character.animOffsets.clear(); - character.animationsArray = parsedJson.animations; - for (anim in character.animationsArray) - { - character.addOffset(anim.anim, anim.offsets[0], anim.offsets[1]); - } - if(character.animationsArray[0] != null) { - character.playAnim(character.animationsArray[0].anim, true); - } - - character.singDuration = parsedJson.sing_duration; - character.positionArray = parsedJson.position; - character.cameraPosition = parsedJson.camera_position; - - character.imageFile = parsedJson.image; - character.jsonScale = parsedJson.scale; - character.noAntialiasing = parsedJson.no_antialiasing; - character.originalFlipX = parsedJson.flip_x; - character.healthIcon = parsedJson.healthicon; - character.healthColorArray = parsedJson.healthbar_colors; - character.setPosition(character.positionArray[0] + OFFSET_X + 100, character.positionArray[1]); - } + animations: [ + newAnim('idle', 'BF idle dance'), + newAnim('singLEFT', 'BF NOTE LEFT0'), + newAnim('singDOWN', 'BF NOTE DOWN0'), + newAnim('singUP', 'BF NOTE UP0'), + newAnim('singRIGHT', 'BF NOTE RIGHT0') + ], + no_antialiasing: false, + flip_x: false, + healthicon: 'face', + image: 'characters/BOYFRIEND', + sing_duration: 4, + scale: 1, + healthbar_colors: [161, 161, 161], + winning_colors: [161, 161, 161], + losing_colors: [161, 161, 161], + camera_position: [0, 0], + position: [0, 0], + vocals_file: null, + noteskin: null, + shake_screen: false, + shake_intensity: 0, + shake_duration: 0, + health_drain: false, + drain_floor: 0.05, + drain_amount: 0.01 + }; - reloadCharacterImage(); - reloadCharacterDropDown(); + char.loadCharacterFile(_template); + char.debugMode = true; + char.color = FlxColor.WHITE; + char.alpha = 1; + reloadAnimList(); reloadCharacterOptions(); - resetHealthBarColor(); + updateCharacterPositions(); updatePointerPos(); - genBoyOffsets(); + reloadCharacterDropDown(); + resetHealthBarColor(); }); templateCharacter.color = FlxColor.RED; templateCharacter.label.color = FlxColor.WHITE; @@ -481,7 +676,7 @@ class CharacterEditorState extends MusicBeatState imageInputText.focusGained = () -> FlxG.stage.window.textInputEnabled = true; var reloadImage:FlxButton = new FlxButton(imageInputText.x + 210, imageInputText.y - 3, "Reload Image", function() { - if (sys.FileSystem.exists(Paths.modsImages(imageInputText.text)) || sys.FileSystem.exists('assets/images/' + imageInputText.text)) + if (sys.FileSystem.exists(Paths.modsImages(imageInputText.text)) || sys.FileSystem.exists('assets/shared/images/' + imageInputText.text)) { char.imageFile = imageInputText.text; reloadCharacterImage(); @@ -655,7 +850,6 @@ class CharacterEditorState extends MusicBeatState healthDrainCheckBox.checked = char.healthDrain; healthDrainCheckBox.callback = function() { char.healthDrain = healthDrainCheckBox.checked; - ghostChar.healthDrain = healthDrainCheckBox.checked; }; minimumHealthStepper = new FlxUINumericStepper(healthDrainCheckBox.x + 80, healthDrainCheckBox.y, 0.01, char.drainFloor, -1, 2, 3); @@ -668,7 +862,6 @@ class CharacterEditorState extends MusicBeatState shakeScreenBox.checked = char.shakeScreen; shakeScreenBox.callback = function() { char.shakeScreen = shakeScreenBox.checked; - ghostChar.shakeScreen = shakeScreenBox.checked; }; shakeIntensityStepper = new FlxUINumericStepper(shakeScreenBox.x + 80, shakeScreenBox.y, 0.0005, char.shakeIntensity, 0, 1, 4); @@ -694,12 +887,11 @@ class CharacterEditorState extends MusicBeatState UI_characterbox.addGroup(tab_group); } - var ghostDropDown:FlxUIDropDownMenuCustom; var animationDropDown:FlxUIDropDownMenuCustom; var animationInputText:FlxUIInputText; var animationNameInputText:FlxUIInputText; var animationIndicesInputText:FlxUIInputText; - var animationNameFramerate:FlxUINumericStepper; + var animationFramerate:FlxUINumericStepper; var animationLoopCheckBox:FlxUICheckBox; function addAnimationsUI() { var tab_group = new FlxUI(null, UI_box); @@ -711,7 +903,7 @@ class CharacterEditorState extends MusicBeatState animationNameInputText.focusGained = () -> FlxG.stage.window.textInputEnabled = true; animationIndicesInputText = new FlxUIInputText(animationNameInputText.x, animationNameInputText.y + 40, 250, '', 8); animationIndicesInputText.focusGained = () -> FlxG.stage.window.textInputEnabled = true; - animationNameFramerate = new FlxUINumericStepper(animationInputText.x + 170, animationInputText.y, 1, 24, 0, 240, 0); + animationFramerate = new FlxUINumericStepper(animationInputText.x + 170, animationInputText.y, 1, 24, 0, 240, 0); animationLoopCheckBox = new FlxUICheckBox(animationNameInputText.x + 170, animationNameInputText.y - 1, null, null, "Should it Loop?", 100); animationDropDown = new FlxUIDropDownMenuCustom(15, animationInputText.y - 55, FlxUIDropDownMenuCustom.makeStrIdLabelArray([''], true), function(pressed:String) { @@ -720,23 +912,12 @@ class CharacterEditorState extends MusicBeatState animationInputText.text = anim.anim; animationNameInputText.text = anim.name; animationLoopCheckBox.checked = anim.loop; - animationNameFramerate.value = anim.fps; + animationFramerate.value = anim.fps; var indicesStr:String = anim.indices.toString(); animationIndicesInputText.text = indicesStr.substr(1, indicesStr.length - 2); }); - ghostDropDown = new FlxUIDropDownMenuCustom(animationDropDown.x + 150, animationDropDown.y, FlxUIDropDownMenuCustom.makeStrIdLabelArray([''], true), function(pressed:String) { - var selectedAnimation:Int = Std.parseInt(pressed); - ghostChar.visible = false; - char.alpha = 1; - if(selectedAnimation > 0 && ghostChar.animationsArray[selectedAnimation-1] != null) { - ghostChar.visible = true; - ghostChar.playAnim(ghostChar.animationsArray[selectedAnimation-1].anim, true); - char.alpha = 0.85; - } - }); - var addUpdateButton:FlxButton = new FlxButton(70, animationIndicesInputText.y + 30, "Add/Update", function() { var indices:Array = []; var indicesStr:Array = animationIndicesInputText.text.trim().split(','); @@ -758,95 +939,68 @@ class CharacterEditorState extends MusicBeatState for (anim in char.animationsArray) { if(animationInputText.text == anim.anim) { lastOffsets = anim.offsets; - if(char.animation.getByName(animationInputText.text) != null) { - char.animation.remove(animationInputText.text); + if(char.animOffsets.exists(animationInputText.text)) + { + if(!char.isAnimateAtlas) char.animation.remove(animationInputText.text); + else @:privateAccess char.atlas.anim.animsMap.remove(animationInputText.text); } char.animationsArray.remove(anim); } } - var newAnim:AnimArray = { - anim: animationInputText.text, - name: animationNameInputText.text, - fps: Math.round(animationNameFramerate.value), - loop: animationLoopCheckBox.checked, - indices: indices, - offsets: lastOffsets - }; - if(indices != null && indices.length > 0) { - char.animation.addByIndices(newAnim.anim, newAnim.name, newAnim.indices, "", newAnim.fps, newAnim.loop); - } else { - char.animation.addByPrefix(newAnim.anim, newAnim.name, newAnim.fps, newAnim.loop); - } - - if(!char.animOffsets.exists(newAnim.anim)) { - char.addOffset(newAnim.anim, 0, 0); - } - char.animationsArray.push(newAnim); - - if(lastAnim == animationInputText.text) { - var leAnim:FlxAnimation = char.animation.getByName(lastAnim); - if(leAnim != null && leAnim.frames.length > 0) { - char.playAnim(lastAnim, true); - } else { - for(i in 0...char.animationsArray.length) { - if(char.animationsArray[i] != null) { - leAnim = char.animation.getByName(char.animationsArray[i].anim); - if(leAnim != null && leAnim.frames.length > 0) { - char.playAnim(char.animationsArray[i].anim, true); - curAnim = i; - break; - } - } - } - } - } - - reloadAnimationDropDown(); - genBoyOffsets(); + var addedAnim:AnimArray = newAnim(animationInputText.text, animationNameInputText.text); + addedAnim.fps = Math.round(animationFramerate.value); + addedAnim.loop = animationLoopCheckBox.checked; + addedAnim.indices = indices; + addedAnim.offsets = lastOffsets; + addAnimation(addedAnim.anim, addedAnim.name, addedAnim.fps, addedAnim.loop, addedAnim.indices); + char.animationsArray.push(addedAnim); + + reloadAnimList(); + @:arrayAccess curAnim = Std.int(Math.max(0, char.animationsArray.indexOf(addedAnim))); + char.playAnim(addedAnim.anim, true); trace('Added/Updated animation: ' + animationInputText.text); }); var removeButton:FlxButton = new FlxButton(180, animationIndicesInputText.y + 30, "Remove", function() { for (anim in char.animationsArray) { - if(animationInputText.text == anim.anim) { + if(animationInputText.text == anim.anim) + { var resetAnim:Bool = false; - if(char.animation.curAnim != null && anim.anim == char.animation.curAnim.name) resetAnim = true; - - if(char.animation.getByName(anim.anim) != null) { - char.animation.remove(anim.anim); - } - if(char.animOffsets.exists(anim.anim)) { + if(anim.anim == char.getAnimationName()) resetAnim = true; + if(char.hasAnimation(anim.anim)) + { + if(!char.isAnimateAtlas) char.animation.remove(anim.anim); + else @:privateAccess char.atlas.anim.animsMap.remove(anim.anim); char.animOffsets.remove(anim.anim); + char.animationsArray.remove(anim); } - char.animationsArray.remove(anim); if(resetAnim && char.animationsArray.length > 0) { - char.playAnim(char.animationsArray[0].anim, true); + curAnim = FlxMath.wrap(curAnim, 0, animList.length-1); + char.playAnim(animList[curAnim].anim, true); } - reloadAnimationDropDown(); - genBoyOffsets(); + reloadAnimList(); trace('Removed animation: ' + animationInputText.text); break; } } }); + reloadAnimList(); tab_group.add(new FlxText(animationDropDown.x, animationDropDown.y - 18, 0, 'Animations:')); - tab_group.add(new FlxText(ghostDropDown.x, ghostDropDown.y - 18, 0, 'Animation Ghost:')); tab_group.add(new FlxText(animationInputText.x, animationInputText.y - 18, 0, 'Animation name:')); - tab_group.add(new FlxText(animationNameFramerate.x, animationNameFramerate.y - 18, 0, 'Framerate:')); + tab_group.add(new FlxText(animationFramerate.x, animationFramerate.y - 18, 0, 'Framerate:')); tab_group.add(new FlxText(animationNameInputText.x, animationNameInputText.y - 18, 0, 'Animation on .XML/.TXT file:')); tab_group.add(new FlxText(animationIndicesInputText.x, animationIndicesInputText.y - 18, 0, 'ADVANCED - Animation Indices:')); tab_group.add(animationInputText); tab_group.add(animationNameInputText); tab_group.add(animationIndicesInputText); - tab_group.add(animationNameFramerate); + tab_group.add(animationFramerate); tab_group.add(animationLoopCheckBox); tab_group.add(addUpdateButton); tab_group.add(removeButton); - tab_group.add(ghostDropDown); tab_group.add(animationDropDown); UI_characterbox.addGroup(tab_group); } @@ -875,14 +1029,7 @@ class CharacterEditorState extends MusicBeatState char.jsonScale = sender.value; char.setGraphicSize(Std.int(char.width * char.jsonScale)); char.updateHitbox(); - ghostChar.setGraphicSize(Std.int(ghostChar.width * char.jsonScale)); - ghostChar.updateHitbox(); - reloadGhost(); updatePointerPos(); - - if(char.animation.curAnim != null) { - char.playAnim(char.animation.curAnim.name, true); - } } else if(sender == positionXStepper) { @@ -974,119 +1121,64 @@ class CharacterEditorState extends MusicBeatState } } - function reloadCharacterImage() { - var lastAnim:String = ''; - if(char.animation.curAnim != null) { - lastAnim = char.animation.curAnim.name; - } + function reloadCharacterImage() + { + var lastAnim:String = char.getAnimationName(); var anims:Array = char.animationsArray.copy(); - if(Paths.fileExists('images/' + char.imageFile + '/Animation.json', TEXT)) { - char.frames = AtlasFrameMaker.construct(char.imageFile); - } else if(Paths.fileExists('images/' + char.imageFile + '.txt', TEXT)) { - char.frames = Paths.getPackerAtlas(char.imageFile); - } else { - char.frames = Paths.getSparrowAtlas(char.imageFile); - } - - if(char.animationsArray != null && char.animationsArray.length > 0) { - for (anim in char.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) { - char.animation.addByIndices(animAnim, animName, animIndices, "", animFps, animLoop); - } else { - char.animation.addByPrefix(animAnim, animName, animFps, animLoop); - } - } - } else { - char.quickAnimAdd('idle', 'BF idle dance'); - } - - if(lastAnim != '') { - char.playAnim(lastAnim, true); - } else { - char.dance(); - } - ghostDropDown.selectedLabel = ''; - reloadGhost(); - } - function genBoyOffsets():Void - { - var daLoop:Int = 0; + char.atlas = FlxDestroyUtil.destroy(char.atlas); + char.isAnimateAtlas = false; + char.color = FlxColor.WHITE; + char.alpha = 1; - var i:Int = dumbTexts.members.length-1; - while(i >= 0) { - var memb:FlxText = dumbTexts.members[i]; - if(memb != null) { - memb.kill(); - dumbTexts.remove(memb); - memb.destroy(); + if(Paths.fileExists('images/' + char.imageFile + '/Animation.json', TEXT)) + { + char.atlas = new FlxAnimate(); + char.atlas.showPivot = false; + try + { + Paths.loadAnimateAtlas(char.atlas, char.imageFile); } - --i; + catch(e:Dynamic) + { + FlxG.log.warn('Could not load atlas ${char.imageFile}: $e'); + } + char.isAnimateAtlas = true; } - dumbTexts.clear(); - - for (anim => offsets in char.animOffsets) + else { - var text:FlxText = new FlxText(10, 20 + (18 * daLoop), 0, anim + ": " + offsets, 15); - text.setFormat(null, 16, FlxColor.WHITE, CENTER, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK); - text.scrollFactor.set(); - text.borderSize = 1; - dumbTexts.add(text); - text.cameras = [camHUD]; - - daLoop++; - } - - textAnim.visible = true; - if(dumbTexts.length < 1) { - var text:FlxText = new FlxText(10, 38, 0, "ERROR! No animations found.", 15); - text.scrollFactor.set(); - text.borderSize = 1; - dumbTexts.add(text); - textAnim.visible = false; - } - } - - function loadChar(isDad:Bool, blahBlahBlah:Bool = true) { - var i:Int = charLayer.members.length-1; - while(i >= 0) { - var memb:Character = charLayer.members[i]; - if(memb != null) { - memb.kill(); - charLayer.remove(memb); - memb.destroy(); + var split:Array = char.imageFile.split(','); + var charFrames:FlxAtlasFrames = Paths.getAtlas(split[0].trim()); + + if(split.length > 1) + { + var original:FlxAtlasFrames = charFrames; + charFrames = new FlxAtlasFrames(charFrames.parent); + charFrames.addAtlas(original, true); + for (i in 1...split.length) + { + var extraFrames:FlxAtlasFrames = Paths.getAtlas(split[i].trim()); + if(extraFrames != null) + charFrames.addAtlas(extraFrames, true); + } } - --i; + char.frames = charFrames; } - charLayer.clear(); - ghostChar = new Character(0, 0, daAnim, !isDad); - ghostChar.debugMode = true; - ghostChar.alpha = 0.6; - - char = new Character(0, 0, daAnim, !isDad); - if(char.animationsArray[0] != null) { - char.playAnim(char.animationsArray[0].anim, true); - } - char.debugMode = true; - - //currentCharacter = (Reflect.fields(char).indexOf('DADDY_DEAREST') != -1 || Reflect.fields(cast(Json.parse(TemplateCharacter), Array)).substr(0) == TemplateCharacter.substr(0)); - - charLayer.add(ghostChar); - charLayer.add(char); - char.setPosition(char.positionArray[0] + OFFSET_X + 100, char.positionArray[1]); + for (anim in anims) { + 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; + addAnimation(animAnim, animName, animFps, animLoop, animIndices); + } - if(blahBlahBlah) { - genBoyOffsets(); + if(anims.length > 0) + { + if(lastAnim != '') char.playAnim(lastAnim, true); + else char.dance(); } - reloadCharacterOptions(); - reloadBGs(); - updatePointerPos(); } function updatePointerPos() { @@ -1113,10 +1205,55 @@ class CharacterEditorState extends MusicBeatState return null; } + inline function updateCharacterPositions() + { + char.setPosition(char.positionArray[0] + OFFSET_X + 100, char.positionArray[1]); + updatePointerPos(); + } + + inline function predictCharacterIsNotPlayer(name:String) + { + return (name != 'bf' && !name.startsWith('bf-') && !name.endsWith('-player') && !name.endsWith('-playable') && !name.endsWith('-dead')) || + name.endsWith('-opponent') || name.startsWith('gf-') || name.endsWith('-gf') || name == 'gf'; + } + + function addAnimation(anim:String, name:String, fps:Float, loop:Bool, indices:Array) + { + if(!char.isAnimateAtlas) + { + if(indices != null && indices.length > 0) + char.animation.addByIndices(anim, name, indices, "", fps, loop); + else + char.animation.addByPrefix(anim, name, fps, loop); + } + else + { + if(indices != null && indices.length > 0) + char.atlas.anim.addBySymbolIndices(anim, name, indices, fps, loop); + else + char.atlas.anim.addBySymbol(anim, name, fps, loop); + } + + if(!char.animOffsets.exists(anim)) + char.addOffset(anim, 0, 0); + } + + inline function newAnim(anim:String, name:String):AnimArray + { + return { + offsets: [0, 0], + loop: false, + fps: 24, + anim: anim, + indices: [], + name: name + }; + } + function reloadCharacterOptions() { if(UI_characterbox != null) { imageInputText.text = char.imageFile; - if (char.noteskin != null) noteskinText.text = char.noteskin; + noteskinText.text = char.noteskin; healthIconInputText.text = char.healthIcon; vocalsInputText.text = char.vocalsFile != null ? char.vocalsFile : ''; singDurationStepper.value = char.singDuration; @@ -1134,49 +1271,42 @@ class CharacterEditorState extends MusicBeatState } } - function reloadAnimationDropDown() { - var anims:Array = []; - var ghostAnims:Array = ['']; - for (anim in char.animationsArray) { - anims.push(anim.anim); - ghostAnims.push(anim.anim); - } - if(anims.length < 1) anims.push('NO ANIMATIONS'); //Prevents crash + inline function updateText() + { + animsTxt.removeFormat(selectedFormat); - animList = anims.copy(); + var intendText:String = ''; + for (num => anim in animList) + { + if(num > 0) intendText += '\n'; - animationDropDown.setData(FlxUIDropDownMenuCustom.makeStrIdLabelArray(anims, true)); - ghostDropDown.setData(FlxUIDropDownMenuCustom.makeStrIdLabelArray(ghostAnims, true)); - reloadGhost(); + if(num == curAnim) + { + var n:Int = intendText.length; + intendText += anim.anim + ": " + anim.offsets; + animsTxt.addFormat(selectedFormat, n, intendText.length); + } + else intendText += anim.anim + ": " + anim.offsets; + } + animsTxt.text = intendText; } - function reloadGhost() { - ghostChar.frames = char.frames; - for (anim in char.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) { - ghostChar.animation.addByIndices(animAnim, animName, animIndices, "", animFps, animLoop); - } else { - ghostChar.animation.addByPrefix(animAnim, animName, animFps, animLoop); - } + inline function reloadAnimList() + { + animList = char.animationsArray; + if(animList.length > 0) char.playAnim(animList[0].anim, true); + curAnim = 0; - if(anim.offsets != null && anim.offsets.length > 1) { - ghostChar.addOffset(anim.anim, anim.offsets[0], anim.offsets[1]); - } - } + updateText(); + if(animationDropDown != null) reloadAnimationDropDown(); + } - char.alpha = 0.85; - ghostChar.visible = true; - if(ghostDropDown.selectedLabel == '') { - ghostChar.visible = false; - char.alpha = 1; - } - ghostChar.color = 0xFF666688; - ghostChar.antialiasing = char.antialiasing; + function reloadAnimationDropDown() { + var animationList:Array = []; + for (anim in animList) animationList.push(anim.anim); + if(animationList.length < 1) animationList.push('NO ANIMATIONS'); //Prevents crash + + animationDropDown.setData(FlxUIDropDownMenuCustom.makeStrIdLabelArray(animationList, true)); } function reloadCharacterDropDown() { @@ -1207,7 +1337,7 @@ class CharacterEditorState extends MusicBeatState #end charDropDown.setData(FlxUIDropDownMenuCustom.makeStrIdLabelArray(characterList, true)); - charDropDown.selectedLabel = daAnim; + charDropDown.selectedLabel = _char; } function resetHealthBarColor() { @@ -1247,24 +1377,16 @@ class CharacterEditorState extends MusicBeatState function updatePresence() { #if desktop // Updating Discord Rich Presence - DiscordClient.changePresence("Character Editor", "Character: " + daAnim, leHealthIcon.getCharacter()); + DiscordClient.changePresence("Character Editor", "Character: " + _char, leHealthIcon.getCharacter()); #end } + var holdingFrameTime:Float = 0; + var holdingFrameElapsed:Float = 0; override function update(elapsed:Float) { if (FlxG.mouse.justPressed) FlxG.sound.play(Paths.sound('click')); MusicBeatState.camBeat = FlxG.camera; - if(char.animationsArray[curAnim] != null) { - textAnim.text = char.animationsArray[curAnim].anim; - - var curAnim:FlxAnimation = char.animation.getByName(char.animationsArray[curAnim].anim); - if(curAnim == null || curAnim.frames.length < 1) { - textAnim.text += ' (ERROR!)'; - } - } else { - textAnim.text = ''; - } while (changeBar = false) { @@ -1295,12 +1417,8 @@ class CharacterEditorState extends MusicBeatState char.offset.x -= FlxG.mouse.deltaScreenX; char.offset.y -= FlxG.mouse.deltaScreenY; - var anim = animList[curAnim]; - char.addOffset(char.animationsArray[curAnim].anim, char.animationsArray[curAnim].offsets[0], char.animationsArray[curAnim].offsets[1]); - ghostChar.addOffset(char.animationsArray[curAnim].anim, char.animationsArray[curAnim].offsets[0], char.animationsArray[curAnim].offsets[1]); - var myText:FlxText = dumbTexts.members[curAnim]; - myText.text = anim + ": " + char.animOffsets.get(animList[curAnim]); + updateText(); } if(!charDropDown.dropPanel.visible) { @@ -1320,20 +1438,27 @@ class CharacterEditorState extends MusicBeatState FlxG.camera.zoom = 1; } + var shiftMult:Float = 1; + var ctrlMult:Float = 1; + var shiftMultBig:Float = 1; + if(FlxG.keys.pressed.SHIFT) + { + shiftMult = 4; + shiftMultBig = 10; + } + if (FlxG.keys.pressed.E && FlxG.camera.zoom < 3) { - FlxG.camera.zoom += elapsed * FlxG.camera.zoom; + FlxG.camera.zoom += elapsed * FlxG.camera.zoom * shiftMult; if(FlxG.camera.zoom > 3) FlxG.camera.zoom = 3; } if (FlxG.keys.pressed.Q && FlxG.camera.zoom > 0.1) { - FlxG.camera.zoom -= elapsed * FlxG.camera.zoom; + FlxG.camera.zoom -= elapsed * FlxG.camera.zoom * shiftMult; if(FlxG.camera.zoom < 0.1) FlxG.camera.zoom = 0.1; } if (FlxG.keys.pressed.I || FlxG.keys.pressed.J || FlxG.keys.pressed.K || FlxG.keys.pressed.L) { - var addToCam:Float = 500 * elapsed; - if (FlxG.keys.pressed.SHIFT) - addToCam *= 4; + var addToCam:Float = 500 * elapsed * shiftMult; if (FlxG.keys.pressed.I) camFollow.y -= addToCam; @@ -1346,16 +1471,19 @@ class CharacterEditorState extends MusicBeatState camFollow.x += addToCam; } + var txt = 'ERROR: No Animation Found'; + var clr = FlxColor.RED; + if(char.animationsArray.length > 0) { - if (FlxG.keys.justPressed.W) + if(FlxG.keys.pressed.A || FlxG.keys.pressed.D) { - curAnim -= 1; + holdingFrameTime += elapsed; + if(holdingFrameTime > 0.5) holdingFrameElapsed += elapsed; } + else holdingFrameTime = 0; - if (FlxG.keys.justPressed.S) - { - curAnim += 1; - } + if(FlxG.keys.justPressed.W) curAnim--; + else if(FlxG.keys.justPressed.S) curAnim++; if (curAnim < 0) curAnim = char.animationsArray.length - 1; @@ -1365,16 +1493,15 @@ class CharacterEditorState extends MusicBeatState if (FlxG.keys.justPressed.S || FlxG.keys.justPressed.W || FlxG.keys.justPressed.SPACE) { - char.playAnim(char.animationsArray[curAnim].anim, true); - genBoyOffsets(); + char.playAnim(animList[curAnim].anim, true); + updateText(); } if (FlxG.keys.justPressed.T) { char.animationsArray[curAnim].offsets = [0, 0]; char.addOffset(char.animationsArray[curAnim].anim, char.animationsArray[curAnim].offsets[0], char.animationsArray[curAnim].offsets[1]); - ghostChar.addOffset(char.animationsArray[curAnim].anim, char.animationsArray[curAnim].offsets[0], char.animationsArray[curAnim].offsets[1]); - genBoyOffsets(); + updateText(); } var controlArray:Array = [FlxG.keys.justPressed.LEFT, FlxG.keys.justPressed.RIGHT, FlxG.keys.justPressed.UP, FlxG.keys.justPressed.DOWN]; @@ -1394,16 +1521,55 @@ class CharacterEditorState extends MusicBeatState char.animationsArray[curAnim].offsets[arrayVal] += negaMult * multiplier; char.addOffset(char.animationsArray[curAnim].anim, char.animationsArray[curAnim].offsets[0], char.animationsArray[curAnim].offsets[1]); - ghostChar.addOffset(char.animationsArray[curAnim].anim, char.animationsArray[curAnim].offsets[0], char.animationsArray[curAnim].offsets[1]); char.playAnim(char.animationsArray[curAnim].anim, false); - if(ghostChar.animation.curAnim != null && char.animation.curAnim != null && char.animation.curAnim.name == ghostChar.animation.curAnim.name) { - ghostChar.playAnim(char.animation.curAnim.name, false); + updateText(); + } + } + var frames:Int = -1; + var length:Int = -1; + if(!char.isAnimateAtlas && char.animation.curAnim != null) + { + frames = char.animation.curAnim.curFrame; + length = char.animation.curAnim.numFrames; + } + else if(char.isAnimateAtlas && char.atlas.anim != null) + { + frames = char.atlas.anim.curFrame; + length = char.atlas.anim.length; + } + + if(length >= 0) + { + if(FlxG.keys.justPressed.A || FlxG.keys.justPressed.D || holdingFrameTime > 0.5) + { + var isLeft = false; + if((holdingFrameTime > 0.5 && FlxG.keys.pressed.A) || FlxG.keys.justPressed.A) isLeft = true; + char.animPaused = true; + + if(holdingFrameTime <= 0.5 || holdingFrameElapsed > 0.1) + { + frames = FlxMath.wrap(frames + Std.int(isLeft ? -shiftMult : shiftMult), 0, length-1); + if(!char.isAnimateAtlas) char.animation.curAnim.curFrame = frames; + else char.atlas.anim.curFrame = frames; + holdingFrameElapsed -= 0.1; } - genBoyOffsets(); } + + txt = 'Frames: ( $frames / ${length-1} )'; + //if(character.animation.curAnim.paused) txt += ' - PAUSED'; + clr = FlxColor.WHITE; } } + if(txt != frameAdvanceText.text) frameAdvanceText.text = txt; + frameAdvanceText.color = clr; + + // OTHER CONTROLS + if(FlxG.keys.justPressed.F1 || (helpBg.visible && FlxG.keys.justPressed.ESCAPE)) + { + helpBg.visible = !helpBg.visible; + helpTexts.visible = helpBg.visible; + } } //camMenu.zoom = FlxG.camera.zoom; ghostChar.setPosition(char.x, char.y); @@ -1425,7 +1591,7 @@ class CharacterEditorState extends MusicBeatState _file.addEventListener(Event.COMPLETE, onSaveComplete); _file.addEventListener(Event.CANCEL, onSaveCancel); _file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError); - _file.save(data, daAnim + "Offsets.txt"); + _file.save(data, _char + "Offsets.txt"); } }*/ @@ -1498,7 +1664,7 @@ class CharacterEditorState extends MusicBeatState _file.addEventListener(Event.COMPLETE, onSaveComplete); _file.addEventListener(Event.CANCEL, onSaveCancel); _file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError); - _file.save(data, daAnim + ".json"); + _file.save(data, _char + ".json"); } }