Skip to content

Commit

Permalink
health icon saving system
Browse files Browse the repository at this point in the history
  • Loading branch information
KoloInDaCrib committed Nov 3, 2024
1 parent 1096b87 commit 3ea5fca
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 13 deletions.
10 changes: 5 additions & 5 deletions source/funkin/ui/debug/char/CharCreatorCharacter.hx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class CharCreatorCharacter extends Bopper
public var characterFlipX:Bool = false;
public var characterScale:Float = 1.0; // character scale to be used in the data, ghosts need one

public var healthIcon:HealthIconData = null;
public var healthIconFiles:Array<WizardFile> = [];

public var characterOrigin(get, never):FlxPoint;
public var feetPosition(get, never):FlxPoint;
public var totalScale(default, set):Float; // total character scale, included with the stage scale
Expand Down Expand Up @@ -290,18 +293,15 @@ class CharCreatorCharacter extends Bopper
name: characterName,
assetPaths: generatedParams.files.filter((file) -> return file.name.endsWith(".png") || file.name.endsWith(".zip")).map((file) -> {
var path = Path.withoutExtension(Path.normalize(file.name));
if (!CharCreatorUtil.isCharacterPath(path))
if (!CharCreatorUtil.isPathProvided(path, "images/characters"))
{
return 'characters/${Path.withoutDirectory(path)}';
}
return path.substr(path.lastIndexOf("images") + 7);
}),
flipX: characterFlipX,
renderType: generatedParams.renderType,
healthIcon:
{
id: characterId
},
healthIcon: healthIcon,
animations: animations,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,58 @@ class HealthIconDialog extends DefaultPageDialog
{
var healthIcon:FlxSprite;

override public function new(daPage:CharCreatorDefaultPage)
override public function new(daPage:CharCreatorDefaultPage, char:CharCreatorCharacter)
{
super(daPage);

if (char.healthIcon != null && char.healthIconFiles.length >= 1) // set the data considering we have all the stuff we need
{
healthIcon = new FlxSprite();
var bitmap = openfl.display.BitmapData.fromBytes(char.healthIconFiles[0].bytes);

if (char.healthIconFiles.length == 1) // legacy
{
var iconSize = HealthIcon.HEALTH_ICON_SIZE;
@:privateAccess if (char.healthIcon.isPixel) iconSize = HealthIcon.PIXEL_ICON_SIZE;

healthIcon.loadGraphic(bitmap, true, iconSize, iconSize);
healthIcon.animation.add("idle", [0], 0, false, false);
healthIcon.animation.add("losing", [1], 0, false, false);
if (healthIcon.animation.numFrames >= 3)
{
healthIcon.animation.add("winning", [2], 0, false, false);
}
}
else
{
healthIcon.frames = FlxAtlasFrames.fromSparrow(bitmap, char.healthIconFiles[1].bytes.toString());
if (healthIcon.frames.frames.length == 0) return;

healthIcon.animation.addByPrefix("idle", "idle", 24, true);
healthIcon.animation.addByPrefix("winning", "winning", 24, true);
healthIcon.animation.addByPrefix("losing", "losing", 24, true);
healthIcon.animation.addByPrefix("toWinning", "toWinning", 24, false);
healthIcon.animation.addByPrefix("toLosing", "toLosing", 24, false);
healthIcon.animation.addByPrefix("fromWinning", "fromWinning", 24, false);
healthIcon.animation.addByPrefix("fromLosing", "fromLosing", 24, false);

if (healthIcon.animation.getNameList().length == 0) return;
}

// some cosmetic stuff
healthIconPreviewImg.flipX = healthIconFlipX.selected = (char.healthIcon.flipX ?? false);
healthIconPreviewImg.antialiasing = healthIconPixelated.selected = (char.healthIcon.isPixel ?? false);
healthIconPreviewImg.imageScale = healthIconScale.pos = (char.healthIcon.scale ?? 1);
healthIconPreviewImg.left = healthIconOffsetX.pos = (char.healthIcon.offsets[0] ?? 0);
healthIconPreviewImg.top = healthIconOffsetY.pos = (char.healthIcon.offsets[1] ?? 0);

healthIcon.animation.onFrameChange.add(function(animName:String, frameNumber:Int, frameIndex:Int) {
healthIconPreviewImg.resource = healthIcon.frames.frames[frameIndex];
});

healthIcon.animation.play("idle");
}

healthIconLoadBtn.onClick = function(_) {
FileUtil.browseForBinaryFile("Load File", [FileUtil.FILE_EXTENSION_INFO_PNG], function(_) {
if (_?.fullPath != null) healthIconLoadField.text = _.fullPath;
Expand Down Expand Up @@ -123,6 +171,18 @@ class HealthIconDialog extends DefaultPageDialog
});

healthIcon.animation.play("idle");

char.healthIconFiles = [
{name: healthIconLoadField.text, bytes: imgBytes}];
if (xmlBytes != null) char.healthIconFiles.push({name: healthIconLoadField.text.replace(".png", ".xml"), bytes: xmlBytes});
char.healthIcon =
{
scale: healthIconScale.pos,
id: char.characterId,
offsets: [healthIconOffsetX.pos, healthIconOffsetY.pos],
flipX: healthIconFlipX.selected,
isPixel: healthIconPixelated.selected
}
}

healthIconCurAnim.onChange = function(_) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import funkin.ui.debug.char.pages.CharCreatorGameplayPage;
import funkin.ui.debug.char.CharCreatorState;
import funkin.util.FileUtil;

using StringTools;

@:access(funkin.ui.debug.char.CharCreatorState)
class CharCreatorImportExportHandler
{
Expand All @@ -15,19 +17,37 @@ class CharCreatorImportExportHandler
var gameplayPage:CharCreatorGameplayPage = cast state.pages[Gameplay];

var zipEntries = [];
zipEntries.push(FileUtil.makeZIPEntry('${gameplayPage.currentCharacter.characterId}.json', gameplayPage.currentCharacter.toJSON()));

for (file in gameplayPage.currentCharacter.files)
{
// skip if the file is in a character path
if (CharCreatorUtil.isCharacterPath(file.name))
if (CharCreatorUtil.isPathProvided(file.name, "images/characters"))
{
continue;
}

zipEntries.push(FileUtil.makeZIPEntryFromBytes('images/characters/${Path.withoutDirectory(file.name)}', file.bytes));
}

// if the icon path isn't absolute, in the proper folder AND there already was an xml file (if we added one), then we don't save files and replace the typedef's id field
var iconPath = gameplayPage.currentCharacter.healthIconFiles[0].name;
if (CharCreatorUtil.isPathProvided(iconPath, "images/icons/icon-")
&& ((gameplayPage.currentCharacter.healthIconFiles.length > 1
&& CharCreatorUtil.isPathProvided(iconPath.replace(".png", ".xml"), "images/icons/icon-"))
|| gameplayPage.currentCharacter.healthIconFiles.length == 1))
{
var typicalPath = Path.withoutDirectory(iconPath).split(".")[0];
gameplayPage.currentCharacter.healthIcon.id = typicalPath.replace("icon-", "");
}
else
{
for (file in gameplayPage.currentCharacter.healthIconFiles)
zipEntries.push(FileUtil.makeZIPEntryFromBytes('images/icons/icon-${gameplayPage.currentCharacter.characterId}.${Path.extension(file.name)}',
file.bytes));
}

// we push this later in case we use a pre-existing icon
zipEntries.push(FileUtil.makeZIPEntry('${gameplayPage.currentCharacter.characterId}.json', gameplayPage.currentCharacter.toJSON()));
FileUtil.saveFilesAsZIP(zipEntries);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class CharCreatorGameplayPage extends CharCreatorDefaultPage

dialogMap.set(Animation, new AddAnimDialog(this, currentCharacter));
dialogMap.set(Ghost, new GhostSettingsDialog(this));
dialogMap.set(Health, new HealthIconDialog(this));
dialogMap.set(Health, new HealthIconDialog(this, currentCharacter));

// defaults for UI
labelAnimName.text = "None";
Expand Down
6 changes: 3 additions & 3 deletions source/funkin/ui/debug/char/util/CharCreatorUtil.hx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ class CharCreatorUtil
return text;
}

public static function isCharacterPath(path:String):Bool
public static function isPathProvided(path:String, checkFor:String = "images/characters"):Bool
{
var cwd = Path.addTrailingSlash(Path.normalize(sys.FileSystem.fullPath(".")));
var cwd = Path.addTrailingSlash(Path.normalize(#if sys sys.FileSystem.fullPath(".") #else "." #end));
path = Path.normalize(path);
path = path.replace(cwd, "");
return !Path.isAbsolute(path) && path.indexOf("images/characters") != -1;
return !Path.isAbsolute(path) && path.indexOf(checkFor) != -1;
}
}

0 comments on commit 3ea5fca

Please sign in to comment.