Merge remote-tracking branch 'upstream/main'
@@ -97,9 +97,6 @@ function postCreate() {
|
||||
defaultCamZoom /= daPixelZoom;
|
||||
}
|
||||
|
||||
iconP1.antialiasing = false;
|
||||
iconP2.antialiasing = false;
|
||||
|
||||
if (enablePixelGameOver) {
|
||||
gameOverSong = "pixel/gameOver";
|
||||
lossSFX = "pixel/gameOverSFX";
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE codename-engine-icon>
|
||||
<icon antialiasing="false" />
|
||||
|
Before Width: | Height: | Size: 384 B After Width: | Height: | Size: 384 B |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE codename-engine-icon>
|
||||
<icon antialiasing="false" />
|
||||
|
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 358 B |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE codename-engine-icon>
|
||||
<icon antialiasing="false" />
|
||||
|
Before Width: | Height: | Size: 409 B After Width: | Height: | Size: 409 B |
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE codename-engine-icon>
|
||||
<icon antialiasing="false" />
|
||||
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 339 B |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -75,24 +75,34 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
moves = false;
|
||||
}
|
||||
|
||||
public static function copyFrom(source:FunkinSprite)
|
||||
/**
|
||||
* Gets the graphics and copies other properties from another sprite (Works both for `FlxSprite` and `FunkinSprite`!).
|
||||
*/
|
||||
public static function copyFrom(source:FlxSprite):FunkinSprite
|
||||
{
|
||||
var spr = new FunkinSprite();
|
||||
var casted:FunkinSprite = null;
|
||||
if (source is FunkinSprite)
|
||||
casted = cast source;
|
||||
|
||||
@:privateAccess {
|
||||
spr.setPosition(source.x, source.y);
|
||||
spr.frames = source.frames;
|
||||
if (source.animateAtlas != null && source.atlasPath != null)
|
||||
spr.loadSprite(source.atlasPath);
|
||||
if (casted != null && casted.animateAtlas != null && casted.atlasPath != null)
|
||||
spr.loadSprite(casted.atlasPath);
|
||||
spr.animation.copyFrom(source.animation);
|
||||
spr.visible = source.visible;
|
||||
spr.alpha = source.alpha;
|
||||
spr.antialiasing = source.antialiasing;
|
||||
spr.scale.set(source.scale.x, source.scale.y);
|
||||
spr.scrollFactor.set(source.scrollFactor.x, source.scrollFactor.y);
|
||||
spr.skew.set(source.skew.x, source.skew.y);
|
||||
spr.transformMatrix = source.transformMatrix;
|
||||
spr.matrixExposed = source.matrixExposed;
|
||||
spr.animOffsets = source.animOffsets.copy();
|
||||
|
||||
if (casted != null) {
|
||||
spr.skew.set(casted.skew.x, casted.skew.y);
|
||||
spr.transformMatrix = casted.transformMatrix;
|
||||
spr.matrixExposed = casted.matrixExposed;
|
||||
spr.animOffsets = casted.animOffsets.copy();
|
||||
}
|
||||
}
|
||||
return spr;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
if (l is IModsAssetLibrary) {
|
||||
var lib = cast(l, IModsAssetLibrary);
|
||||
for(e in lib.getFiles(folder))
|
||||
content.push(e);
|
||||
content.pushOnce(e);
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
@@ -194,6 +194,29 @@ class Paths
|
||||
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the images needed for using getFrames() exist.
|
||||
* @param key Path to the image
|
||||
* @param checkAtlas Whenever to check for the Animation.json file (used in FlxAnimate)
|
||||
* @param assetsPath Whenever to use the raw path or to pass it through Paths.image()
|
||||
* @param library (Additional) library to load the frames from.
|
||||
* @return True if the images exist, false otherwise.
|
||||
**/
|
||||
public static function framesExists(key:String, checkAtlas:Bool = false, checkMulti:Bool = true, assetsPath:Bool = false, ?library:String) {
|
||||
var path = assetsPath ? key : Paths.image(key, library, true);
|
||||
var noExt = Path.withoutExtension(path);
|
||||
if(checkAtlas && Assets.exists('$noExt/Animation.json'))
|
||||
return true;
|
||||
if(checkMulti && Assets.exists('$noExt/1.png'))
|
||||
return true;
|
||||
if(Assets.exists('$noExt.xml'))
|
||||
return true;
|
||||
if(Assets.exists('$noExt.txt'))
|
||||
return true;
|
||||
if(Assets.exists('$noExt.json'))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads frames from a specific image path. Supports Sparrow Atlases, Packer Atlases, and multiple spritesheets.
|
||||
|
||||
@@ -128,6 +128,10 @@ class HScript extends Script {
|
||||
interp.execute(expr);
|
||||
call("new", []);
|
||||
}
|
||||
|
||||
#if GLOBAL_SCRIPT
|
||||
funkin.backend.scripting.GlobalScript.call("onScriptSetup", [this, "hscript"]);
|
||||
#end
|
||||
}
|
||||
|
||||
public override function reload() {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package funkin.backend.scripting.events.healthicon;
|
||||
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
|
||||
final class HealthIconChangeEvent extends CancellableEvent {
|
||||
/**
|
||||
* Amount
|
||||
* Animation State
|
||||
*/
|
||||
public var amount:Int;
|
||||
public var anim:OneOfTwo<String, Int>;
|
||||
|
||||
/**
|
||||
* The health icon
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package funkin.backend.scripting.events.note;
|
||||
|
||||
import funkin.game.Character;
|
||||
import funkin.game.HealthIcon;
|
||||
import funkin.game.Note;
|
||||
|
||||
final class NoteHitEvent extends CancellableEvent {
|
||||
@@ -113,6 +114,10 @@ final class NoteHitEvent extends CancellableEvent {
|
||||
* Whenever the animation should be forced to play (if it's null it will be forced based on the sprite's data xml, if it has one).
|
||||
*/
|
||||
public var forceAnim:Null<Bool> = true;
|
||||
/**
|
||||
* The attached healthIcon used distinction for icons amongst others
|
||||
*/
|
||||
public var healthIcon:HealthIcon;
|
||||
|
||||
/**
|
||||
* Prevents the default sing animation from being played.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.backend.shaders;
|
||||
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
import flixel.util.FlxSignal.FlxTypedSignal;
|
||||
import haxe.Exception;
|
||||
@@ -555,34 +556,44 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
return val;
|
||||
}
|
||||
|
||||
var field:Dynamic = Reflect.field(data, name);
|
||||
var cl:String = Type.getClassName(Type.getClass(field));
|
||||
var field = Reflect.field(data, name);
|
||||
var cl = Type.getClassName(Type.getClass(field));
|
||||
var isNotNull = val != null;
|
||||
// cant do "field is ShaderInput" for some reason
|
||||
if (cl.startsWith("openfl.display.ShaderParameter")) {
|
||||
if (field.__length <= 1) {
|
||||
if ((val is Array))
|
||||
return field.value = val;
|
||||
// that means we wait for a single number, instead of an array
|
||||
if (field.__isInt && !(val is Int))
|
||||
if (field.__isInt && isNotNull && !(val is Int)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), 'Int');
|
||||
else if (field.__isBool && !(val is Bool))
|
||||
return null;
|
||||
} else
|
||||
if (field.__isBool && isNotNull && !(val is Bool)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), 'Bool');
|
||||
else if (field.__isFloat && !(val is Float))
|
||||
return null;
|
||||
} else
|
||||
if (field.__isFloat && isNotNull && !(val is Float)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), 'Float');
|
||||
|
||||
return field.value = [val];
|
||||
return null;
|
||||
}
|
||||
return field.value = isNotNull ? [val] : null;
|
||||
} else {
|
||||
if (!(val is Array))
|
||||
if (isNotNull && !(val is Array)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), Array);
|
||||
|
||||
return null;
|
||||
}
|
||||
return field.value = val;
|
||||
}
|
||||
} else if (cl.startsWith("openfl.display.ShaderInput")) {
|
||||
// shader input!!
|
||||
if (!(val is BitmapData)) {
|
||||
var bitmap:BitmapData;
|
||||
if (!isNotNull) bitmap = null;
|
||||
else if (val is BitmapData) bitmap = val;
|
||||
else if (val is FlxGraphic) bitmap = val.bitmap;
|
||||
else {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), BitmapData);
|
||||
return null;
|
||||
}
|
||||
field.input = cast val;
|
||||
field.input = bitmap;
|
||||
}
|
||||
|
||||
return val;
|
||||
|
||||
@@ -3,6 +3,7 @@ package funkin.editors.character;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.editors.extra.PropertyButton;
|
||||
import funkin.game.Character;
|
||||
import funkin.game.HealthIcon;
|
||||
import haxe.xml.Access;
|
||||
|
||||
class CharacterInfoScreen extends UISubstateWindow {
|
||||
@@ -10,7 +11,7 @@ class CharacterInfoScreen extends UISubstateWindow {
|
||||
|
||||
public var spriteTextBox:UITextBox;
|
||||
public var iconTextBox:UITextBox;
|
||||
public var iconSprite:FlxSprite;
|
||||
public var iconSprite:HealthIcon;
|
||||
public var gameOverCharTextBox:UITextBox;
|
||||
public var antialiasingCheckbox:UICheckbox;
|
||||
public var flipXCheckbox:UICheckbox;
|
||||
@@ -147,22 +148,14 @@ class CharacterInfoScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
function updateIcon(icon:String) {
|
||||
if (iconSprite == null) add(iconSprite = new FlxSprite());
|
||||
if (iconSprite == null) add(iconSprite = new HealthIcon());
|
||||
|
||||
if (iconSprite.animation.exists(icon)) return;
|
||||
@:privateAccess iconSprite.animation.clearAnimations();
|
||||
|
||||
var path:String = Paths.image('icons/$icon');
|
||||
if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
|
||||
|
||||
iconSprite.loadGraphic(path, true, 150, 150);
|
||||
iconSprite.animation.add(icon, [0], 0, false);
|
||||
iconSprite.antialiasing = true;
|
||||
iconSprite.animation.play(icon);
|
||||
|
||||
iconSprite.scale.set(0.5, 0.5);
|
||||
iconSprite.setIcon(icon);
|
||||
var size = Std.int(150 * 0.5);
|
||||
iconSprite.setUnstretchedGraphicSize(size, size, true);
|
||||
iconSprite.updateHitbox();
|
||||
iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2));
|
||||
iconSprite.setPosition(iconTextBox.x + iconTextBox.bWidth + 8, iconTextBox.y + (iconTextBox.bHeight / 2) - (iconSprite.height / 2));
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
function saveCharacterInfo() {
|
||||
|
||||
@@ -319,7 +319,8 @@ class CompactCharacterButton extends UIButton {
|
||||
autoAlpha = false;
|
||||
|
||||
charIcon = new HealthIcon(funkin.game.Character.getIconFromCharName(char));
|
||||
charIcon.scale.set(0.2, 0.2);
|
||||
var size = Std.int(150 * 0.2);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(10, bHeight/2 - charIcon.height / 2);
|
||||
charIcon.scrollFactor.set(1,1);
|
||||
@@ -331,11 +332,10 @@ class CompactCharacterButton extends UIButton {
|
||||
textBox.antialiasing = true;
|
||||
textBox.onChange = function(char:String) {
|
||||
char = funkin.game.Character.getIconFromCharName(char);
|
||||
var image = Paths.image("icons/" + char);
|
||||
if(!Assets.exists(image))
|
||||
image = Paths.image("icons/" + Flags.DEFAULT_HEALTH_ICON);
|
||||
charIcon.loadGraphic(image, true, 150, 150);
|
||||
charIcon.setIcon(char);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(10, bHeight/2 - charIcon.height / 2);
|
||||
}
|
||||
|
||||
deleteButton = new UIButton(textBox.x + 115 + 16, bHeight/2 - (32/2), "", function () {
|
||||
|
||||
@@ -3,6 +3,7 @@ package funkin.editors.charter;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.chart.ChartData.ChartMetaData;
|
||||
import funkin.editors.extra.PropertyButton;
|
||||
import funkin.game.HealthIcon;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@@ -19,7 +20,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
|
||||
public var displayNameTextBox:UITextBox;
|
||||
public var iconTextBox:UITextBox;
|
||||
public var iconSprite:FlxSprite;
|
||||
public var iconSprite:HealthIcon;
|
||||
public var opponentModeCheckbox:UICheckbox;
|
||||
public var coopAllowedCheckbox:UICheckbox;
|
||||
public var colorWheel:UIColorwheel;
|
||||
@@ -124,22 +125,14 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
function updateIcon(icon:String) {
|
||||
if (iconSprite == null) add(iconSprite = new FlxSprite());
|
||||
if (iconSprite == null) add(iconSprite = new HealthIcon());
|
||||
|
||||
if (iconSprite.animation.exists(icon)) return;
|
||||
@:privateAccess iconSprite.animation.clearAnimations();
|
||||
|
||||
var path:String = Paths.image('icons/$icon');
|
||||
if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
|
||||
|
||||
iconSprite.loadGraphic(path, true, 150, 150);
|
||||
iconSprite.animation.add(icon, [0], 0, false);
|
||||
iconSprite.antialiasing = true;
|
||||
iconSprite.animation.play(icon);
|
||||
|
||||
iconSprite.scale.set(0.5, 0.5);
|
||||
iconSprite.setIcon(icon);
|
||||
var size = Std.int(150 * 0.5);
|
||||
iconSprite.setUnstretchedGraphicSize(size, size, true);
|
||||
iconSprite.updateHitbox();
|
||||
iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2));
|
||||
iconSprite.setPosition(iconTextBox.x + iconTextBox.bWidth + 8, iconTextBox.y + (iconTextBox.bHeight / 2) - (iconSprite.height / 2));
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
public function saveMeta() {
|
||||
|
||||
@@ -43,20 +43,7 @@ class CharterStrumline extends UISprite {
|
||||
|
||||
if(strumLine.visible == null) strumLine.visible = true;
|
||||
|
||||
var icons = strumLine.characters != null ? strumLine.characters : [];
|
||||
|
||||
healthIcons = new FlxSpriteGroup(x, y);
|
||||
|
||||
for (i=>icon in icons) {
|
||||
var healthIcon = new HealthIcon(Character.getIconFromCharName(icon));
|
||||
healthIcon.scale.x = healthIcon.scale.y = 0.6 - (icons.length / 20);
|
||||
healthIcon.updateHitbox();
|
||||
healthIcon.x = FlxMath.lerp(0, icons.length * 20, (icons.length-1 != 0 ? i / (icons.length-1) : 0));
|
||||
healthIcon.y = draggable ? 29 : 7;
|
||||
healthIcon.alpha = strumLine.visible ? 1 : 0.4;
|
||||
healthIcons.add(healthIcon);
|
||||
}
|
||||
|
||||
members.push(healthIcons);
|
||||
|
||||
draggingSprite = new UISprite();
|
||||
@@ -70,8 +57,7 @@ class CharterStrumline extends UISprite {
|
||||
button = new CharterStrumlineOptions(this);
|
||||
members.push(button);
|
||||
|
||||
vocals = strumLine.vocalsSuffix.length > 0 ? FlxG.sound.load(Paths.voices(PlayState.SONG.meta.name, PlayState.difficulty, strumLine.vocalsSuffix)) : new FlxSound();
|
||||
vocals.group = FlxG.sound.defaultMusicGroup;
|
||||
updateInfo();
|
||||
|
||||
selectedWaveform = -1;
|
||||
}
|
||||
@@ -106,7 +92,9 @@ class CharterStrumline extends UISprite {
|
||||
|
||||
for (i=>icon in icons) {
|
||||
var healthIcon = new HealthIcon(Character.getIconFromCharName(icon));
|
||||
healthIcon.scale.x = healthIcon.scale.y = 0.6 - (icons.length / 20);
|
||||
var newScale = 0.6 - (icons.length / 20);
|
||||
var size = Std.int(150 * newScale);
|
||||
healthIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
healthIcon.updateHitbox();
|
||||
healthIcon.x = FlxMath.lerp(0, icons.length * 20, (icons.length-1 != 0 ? i / (icons.length-1) : 0));
|
||||
healthIcon.y = draggable ? 14 : 7;
|
||||
|
||||
@@ -192,7 +192,8 @@ class CharacterButton extends UIButton {
|
||||
super(x, y, "", null, 250, 54);
|
||||
|
||||
charIcon = new HealthIcon(Character.getIconFromCharName(char));
|
||||
charIcon.scale.set(0.3, 0.3);
|
||||
var size = Std.int(150 * 0.3);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(x + 10, bHeight/2 - charIcon.height / 2);
|
||||
charIcon.scrollFactor.set(1,1);
|
||||
@@ -204,11 +205,10 @@ class CharacterButton extends UIButton {
|
||||
textBox.antialiasing = true;
|
||||
textBox.onChange = function(char:String) {
|
||||
char = Character.getIconFromCharName(char);
|
||||
var image = Paths.image("icons/" + char);
|
||||
if(!Assets.exists(image))
|
||||
image = Paths.image("icons/" + Flags.DEFAULT_HEALTH_ICON);
|
||||
charIcon.loadGraphic(image, true, 150, 150);
|
||||
charIcon.setIcon(char);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(x + 10, bHeight/2 - charIcon.height / 2);
|
||||
}
|
||||
|
||||
deleteButton = new UIButton(textBox.x + 115 + 16, bHeight/2 - (32/2), "", function () {
|
||||
|
||||
@@ -8,6 +8,7 @@ import funkin.backend.chart.FNFLegacyParser.SwagSong;
|
||||
import funkin.backend.chart.PsychParser;
|
||||
import funkin.backend.chart.VSliceParser;
|
||||
import funkin.backend.utils.ZipUtil;
|
||||
import funkin.game.HealthIcon;
|
||||
import haxe.Json;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.BytesInput;
|
||||
@@ -33,7 +34,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
|
||||
public var displayNameTextBox:UITextBox;
|
||||
public var iconTextBox:UITextBox;
|
||||
public var iconSprite:FlxSprite;
|
||||
public var iconSprite:HealthIcon;
|
||||
public var opponentModeCheckbox:UICheckbox;
|
||||
public var coopAllowedCheckbox:UICheckbox;
|
||||
public var colorWheel:UIColorwheel;
|
||||
@@ -328,22 +329,14 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
function updateIcon(icon:String) {
|
||||
if (iconSprite == null) menuDataGroup.add(iconSprite = new FlxSprite());
|
||||
if (iconSprite == null) menuDataGroup.add(iconSprite = new HealthIcon());
|
||||
|
||||
if (iconSprite.animation.exists(icon)) return;
|
||||
@:privateAccess iconSprite.animation.clearAnimations();
|
||||
|
||||
var path:String = Paths.image('icons/$icon');
|
||||
if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
|
||||
|
||||
iconSprite.loadGraphic(path, true, 150, 150);
|
||||
iconSprite.animation.add(icon, [0], 0, false);
|
||||
iconSprite.antialiasing = true;
|
||||
iconSprite.animation.play(icon);
|
||||
|
||||
iconSprite.scale.set(0.5, 0.5);
|
||||
iconSprite.setIcon(icon);
|
||||
var size = Std.int(150 * 0.5);
|
||||
iconSprite.setUnstretchedGraphicSize(size, size, true);
|
||||
iconSprite.updateHitbox();
|
||||
iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2));
|
||||
iconSprite.setPosition(iconTextBox.x + iconTextBox.bWidth + 8, iconTextBox.y + (iconTextBox.bHeight / 2) - (iconSprite.height / 2));
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
function saveSongInfo() {
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
package funkin.game;
|
||||
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import funkin.backend.scripting.events.healthicon.HealthIconChangeEvent;
|
||||
|
||||
class HealthIcon extends FlxSprite
|
||||
class HealthIcon extends FunkinSprite
|
||||
{
|
||||
/**
|
||||
* Used for FreeplayState! If you use it elsewhere, prob gonna annoying
|
||||
* Attaches the icon to a sprite, following it's position
|
||||
*/
|
||||
public var sprTracker:FlxSprite;
|
||||
/**
|
||||
* Where to place the icon in relation to the sprite
|
||||
*
|
||||
* LEFT: Left of the sprite
|
||||
*
|
||||
* CENTER: Center of the sprite
|
||||
*
|
||||
* RIGHT: Right of the sprite
|
||||
*/
|
||||
public var sprTrackerAlignment:TrackerAlignment = RIGHT;
|
||||
/**
|
||||
* Offset of the icon in relation to the sprite
|
||||
*
|
||||
* By default it is set to (10, -30) and is intended to be used with Alphabet
|
||||
*/
|
||||
public var sprTrackerOffset:FlxPoint = new FlxPoint(10, -30);
|
||||
|
||||
/**
|
||||
* The currently showing icon
|
||||
@@ -20,31 +40,60 @@ class HealthIcon extends FlxSprite
|
||||
|
||||
/**
|
||||
* Health steps in this format:
|
||||
* Min Percentage => Frame Index
|
||||
*
|
||||
* Min Percentage => Frame Index / Animation Name
|
||||
*/
|
||||
public var healthSteps:Map<Int, Int> = null;
|
||||
public var healthSteps:Map<Int, OneOfTwo<String, Int>> = null;
|
||||
|
||||
/**
|
||||
* current animation state
|
||||
* Current animation state
|
||||
*/
|
||||
public var curAnimState:Int = -1;
|
||||
public var curAnimState:OneOfTwo<String, Int> = -1;
|
||||
|
||||
/**
|
||||
* The Default Scale For The Icon
|
||||
*
|
||||
* This is what scale the icon should return to when its bump animation is finished
|
||||
*/
|
||||
public var defaultScale:Float = 1;
|
||||
|
||||
/**
|
||||
* Whenever or not the icon is animated or not
|
||||
*/
|
||||
public var animated:Bool = false;
|
||||
|
||||
/**
|
||||
* XML Animated Icon data
|
||||
*
|
||||
* `null` if the icon is not animated or its invalid
|
||||
*/
|
||||
public var xmlData:Xml;
|
||||
|
||||
/**
|
||||
* Extra offsets to add when updating the hitbox
|
||||
*/
|
||||
public var extraOffsets:FlxPoint = FlxPoint.get();
|
||||
|
||||
/**
|
||||
* Helper for HScript who can't make maps
|
||||
* @param steps Something like this: `[[0, 1], [20, 0]]`
|
||||
*
|
||||
* THIS IS DEPRECATED AND WILL BE REMOVED IN THE FUTURE
|
||||
*
|
||||
* Please set the healthSteps directly in the script instead, hscript does support maps
|
||||
*
|
||||
* @param steps Something like this: `[[0, 1], [20, 0]]` or `[[0, "losing"], [20, "neutral"]]` for animated icons
|
||||
*/
|
||||
public function setHealthSteps(steps:Array<Array<Int>>) { // helper for hscript that can't do maps
|
||||
@:dox(hide) @:noCompletion @:deprecated("use healthSteps instead")
|
||||
public function setHealthSteps(steps:Array<Array<OneOfTwo<String, Int>>>):Void { // helper for hscript that can't do maps
|
||||
if (steps == null) return;
|
||||
healthSteps = [];
|
||||
for(s in steps)
|
||||
for (s in steps)
|
||||
if (s.length > 1)
|
||||
healthSteps[s[0]] = s[1];
|
||||
var am = 0;
|
||||
for(k=>e in healthSteps) am++;
|
||||
|
||||
if (am <= 0) healthSteps = [
|
||||
0 => 1, // losing icon
|
||||
20 => 0, // normal icon
|
||||
if (Lambda.count(healthSteps) <= 0) healthSteps = [
|
||||
0 => (this.animated ? "losing" : 1), // losing icon
|
||||
20 => (this.animated ? "neutral" : 0), // normal icon
|
||||
];
|
||||
}
|
||||
|
||||
@@ -58,50 +107,338 @@ class HealthIcon extends FlxSprite
|
||||
scrollFactor.set();
|
||||
}
|
||||
|
||||
public function setIcon(char:String, width:Int = 150, height:Int = 150) {
|
||||
if(curCharacter != char || this.width != width || this.height != height) {
|
||||
curCharacter = char;
|
||||
var path = Paths.image('icons/$char');
|
||||
if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
|
||||
|
||||
loadGraphic(path, true, width, height);
|
||||
|
||||
animation.add(char, [for(i in 0...frames.frames.length) i], 0, false, isPlayer);
|
||||
antialiasing = true;
|
||||
animation.play(char);
|
||||
|
||||
healthSteps = [
|
||||
0 => 1, // losing icon
|
||||
20 => 0, // normal icon
|
||||
];
|
||||
|
||||
if (frames.frames.length >= 3)
|
||||
healthSteps[80] = 2; // winning icon
|
||||
}
|
||||
/**
|
||||
* Called every beat, and causes the icon to become bigger
|
||||
**/
|
||||
public dynamic function bump():Void {
|
||||
var iconScale = Flags.BOP_ICON_SCALE;
|
||||
scale.set(defaultScale * iconScale, defaultScale * iconScale);
|
||||
updateHitbox();
|
||||
}
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
/**
|
||||
* Called every frame and causes the icon to become smaller
|
||||
**/
|
||||
public dynamic function updateBump():Void {
|
||||
var iconLerp = Flags.ICON_LERP;
|
||||
scale.set(CoolUtil.fpsLerp(scale.x, defaultScale, iconLerp), CoolUtil.fpsLerp(scale.y, defaultScale, iconLerp));
|
||||
updateHitbox();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon to the specified character
|
||||
* @param char Character to set the icon to
|
||||
* @param allowAnimated Whenever the icon can be animated
|
||||
**/
|
||||
public function setIcon(char:String, allowAnimated:Bool = true):Void {
|
||||
if (curCharacter == char) return;
|
||||
|
||||
var oldIconPath = 'icons/$char';
|
||||
var newIconPath = 'icons/$char/icon';
|
||||
|
||||
if (!Assets.exists(Paths.image(oldIconPath)) && !Assets.exists(Paths.image(newIconPath))) {
|
||||
char = 'face';
|
||||
oldIconPath = 'icons/$char';
|
||||
newIconPath = 'icons/$char/icon';
|
||||
}
|
||||
curCharacter = char;
|
||||
|
||||
var iconPath = Assets.exists(Paths.image(oldIconPath)) ? oldIconPath : newIconPath;
|
||||
var iconXmlPath = Paths.getPath('images/icons/$char/data.xml');
|
||||
var iconFoundData = Assets.exists(iconXmlPath);
|
||||
|
||||
try {
|
||||
xmlData = iconFoundData ? Xml.parse(Assets.getText(iconXmlPath)) : null;
|
||||
} catch(e) {
|
||||
Logs.trace('Error while parsing icon data for $char: ${e.message}', ERROR);
|
||||
xmlData = null;
|
||||
}
|
||||
var xmlValid = xmlData != null && (xmlData = xmlData.firstElement()) != null;
|
||||
|
||||
this.animated = allowAnimated && iconFoundData && xmlValid && Paths.framesExists(Paths.image(newIconPath), true, true, true);
|
||||
|
||||
var iconAmt:Int = 0;
|
||||
var iconSize:Int = 0;
|
||||
var iconIsPlayer = xmlValid ? xmlData.get("facing").getDefault("right").toLowerCase() == "left" : false;
|
||||
|
||||
animateAtlas = null; // reset
|
||||
if (this.animated)
|
||||
loadSprite(Paths.image(newIconPath));
|
||||
else {
|
||||
var iconAsset:FlxGraphic = FlxG.bitmap.add(Paths.image(iconPath));
|
||||
var assetW:Float = iconAsset.width;
|
||||
var assetH:Float = iconAsset.height;
|
||||
|
||||
iconAmt = Math.round(assetW / assetH); // Just in case the icon is in a weird aspect ratio
|
||||
iconSize = Math.floor(assetW / iconAmt);
|
||||
if (iconSize * iconAmt > assetW) {
|
||||
iconSize = Math.floor(assetW / iconAmt);
|
||||
iconAmt = Math.floor(assetW / iconSize);
|
||||
}
|
||||
|
||||
loadGraphic(iconAsset, true, Std.int(Math.min(iconSize, assetW)), Std.int(Math.min(iconSize, assetH)));
|
||||
|
||||
setGraphicSize(150);
|
||||
updateHitbox();
|
||||
|
||||
animation.add(char, [for(i in 0...iconAmt) i], 0, false, isPlayer != iconIsPlayer);
|
||||
animation.play(char);
|
||||
}
|
||||
|
||||
if(!animation.onFinishEnd.has(animFinishCallback))
|
||||
animation.onFinishEnd.add(animFinishCallback);
|
||||
if(animateAtlas != null && !animateAtlas.anim.onFinishEnd.has(animFinishCallback))
|
||||
animateAtlas.anim.onFinishEnd.add(animFinishCallback);
|
||||
|
||||
var parsedSteps:Map<Int, String> = [];
|
||||
|
||||
antialiasing = true;
|
||||
if (xmlValid) {
|
||||
if (xmlData.exists("antialiasing"))
|
||||
antialiasing = xmlData.get("antialiasing").toLowerCase() == "true";
|
||||
if (xmlData.exists("offsetX"))
|
||||
extraOffsets.x = Std.parseFloat(xmlData.get("offsetX")).getDefault(0);
|
||||
if (xmlData.exists("offsetY"))
|
||||
extraOffsets.y = Std.parseFloat(xmlData.get("offsetY")).getDefault(0);
|
||||
|
||||
for (node in xmlData.elements())
|
||||
switch(node.nodeName) {
|
||||
case "transition":
|
||||
if (this.animated == false) {
|
||||
Logs.trace('Icon ${char} data <transition> is not allowed when not animated', WARNING);
|
||||
continue;
|
||||
}
|
||||
if (!node.exists("anim")) {
|
||||
Logs.trace('Icon ${char} data <transition> is missing anim', WARNING);
|
||||
continue;
|
||||
}
|
||||
if (!node.exists("to")) {
|
||||
Logs.trace('Icon ${char} data <transition> is missing to', WARNING);
|
||||
continue;
|
||||
}
|
||||
if (!node.exists("from")) {
|
||||
Logs.trace('Icon ${char} data <transition> is missing from', WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
var animName = 'from-${node.get("from")}-to-${node.get("to")}';
|
||||
if (node.exists("offsetX") || node.exists("offsetY"))
|
||||
addOffset(animName, Std.parseFloat(node.get("offsetX")).getDefault(0), Std.parseFloat(node.get("offsetY")).getDefault(0));
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), false); // don't allow looping for transitions
|
||||
if (animateAtlas == null && animation.exists(animName))
|
||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||
case "anim":
|
||||
if (this.animated == false) {
|
||||
Logs.trace('Icon ${char} data <anim> is not allowed when not animated', WARNING);
|
||||
continue;
|
||||
}
|
||||
if (!node.exists("name")) {
|
||||
Logs.trace('Icon ${char} data <anim> is missing name', WARNING);
|
||||
continue;
|
||||
}
|
||||
if (!node.exists("anim")) {
|
||||
Logs.trace('Icon ${char} data <anim> is missing anim', WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
var animName = node.get("name");
|
||||
|
||||
var offsetX:Float = 0;
|
||||
var offsetY:Float = 0;
|
||||
if (node.exists("offsetX"))
|
||||
offsetX = Std.parseFloat(node.get("offsetX")).getDefault(0);
|
||||
else if (node.exists("offsetx"))
|
||||
offsetX = Std.parseFloat(node.get("offsetx")).getDefault(0);
|
||||
|
||||
if (node.exists("offsetY"))
|
||||
offsetY = Std.parseFloat(node.get("offsetY")).getDefault(0);
|
||||
else if (node.exists("offsety"))
|
||||
offsetY = Std.parseFloat(node.get("offsety")).getDefault(0);
|
||||
|
||||
addOffset(animName, offsetX, offsetY);
|
||||
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), node.get("looped").getDefault("true").toLowerCase() == "true");
|
||||
if (animateAtlas == null && animation.exists(animName))
|
||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||
case "step":
|
||||
if (!node.exists("percent")) {
|
||||
Logs.trace('Icon ${char} data <step> is missing percent', WARNING);
|
||||
continue;
|
||||
}
|
||||
if (!node.exists("name")) {
|
||||
Logs.trace('Icon ${char} data <step> is missing name', WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
parsedSteps.set(Std.parseInt(node.get("percent")).getDefault(0), node.get("name"));
|
||||
}
|
||||
}
|
||||
|
||||
if (Lambda.count(parsedSteps) > 0) {
|
||||
healthSteps = parsedSteps;
|
||||
} else {
|
||||
var hasLosing = this.animated ? hasAnim("losing") : iconAmt >= 2;
|
||||
var hasWinning = this.animated ? hasAnim("winning") : iconAmt >= 3;
|
||||
|
||||
if (hasLosing) {
|
||||
healthSteps = [
|
||||
0 => (this.animated ? "losing" : 1), // losing icon
|
||||
20 => (this.animated ? "neutral" : 0), // normal icon
|
||||
];
|
||||
} else {
|
||||
healthSteps = [
|
||||
0 => (this.animated ? "neutral" : 0), // normal icon
|
||||
];
|
||||
}
|
||||
if (hasWinning)
|
||||
healthSteps.set(80, this.animated ? "winning" : 2); // winning icon
|
||||
}
|
||||
var data = getIconAnim(health);
|
||||
if (data.isValid) {
|
||||
if (this.animated)
|
||||
playAnim(data.animState);
|
||||
else
|
||||
animation.curAnim.curFrame = data.animState;
|
||||
curAnimState = data.animState;
|
||||
}
|
||||
|
||||
if (animateAtlas != null) {
|
||||
@:bypassAccessor
|
||||
frameWidth = 150;
|
||||
@:bypassAccessor
|
||||
frameHeight = 150;
|
||||
extraOffsets.x -= frameWidth / 2;
|
||||
extraOffsets.y -= frameHeight / 2;
|
||||
updateHitbox();
|
||||
} else {
|
||||
setGraphicSize(150);
|
||||
updateHitbox();
|
||||
}
|
||||
|
||||
defaultScale = (xmlValid && xmlData.exists("scale")) ? Std.parseFloat(xmlData.get("scale")).getDefault(scale.x) : scale.x;
|
||||
scale.set(defaultScale, defaultScale);
|
||||
updateHitbox();
|
||||
}
|
||||
|
||||
var normalizedNames = ["neutral", "losing", "winning"];
|
||||
private function normalizeAnim(anim:OneOfTwo<String, Int>):OneOfTwo<String, Int> {
|
||||
if(this.animated) {
|
||||
if (anim is Int) {
|
||||
var _:Int = cast anim;
|
||||
if(_ >= 0 && _ < normalizedNames.length)
|
||||
anim = normalizedNames[anim];
|
||||
}
|
||||
} else {
|
||||
if (anim is String) {
|
||||
var _ = normalizedNames.indexOf(cast anim);
|
||||
if(_ >= 0)
|
||||
anim = _;
|
||||
}
|
||||
}
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animation data for a specific health percentage
|
||||
* @param health Health percentage
|
||||
* @return Animation data (-1 if invalid)
|
||||
*/
|
||||
public dynamic function getIconAnim(health:Float):IconAnimData {
|
||||
var i:OneOfTwo<String, Int> = -1;
|
||||
var oldKey:Int = -1;
|
||||
var isValid = false;
|
||||
for (k=>icon in healthSteps) if (k > oldKey && k <= health * 100) {
|
||||
oldKey = k;
|
||||
i = icon;
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
i = normalizeAnim(i);
|
||||
|
||||
return new IconAnimData(i, isValid);
|
||||
}
|
||||
|
||||
override function update(elapsed:Float):Void {
|
||||
super.update(elapsed);
|
||||
|
||||
if (sprTracker != null)
|
||||
setPosition(sprTracker.x + sprTracker.width + 10, sprTracker.y - 30);
|
||||
if (sprTracker != null) {
|
||||
setPosition(sprTracker.x + (switch sprTrackerAlignment {
|
||||
case LEFT: -width;
|
||||
case CENTER: (sprTracker.width - width) / 2;
|
||||
case RIGHT: sprTracker.width;
|
||||
}) + sprTrackerOffset.x, sprTracker.y + sprTrackerOffset.y);
|
||||
}
|
||||
|
||||
if (animation.curAnim != null) {
|
||||
var i:Int = -1;
|
||||
var oldKey:Int = -1;
|
||||
for (k=>icon in healthSteps) if (k > oldKey && k <= health * 100) {
|
||||
oldKey = k;
|
||||
i = icon;
|
||||
}
|
||||
if (i >= 0 && curAnimState != i) {
|
||||
var event = EventManager.get(funkin.backend.scripting.events.healthicon.HealthIconChangeEvent).recycle(i, this);
|
||||
if (animation.curAnim != null || (this.animated && animateAtlas != null)) {
|
||||
var data = getIconAnim(health);
|
||||
var localAnimState = data.animState;
|
||||
|
||||
if (data.isValid && curAnimState != localAnimState) {
|
||||
var event = EventManager.get(HealthIconChangeEvent).recycle(localAnimState, this);
|
||||
funkin.backend.scripting.GlobalScript.event("onHealthIconAnimChange", event);
|
||||
if (!event.cancelled)
|
||||
animation.curAnim.curFrame = event.amount;
|
||||
if (!event.cancelled) {
|
||||
if (this.animated) {
|
||||
var transAnim = 'from-$curAnimState-to-${event.anim}';
|
||||
playAnim(hasAnim(transAnim) ? transAnim : event.anim);
|
||||
} else {
|
||||
if(animation.curAnim != null)
|
||||
animation.curAnim.curFrame = event.anim;
|
||||
}
|
||||
}
|
||||
|
||||
curAnimState = event.amount;
|
||||
curAnimState = localAnimState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function animFinishCallback(anim:String):Void {
|
||||
if (this.animated)
|
||||
if (anim.startsWith("from-"))
|
||||
playAnim(anim.substr(anim.lastIndexOf('-') + 1));
|
||||
}
|
||||
|
||||
override function updateHitbox():Void {
|
||||
super.updateHitbox();
|
||||
offset += extraOffsets;
|
||||
}
|
||||
}
|
||||
|
||||
@:dox(hide)
|
||||
class IconAnimData {
|
||||
public var animState:OneOfTwo<String, Int>;
|
||||
public var isValid:Bool;
|
||||
|
||||
public function new(animState:OneOfTwo<String, Int>, isValid:Bool) {
|
||||
this.animState = animState;
|
||||
this.isValid = isValid;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return '$animState (Valid: $isValid)';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for `funkin.game.HealthIcon.sprTrackerAlignment`.
|
||||
* This determines the position of the icon in relation to the sprite tracker.
|
||||
**/
|
||||
enum abstract TrackerAlignment(Int) {
|
||||
/**
|
||||
* Left of the sprite tracker
|
||||
*
|
||||
* Mathematically: `tracker.x - icon.width`
|
||||
*/
|
||||
var LEFT = 0;
|
||||
/**
|
||||
* Center of the sprite tracker
|
||||
*
|
||||
* Mathematically: `tracker.x + (tracker.width - icon.width) / 2`
|
||||
*/
|
||||
var CENTER = 1;
|
||||
/**
|
||||
* Right of the sprite tracker
|
||||
*
|
||||
* Mathematically: `tracker.x + tracker.width`
|
||||
*/
|
||||
var RIGHT = 2;
|
||||
}
|
||||
@@ -646,10 +646,11 @@ class PlayState extends MusicBeatState
|
||||
// case "":
|
||||
// ADD YOUR HARDCODED SCRIPTS HERE!
|
||||
default:
|
||||
var scriptsFolders:Array<String> = ['songs/${SONG.meta.name.toLowerCase()}/scripts', 'data/charts/', 'songs/'];
|
||||
var normal = 'songs/${SONG.meta.name.toLowerCase()}/scripts';
|
||||
var scriptsFolders:Array<String> = [normal, normal + '/$difficulty/', 'data/charts/', 'songs/'];
|
||||
|
||||
for(folder in scriptsFolders) {
|
||||
for(file in Paths.getFolderContent(folder, true, fromMods ? MODS : BOTH)) {
|
||||
for (folder in scriptsFolders) {
|
||||
for (file in Paths.getFolderContent(folder, true, fromMods ? MODS : BOTH)) {
|
||||
if (folder == 'data/charts/')
|
||||
Logs.warn('data/charts/ is deprecated and will be removed in the future. Please move script $file to songs/', DARKYELLOW, "PlayState");
|
||||
|
||||
@@ -848,7 +849,8 @@ class PlayState extends MusicBeatState
|
||||
|
||||
// Make icons appear in the correct spot during cutscenes
|
||||
healthBar.update(0);
|
||||
updateIconPositions();
|
||||
if (updateIconPositions != null)
|
||||
updateIconPositions();
|
||||
|
||||
__updateNote_event = EventManager.get(NoteUpdateEvent);
|
||||
|
||||
@@ -1266,18 +1268,19 @@ class PlayState extends MusicBeatState
|
||||
]));
|
||||
}
|
||||
|
||||
function updateIconPositions() {
|
||||
dynamic function updateIconPositions() {
|
||||
var iconOffset = Flags.ICON_OFFSET;
|
||||
var healthBarPercent = healthBar.percent;
|
||||
|
||||
var center:Float = healthBar.x + healthBar.width * FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0);
|
||||
var center:Float = healthBar.x + healthBar.width * FlxMath.remapToRange(healthBarPercent, 0, 100, 1, 0);
|
||||
|
||||
iconP1.x = center - iconOffset;
|
||||
iconP2.x = center - (iconP2.width - iconOffset);
|
||||
|
||||
health = FlxMath.bound(health, 0, maxHealth);
|
||||
|
||||
iconP1.health = healthBar.percent / 100;
|
||||
iconP2.health = 1 - (healthBar.percent / 100);
|
||||
iconP1.health = healthBarPercent / 100;
|
||||
iconP2.health = 1 - (healthBarPercent / 100);
|
||||
}
|
||||
|
||||
function updateRatingStuff() {
|
||||
@@ -1323,15 +1326,13 @@ class PlayState extends MusicBeatState
|
||||
}*/
|
||||
}
|
||||
|
||||
if (doIconBop) {
|
||||
var iconLerp = Flags.ICON_LERP;
|
||||
iconP1.scale.set(lerp(iconP1.scale.x, 1, iconLerp), lerp(iconP1.scale.y, 1, iconLerp));
|
||||
iconP2.scale.set(lerp(iconP2.scale.x, 1, iconLerp), lerp(iconP2.scale.y, 1, iconLerp));
|
||||
if (doIconBop)
|
||||
for (icon in [iconP1, iconP2])
|
||||
if (icon.updateBump != null)
|
||||
icon.updateBump();
|
||||
|
||||
iconP1.updateHitbox();
|
||||
iconP2.updateHitbox();
|
||||
}
|
||||
updateIconPositions();
|
||||
if (updateIconPositions != null)
|
||||
updateIconPositions();
|
||||
|
||||
if (startingSong)
|
||||
{
|
||||
@@ -1794,9 +1795,9 @@ class PlayState extends MusicBeatState
|
||||
|
||||
var event:NoteHitEvent;
|
||||
if (strumLine != null && !strumLine.cpu)
|
||||
event = EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, true, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, 0.023, daRating, Options.splashesEnabled && !note.isSustainNote && daRating == "sick");
|
||||
event = EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, true, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, 0.023, daRating, Options.splashesEnabled && !note.isSustainNote && daRating == "sick", 0.5, true, 0.7, true, true, iconP1);
|
||||
else
|
||||
event = EventManager.get(NoteHitEvent).recycle(false, false, false, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, false, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, 0, null, 0, daRating, false);
|
||||
event = EventManager.get(NoteHitEvent).recycle(false, false, false, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, false, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, 0, null, 0, daRating, false, 0.5, true, 0.7, true, true, iconP2);
|
||||
event.deleteNote = !note.isSustainNote; // work around, to allow sustain notes to be deleted
|
||||
event = scripts.event(strumLine != null && !strumLine.cpu ? "onPlayerHit" : "onDadHit", event);
|
||||
strumLine.onHit.dispatch(event);
|
||||
@@ -1959,14 +1960,9 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
|
||||
if (doIconBop)
|
||||
{
|
||||
var iconScale = Flags.BOP_ICON_SCALE;
|
||||
iconP1.scale.set(iconScale, iconScale);
|
||||
iconP2.scale.set(iconScale, iconScale);
|
||||
|
||||
iconP1.updateHitbox();
|
||||
iconP2.updateHitbox();
|
||||
}
|
||||
for (icon in [iconP1, iconP2])
|
||||
if (icon.bump != null)
|
||||
icon.bump();
|
||||
|
||||
scripts.call("beatHit", [curBeat]);
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ class FreeplayState extends MusicBeatState
|
||||
|
||||
var icon:HealthIcon = new HealthIcon(songs[i].icon);
|
||||
icon.sprTracker = songText;
|
||||
icon.setUnstretchedGraphicSize(150, 150, true);
|
||||
icon.updateHitbox();
|
||||
|
||||
// using a FlxGroup is too much fuss!
|
||||
iconArray.push(icon);
|
||||
|
||||
@@ -14,6 +14,10 @@ class IconOption extends TextOption {
|
||||
|
||||
iconSpr = new HealthIcon(icon, false);
|
||||
iconSpr.setPosition(90 - iconSpr.width, (__text.height - iconSpr.height) / 2);
|
||||
iconSpr.setUnstretchedGraphicSize(150, 150, true);
|
||||
iconSpr.updateHitbox();
|
||||
iconSpr.sprTracker = __text;
|
||||
iconSpr.sprTrackerAlignment = LEFT;
|
||||
add(iconSpr);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package funkin.options.type;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.game.HealthIcon;
|
||||
|
||||
/**
|
||||
* Option type that has a new button, and is green.
|
||||
|
||||