diff --git a/assets/images/menus/options/meter.png b/assets/images/menus/options/meter.png new file mode 100644 index 00000000..4607e9b0 Binary files /dev/null and b/assets/images/menus/options/meter.png differ diff --git a/assets/images/menus/options/meter.xml b/assets/images/menus/options/meter.xml new file mode 100644 index 00000000..fddf0e4e --- /dev/null +++ b/assets/images/menus/options/meter.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/assets/languages/en/Options.xml b/assets/languages/en/Options.xml index 4e0b46fd..2557c8ec 100644 --- a/assets/languages/en/Options.xml +++ b/assets/languages/en/Options.xml @@ -105,7 +105,10 @@ If unchecked, will censor the Week 7 cutscenes. Camera Zoom on Beat - If unchecked, will stop the camera from zooming in every 4 beats + If unchecked, will stop the camera from zooming in every 4 beats. + + SFX Volume + Changes only the volume of the SFX instead of everything. diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx index 767f239e..2e89b29f 100644 --- a/source/funkin/options/Options.hx +++ b/source/funkin/options/Options.hx @@ -29,6 +29,7 @@ class Options public static var autoPause:Bool = true; public static var antialiasing:Bool = true; public static var volume:Float = 1; + public static var volumeSFX:Float = 1; public static var week6PixelPerfect:Bool = true; public static var gameplayShaders:Bool = true; public static var colorHealthBar:Bool = true; diff --git a/source/funkin/options/categories/GameplayOptions.hx b/source/funkin/options/categories/GameplayOptions.hx index 4d6dc72c..0de4ceeb 100644 --- a/source/funkin/options/categories/GameplayOptions.hx +++ b/source/funkin/options/categories/GameplayOptions.hx @@ -34,6 +34,13 @@ class GameplayOptions extends OptionsScreen { getName("camZoomOnBeat"), getDesc("camZoomOnBeat"), "camZoomOnBeat")); + add(new MeterOption( + getName("volumeSFX"), + getDesc("volumeSFX"), + 0, // minimum + 1, // maximum + 0.1, // change + "volumeSFX")); } private function __changeOffset(offset) diff --git a/source/funkin/options/type/MeterOption.hx b/source/funkin/options/type/MeterOption.hx new file mode 100644 index 00000000..7902e09e --- /dev/null +++ b/source/funkin/options/type/MeterOption.hx @@ -0,0 +1,208 @@ +package funkin.options.type; + +// TODO: RECODE ALL OF THISS!! ITS SO SHITTY + +import flixel.graphics.frames.FlxFrame; +import flixel.math.FlxMatrix; +import flixel.math.FlxRect; + +@:access(flixel.FlxSprite._frame) +class MeterOption extends OptionType { + public var selectCallback:Float->Void; + + public var min:Float; + public var max:Float; + + public var currentSelection:Float; + public var changeVal:Float; + + public var parent:Dynamic; + + public var barWidth(default, set):Int; + + private var rawText(default, set):String; + + public var text(get, set):String; + private function get_text() {return __text.text;} + private function set_text(v:String) {return __text.text = v;} + + private var __text:Alphabet; + var optionName:String; + + var barScale:Float = 0.75; + var realBarWidth:Float; + var cornerWidth:Float; + var slider:FlxSprite; + var cornerEmpty:FlxSprite; + var barEmpty:FlxSprite; + var cornerFill:FlxSprite; + var barFill:FlxSprite; + var valueWidth:Float; + var cornerClipRect:FlxRect; + + public function new(text:String, desc:String, min:Float, max:Float, changeVal:Float, optionName:String, barWidth:Int = 520, + ?selectCallback:Float->Void = null, ?parent:Dynamic) + { + super(desc); + + this.selectCallback = selectCallback; + this.min = min; + this.max = max; + if (parent == null) parent = Options; + + this.parent = parent; + + if (Reflect.field(parent, optionName) != null) this.currentSelection = Reflect.field(parent, optionName); + this.changeVal = changeVal; + this.optionName = optionName; + + add(__text = new Alphabet(20, 20, "", "bold")); + rawText = text; + + var frames = Paths.getFrames('menus/options/meter'); + add(slider = new FlxSprite(0, 24)); + slider.frames = frames; + slider.animation.addByPrefix('slider', 'meter slider', 24); + slider.animation.play('slider'); + slider.antialiasing = true; + slider.scale.set(barScale, barScale); + slider.updateHitbox(); + + (cornerEmpty = new FlxSprite()).frames = (barEmpty = new FlxSprite()).frames = frames; + (cornerFill = new FlxSprite()).frames = (barFill = new FlxSprite()).frames = frames; + cornerEmpty.animation.addByPrefix('corner', 'meter empty corner', 24); + cornerEmpty.animation.play('corner'); + barEmpty.animation.addByPrefix('bar', 'meter empty piece', 24); + barEmpty.animation.play('bar'); + cornerFill.animation.addByPrefix('corner', 'meter filled corner', 24); + cornerFill.animation.play('corner'); + barFill.animation.addByPrefix('bar', 'meter filled piece', 24); + barFill.animation.play('bar'); + + cornerClipRect = new FlxRect(); + cornerEmpty.rawClipRect = cornerClipRect; + cornerFill.rawClipRect = cornerClipRect; + + _matrix = new FlxMatrix(); + cornerWidth = Math.max(cornerFill.frameWidth, cornerEmpty.frameWidth); + this.barWidth = barWidth; + } + + function set_barWidth(value:Int):Int { + if (value == barWidth) return value; + realBarWidth = Math.max(cornerWidth + value / barScale, cornerWidth * 2); + updateBar(); + + __text.x = x + 20 + realBarWidth * barScale; + + return barWidth = value; + } + + function updateBar() { + var w = (currentSelection - min) / (max - min) * (realBarWidth - cornerWidth * 2) + cornerWidth; + slider.x = x + w * barScale - slider.width * 0.5; + valueWidth = w; + } + + inline function drawObject(sprite:FlxSprite, camera:FlxCamera, x:Float, y:Float) { + getScreenPosition(_point, camera).subtractPoint(offset); + _matrix.translate(_point.x + x, _point.y + y); + + /*if (isPixelPerfectRender(camera)) { + _matrix.tx = Math.floor(_matrix.tx); + _matrix.ty = Math.floor(_matrix.ty); + }*/ + + if (layer != null) layer.drawPixels(sprite, camera, sprite._frame, sprite.framePixels, _matrix, colorTransform, blend, true); + else camera.drawPixels(sprite._frame, sprite.framePixels, _matrix, colorTransform, blend, true); + } + + var lastX:Float; + var temp:Float; + function drawCorner(width:Float, flip:Bool, camera:FlxCamera) { + if ((temp = Math.max(Math.min(width, cornerFill.frameWidth), 0)) > 0) { + cornerClipRect.set(0, 0, temp, cornerFill.frameHeight); + cornerFill.frame = cornerFill.frames.frames[cornerFill.animation.frameIndex]; + cornerFill._frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, flip != camera.flipX, flipY != camera.flipY); + _matrix.scale(barScale, barScale); + drawObject(cornerFill, camera, 0, 37); + } + + if (temp < cornerEmpty.frameWidth) { + cornerClipRect.set(temp, 0, cornerEmpty.frameWidth - temp, cornerEmpty.frameHeight); + cornerEmpty.frame = cornerEmpty.frames.frames[cornerEmpty.animation.frameIndex]; + cornerEmpty._frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, flip != camera.flipX, flipY != camera.flipY); + _matrix.scale(barScale, barScale); + drawObject(cornerEmpty, camera, temp * barScale, 37); + } + + x += cornerWidth * barScale; + } + + function drawBar(width:Float, camera:FlxCamera) { + temp = realBarWidth - cornerWidth * 2; + if (width > 0) { + barFill._frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, camera.flipX, flipY != camera.flipY); + _matrix.scale((Math.min(width, temp) + 2) / barFill.frameWidth * barScale, barScale); + drawObject(barFill, camera, -1, 37); + } + + if (width < temp) { + barEmpty._frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, camera.flipX, flipY != camera.flipY); + _matrix.scale((Math.max(temp - width, 0) + 1) / barEmpty.frameWidth * barScale, barScale); + drawObject(barEmpty, camera, width * barScale, 37); + } + + /*if (width < (temp = realBarWidth - cornerWidth * 2)) { + barEmpty._frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, camera.flipX, flipY != camera.flipY); + _matrix.scale((width - realBarWidth + cornerWidth + 1) / barFill.frameWidth, 1); + drawObject(barEmpty, camera, realBarWidth - width, 37); + }*/ + + x += temp * barScale; + } + + function set_rawText(v:String) { + rawText = v; + __text.text = TU.exists(rawText) ? TU.translate(rawText) : rawText; + return v; + } + + override function draw() { + lastX = x; + + for (camera in cameras) { + if (!camera.visible || !camera.exists) continue; + + drawCorner(currentSelection == min ? 0 : valueWidth, false, camera); + drawBar(valueWidth - cornerWidth, camera); + drawCorner(currentSelection == max ? cornerWidth : valueWidth - realBarWidth + cornerWidth, true, camera); + + x = lastX; + } + super.draw(); + } + + override function destroy() { + super.destroy(); + cornerEmpty.destroy(); + barEmpty.destroy(); + cornerFill.destroy(); + barFill.destroy(); + } + + override function reloadStrings() { + super.reloadStrings(); + this.rawText = rawText; + } + + override function onChangeSelection(change:Float) { + if (currentSelection <= min && change == -1 || currentSelection >= max && change == 1) return; + currentSelection = FlxMath.roundDecimal(currentSelection + (change * changeVal), FlxMath.getDecimals(changeVal)); + + updateBar(); + + Reflect.setField(parent, optionName, currentSelection); + if (selectCallback != null) selectCallback(currentSelection); + } +} \ No newline at end of file diff --git a/source/funkin/options/type/NumOption.hx b/source/funkin/options/type/NumOption.hx index 75aa2b5a..e570e197 100644 --- a/source/funkin/options/type/NumOption.hx +++ b/source/funkin/options/type/NumOption.hx @@ -42,9 +42,8 @@ class NumOption extends OptionType { this.changeVal = changeVal; this.optionName = optionName; - add(__text = new Alphabet(100, 20, text, "bold")); - add(__number = new Alphabet(__text.width + 120, 20, ': $currentSelection', "normal")); - + add(__text = new Alphabet(20, 20, "", "bold")); + add(__number = new Alphabet(0, 20, ': $currentSelection', "bold")); rawText = text; } @@ -56,10 +55,11 @@ class NumOption extends OptionType { function set_rawText(v:String) { rawText = v; __text.text = TU.exists(rawText) ? TU.translate(rawText) : rawText; + __number.x = __text.x + __text.width + 12; return v; } - public override function onChangeSelection(change:Float):Void + override function onChangeSelection(change:Float):Void { if(currentSelection <= min && change == -1 || currentSelection >= max && change == 1) return; currentSelection = FlxMath.roundDecimal(currentSelection + (change * changeVal), FlxMath.getDecimals(changeVal)); diff --git a/source/funkin/options/type/TextOption.hx b/source/funkin/options/type/TextOption.hx index 5026211f..2d2b5187 100644 --- a/source/funkin/options/type/TextOption.hx +++ b/source/funkin/options/type/TextOption.hx @@ -23,7 +23,7 @@ class TextOption extends OptionType { public function new(text:String, desc:String, ?suffix:String = "", ?selectCallback:Void->Void = null) { super(desc); this.selectCallback = selectCallback; - add(__text = new Alphabet(100, 20, text, "bold")); + add(__text = new Alphabet(100, 20, "", "bold")); this.suffix = suffix; rawText = text; }