Pixel icons defined by song metadata

This commit is contained in:
Abnormal 2025-03-21 20:55:44 -05:00
parent d31ef12363
commit c0f0bf324e
6 changed files with 61 additions and 10 deletions

2
assets

@ -1 +1 @@
Subproject commit 0303a03f43b078d5263b541de1ff504fd7cfcde5
Subproject commit 8e4e97a7f084e7fa7629e3615696046771c95586

View file

@ -489,6 +489,13 @@ class SongPlayData implements ICloneable<SongPlayData>
@:default(15000)
public var previewEnd:Int;
/**
* The pixel icon for the song in Freeplay.
* Defaults to the opponent's icon.
*/
@:optional
public var freeplayIcon:Null<PixelIconData>;
public function new()
{
ratings = new Map<String, Int>();
@ -507,6 +514,7 @@ class SongPlayData implements ICloneable<SongPlayData>
result.album = this.album;
result.previewStart = this.previewStart;
result.previewEnd = this.previewEnd;
result.freeplayIcon = this.freeplayIcon;
return result;
}
@ -1258,3 +1266,28 @@ class NoteParamData implements ICloneable<NoteParamData>
return 'NoteParamData(${this.name}, ${this.value})';
}
}
typedef PixelIconData =
{
/**
* The ID to use for the icon.
*/
@:optional
var id:String;
/**
* The offsets of the icon.
* @default [0, 0]
*/
@:optional
@:default([0, 0])
var ?offsets:Array<Float>;
/**
* Whether to flip the icon horizontally.
* @default false
*/
@:optional
@:default(false)
var ?flipX:Bool;
}

View file

@ -3,6 +3,7 @@ package funkin.play.song;
import funkin.audio.VoicesGroup;
import funkin.audio.FunkinSound;
import funkin.data.IRegistryEntry;
import funkin.data.song.SongData.PixelIconData;
import funkin.data.song.SongData.SongCharacterData;
import funkin.data.song.SongData.SongChartData;
import funkin.data.song.SongData.SongEventData;
@ -331,6 +332,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
difficulty.difficultyRating = metadata.playData.ratings.get(diffId) ?? 0;
difficulty.album = metadata.playData.album;
difficulty.freeplayIcon = metadata.playData.freeplayIcon;
difficulty.stage = metadata.playData.stage;
difficulty.noteStyle = metadata.playData.noteStyle;
@ -750,6 +752,7 @@ class SongDifficulty
public var difficultyRating:Int = 0;
public var album:Null<String> = null;
public var freeplayIcon:Null<PixelIconData> = null;
public function new(song:Song, diffId:String, variation:String)
{

View file

@ -16,8 +16,10 @@ class PixelatedIcon extends FlxFilteredSprite
this.active = false;
}
public function setCharacter(char:String):Void
public function setCharacter(char:String, ?offsets:Null<Array<Float>>):Void
{
if (offsets == null) offsets = [0, 0];
var charPath:String = "freeplay/icons/";
switch (char)
@ -70,13 +72,10 @@ class PixelatedIcon extends FlxFilteredSprite
this.scale.x = this.scale.y = 2;
switch (char)
{
case 'parents-christmas':
this.origin.x = 140;
default:
this.origin.x = 100;
}
this.origin.x = 100;
this.origin.x += offsets[0];
this.origin.y += offsets[1];
if (isAnimated)
{

View file

@ -18,6 +18,7 @@ import flixel.util.FlxTimer;
import funkin.audio.FunkinSound;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.data.song.SongRegistry;
import funkin.data.song.SongData.PixelIconData;
import funkin.data.story.level.LevelRegistry;
import funkin.effects.IntervalShake;
import funkin.graphics.FunkinCamera;
@ -2266,6 +2267,11 @@ class FreeplaySongData
public var scoringRank(get, never):Null<ScoringRank>;
/**
* The pixel icon for the song.
*/
public var pixelIconData(get, never):Null<PixelIconData>;
public function new(data:Song, levelData:Level)
{
this.data = data;
@ -2341,6 +2347,12 @@ class FreeplaySongData
return Save.instance.getSongRank(data.id, FreeplayState.rememberedDifficulty, variation);
}
function get_pixelIconData():Null<PixelIconData>
{
var variations:Array<String> = data.getVariationsByCharacterId(FreeplayState.rememberedCharacterId);
return data.getDifficulty(FreeplayState.rememberedDifficulty, null, variations)?.freeplayIcon;
}
}
/**

View file

@ -404,7 +404,11 @@ class SongMenuItem extends FlxSpriteGroup
else
{
songText.text = freeplayData.fullSongName;
if (freeplayData.songCharacter != null) pixelIcon.setCharacter(freeplayData.songCharacter);
if (freeplayData.songCharacter != null)
{
pixelIcon.setCharacter(freeplayData.pixelIconData?.id ?? freeplayData.songCharacter, freeplayData.pixelIconData?.offsets);
pixelIcon.flipX = freeplayData.pixelIconData?.flipX ?? false;
}
pixelIcon.visible = true;
updateBPM(Std.int(freeplayData.songStartingBpm) ?? 0);
updateDifficultyRating(freeplayData.difficultyRating ?? 0);