From 82edabfc4f29ac4843104c30a9881f6a39ed786e Mon Sep 17 00:00:00 2001 From: Yoshman29 <81191621+YoshiCrafter29@users.noreply.github.com> Date: Thu, 19 Jan 2023 18:36:46 +0100 Subject: [PATCH] opponent & coop modes --- assets/data/freeplaySonglist.json | 93 ++++++++++++++----- buildnumber.txt | 2 +- source/funkin/game/Note.hx | 18 ++-- source/funkin/game/PlayState.hx | 66 +++++++++---- source/funkin/game/StrumLine.hx | 9 +- source/funkin/menus/FreeplayState.hx | 63 +++++++++++-- source/funkin/menus/PauseSubState.hx | 26 ++---- source/funkin/options/Options.hx | 8 +- source/funkin/options/PlayerSettings.hx | 87 +++-------------- .../options/keybinds/KeybindsOptions.hx | 2 +- source/funkin/options/type/OptionType.hx | 2 +- .../scripting/events/NoteCreationEvent.hx | 2 +- source/funkin/system/MusicBeatState.hx | 16 +++- source/funkin/system/MusicBeatSubstate.hx | 18 +++- source/funkin/utils/CoolUtil.hx | 4 +- 15 files changed, 262 insertions(+), 154 deletions(-) diff --git a/assets/data/freeplaySonglist.json b/assets/data/freeplaySonglist.json index ca58af47..fda09509 100644 --- a/assets/data/freeplaySonglist.json +++ b/assets/data/freeplaySonglist.json @@ -3,131 +3,178 @@ "songs": [ { "name": "test", - "icon": "bf" + "icon": "bf", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Tutorial", "icon": "gf", - "color": "#9271FD" + "color": "#9271FD", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Bopeebo", "icon": "dad", - "color": "#9271FD" + "color": "#9271FD", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Fresh", "icon": "dad", - "color": "#9271FD" + "color": "#9271FD", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Dadbattle", "icon": "dad", - "color": "#9271FD" + "color": "#9271FD", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Spookeez", "icon": "spooky", - "color": "#223344" + "color": "#223344", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "South", "icon": "spooky", - "color": "#223344" + "color": "#223344", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Monster", "icon": "monster", - "color": "#223344" + "color": "#223344", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Pico", "icon": "pico", - "color": "#941653" + "color": "#941653", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Philly Nice", "icon": "pico", - "color": "#941653" + "color": "#941653", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Blammed", "icon": "pico", - "color": "#941653" + "color": "#941653", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Satin Panties", "icon": "mom", - "color": "#FC96D7" + "color": "#FC96D7", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "High", "icon": "mom", - "color": "#FC96D7" + "color": "#FC96D7", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "MILF", "icon": "mom", - "color": "#FC96D7" + "color": "#FC96D7", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Cocoa", "icon": "parents-christmas", - "color": "#A0D1FF" + "color": "#A0D1FF", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Eggnog", "icon": "parents-christmas", - "color": "#A0D1FF" + "color": "#A0D1FF", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Winter Horrorland", "icon": "monster", - "color": "#A0D1FF" + "color": "#A0D1FF", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Senpai", "icon": "senpai", - "color": "#FF78BF" + "color": "#FF78BF", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Roses", "icon": "senpai", - "color": "#FF78BF" + "color": "#FF78BF", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Thorns", "icon": "spirit", - "color": "#FF78BF" + "color": "#FF78BF", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Ugh", "icon": "tankman", - "color": "#F6B604" + "color": "#F6B604", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Guns", "icon": "tankman", - "color": "#F6B604" + "color": "#F6B604", + "coopAllowed": true, + "opponentModeAllowed": true }, { "name": "Stress", "icon": "tankman", - "color": "#F6B604" + "color": "#F6B604", + "difficulties": ["EASY", "NORMAL", "HARD"], + "coopAllowed": true, + "opponentModeAllowed": true } ] } \ No newline at end of file diff --git a/buildnumber.txt b/buildnumber.txt index 8a162a54..9aba31b8 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -2079 \ No newline at end of file +2090 \ No newline at end of file diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 39810168..71c5270a 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -19,17 +19,17 @@ class Note extends FlxSprite public var strumTime:Float = 0; public var mustPress(get, never):Bool; - public var player(get, never):StrumLine; - private function get_player() { + public var strumLine(get, never):StrumLine; + private function get_strumLine() { if (PlayState.instance != null) - return PlayState.instance.players[playerID]; + return PlayState.instance.players[strumLineID]; return null; } private function get_mustPress():Bool { if (PlayState.instance != null) - return PlayState.instance.players[playerID] != null && !PlayState.instance.players[playerID].cpu; - return playerID == 1; + return PlayState.instance.players[strumLineID] != null && !PlayState.instance.players[strumLineID].cpu; + return strumLineID == 1; } public var noteData:Int = 0; public var canBeHit:Bool = false; @@ -72,7 +72,7 @@ class Note extends FlxSprite public var flipSustain:Bool = true; public var noteTypeID:Int = 0; - public var playerID:Int = 0; + public var strumLineID:Int = 0; // TO APPLY THOSE ON A SINGLE NOTE public var scrollSpeed:Null = null; @@ -93,7 +93,7 @@ class Note extends FlxSprite public var animSuffix:String = ""; - public function new(strumTime:Float, noteData:Int, noteType:Int = 0, playerID:Int = 1, ?prevNote:Note, ?sustainNote:Bool = false, animSuffix:String = "") + public function new(strumTime:Float, noteData:Int, noteType:Int = 0, strumLineID:Int = 1, ?prevNote:Note, ?sustainNote:Bool = false, animSuffix:String = "") { super(); @@ -101,7 +101,7 @@ class Note extends FlxSprite prevNote = this; this.prevNote = prevNote; - this.playerID = playerID; + this.strumLineID = strumLineID; this.noteTypeID = noteType; isSustainNote = sustainNote; @@ -113,7 +113,7 @@ class Note extends FlxSprite this.noteData = noteData; var customType = Paths.image('game/notes/${this.noteType}'); - var event = EventManager.get(NoteCreationEvent).recycle(this, strumID, this.noteType, noteTypeID, playerID, mustPress, Assets.exists(customType) ? 'game/notes/${this.noteType}' : 'game/NOTE_assets', 0.7, animSuffix); + var event = EventManager.get(NoteCreationEvent).recycle(this, strumID, this.noteType, noteTypeID, strumLineID, mustPress, Assets.exists(customType) ? 'game/notes/${this.noteType}' : 'game/NOTE_assets', 0.7, animSuffix); if (PlayState.instance != null) event = PlayState.instance.scripts.event("onNoteCreation", event); diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 6031e066..e03d3575 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -92,6 +92,14 @@ class PlayState extends MusicBeatState * Whenever the week is coming from the mods folder or not. */ public static var fromMods:Bool = false; + /** + * Whenever the song has been started with opponent mode on. + */ + public static var opponentMode:Bool = false; + /** + // * Whenever the song has been started with co-op mode on. + */ + public static var coopMode:Bool = false; /** * Script Pack of all the scripts being ran. @@ -123,7 +131,11 @@ class PlayState extends MusicBeatState /** * Whenever the player can die. */ - public var canDie:Bool = true; + public var canDie:Bool = !opponentMode && !coopMode; + /** + * Whenever the opponent can die. + */ + public var canDadDie:Bool = opponentMode && !coopMode; /** * Current scroll speed for all strums. * To set a scroll speed for a specific strum, use `strum.scrollSpeed`. @@ -195,6 +207,14 @@ class PlayState extends MusicBeatState * CPU strums. */ public var cpuStrums:StrumLine; + /** + * Shortcut to `playerStrums`. + */ + public var player(get, set):StrumLine; + /** + * Shortcut to `cpuStrums`. + */ + public var cpu(get, set):StrumLine; /** * Note splashes container @@ -589,8 +609,8 @@ class PlayState extends MusicBeatState strumLineNotes = new FlxTypedGroup(); add(strumLineNotes); - players.push(cpuStrums = new StrumLine([dad], 0.25, true, controls)); - players.push(playerStrums = new StrumLine([boyfriend], 0.75, false, controls)); + players.push(cpuStrums = new StrumLine([dad], 0.25, !coopMode && !opponentMode, true, coopMode ? controlsP2 : controls)); + players.push(playerStrums = new StrumLine([boyfriend], 0.75, !coopMode && opponentMode, false, coopMode ? controlsP1 : controls)); splashHandler = new SplashHandler(); add(splashHandler); @@ -621,7 +641,10 @@ class PlayState extends MusicBeatState healthBar = new FlxBar(healthBarBG.x + 4, healthBarBG.y + 4, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), this, 'health', 0, maxHealth); healthBar.scrollFactor.set(); - healthBar.createFilledBar(0xFFFF0000, 0xFF66FF33); + if (opponentMode) + healthBar.createFilledBar(0xFF66FF33, 0xFFFF0000); // switch the colors + else + healthBar.createFilledBar(0xFFFF0000, 0xFF66FF33); add(healthBar); health = maxHealth / 2; @@ -1130,8 +1153,7 @@ class PlayState extends MusicBeatState iconP1.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0)) - iconOffset); iconP2.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0))) - (iconP2.width - iconOffset); - if (health > maxHealth) - health = maxHealth; + health = FlxMath.bound(health, 0, maxHealth); iconP1.health = healthBar.percent / 100; iconP2.health = 1 - (healthBar.percent / 100); @@ -1199,6 +1221,8 @@ class PlayState extends MusicBeatState if (health <= 0 && canDie) gameOver(); + if (health >= maxHealth && canDadDie) + gameOver(); if (generatedMusic) { __updateNote_event = EventManager.get(NoteUpdateEvent); @@ -1220,7 +1244,7 @@ class PlayState extends MusicBeatState var __updateNote_event:NoteUpdateEvent = null; function updateNote(daNote:Note) { - for(e in players[daNote.playerID].members) { + for(e in players[daNote.strumLineID].members) { if (e.ID == daNote.noteData % 4) { __updateNote_strum = e; break; //ing bad @@ -1237,7 +1261,7 @@ class PlayState extends MusicBeatState daNote.tooLate = true; } - if (event.__autoCPUHit && (daNote.player == null || daNote.player.cpu) && !daNote.wasGoodHit && daNote.strumTime < Conductor.songPosition) goodNoteHit(daNote); + if (event.__autoCPUHit && (daNote.strumLine == null || daNote.strumLine.cpu) && !daNote.wasGoodHit && daNote.strumTime < Conductor.songPosition) goodNoteHit(daNote); if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.stepLength) < Conductor.songPosition) { deleteNote(daNote); @@ -1377,7 +1401,7 @@ class PlayState extends MusicBeatState if (__pressed.contains(true)) { __funcsToExec.push(function(note:Note) { - if (note.playerID == id && __pressed[note.strumID] && note.isSustainNote && note.canBeHit && !note.wasGoodHit) { + if (note.strumLineID == id && __pressed[note.strumID] && note.isSustainNote && note.canBeHit && !note.wasGoodHit) { goodNoteHit(note); } }); @@ -1386,7 +1410,7 @@ class PlayState extends MusicBeatState var notePerStrum = [for(i in 0...4) null]; if (__justPressed.contains(true)) { __funcsToExec.push(function(note:Note) { - if (__justPressed[note.strumID] && !note.isSustainNote && note.playerID == id && !note.wasGoodHit && note.canBeHit) { + if (__justPressed[note.strumID] && !note.isSustainNote && note.strumLineID == id && !note.wasGoodHit && note.canBeHit) { if (notePerStrum[note.strumID] == null) notePerStrum[note.strumID] = note; else if (Math.abs(notePerStrum[note.strumID].strumTime - note.strumTime) <= 5) deleteNote(note); else if (note.strumTime < notePerStrum[note.strumID].strumTime) notePerStrum[note.strumID] = note; @@ -1411,11 +1435,11 @@ class PlayState extends MusicBeatState function noteMiss(note:Note):Void { - var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, [boyfriend], true, note.noteType, "", "", "", note.strumID, -10, 0, -0.04, "shit")); + var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, note.strumLine.characters, true, note.noteType, "", "", "", note.strumID, -10, 0, -0.04, "shit")); if (event.cancelled) return; - health += event.healthGain; + if (event.note.strumLine != null) event.note.strumLine.addHealth(event.healthGain); if (gf != null && combo > 5 && gf.animOffsets.exists('sad')) { gf.playAnim('sad', true, MISS); @@ -1485,10 +1509,10 @@ class PlayState extends MusicBeatState } var event:NoteHitEvent; - if (note.player != null && !note.player.cpu) - event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, note.player.characters, true, note.noteType, "", "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating, !note.isSustainNote && daRating == "sick")); + if (note.strumLine != null && !note.strumLine.cpu) + event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, note.strumLine.characters, true, note.noteType, "", "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating, !note.isSustainNote && daRating == "sick")); else - event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, note.player.characters, false, note.noteType, "", "game/score/", "", note.strumID, 0, null, 0, daRating, false)); + event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, note.strumLine.characters, false, note.noteType, "", "game/score/", "", note.strumID, 0, null, 0, daRating, false)); scripts.event("onNoteHit", event); if (!event.cancelled) { @@ -1576,7 +1600,7 @@ class PlayState extends MusicBeatState ratingNum += 1; } - health += event.healthGain; + if (event.note.strumLine != null) event.note.strumLine.addHealth(event.healthGain); if (!event.animCancelled) for(char in event.characters) @@ -1637,6 +1661,16 @@ class PlayState extends MusicBeatState scripts.call("beatHit", [curBeat]); } + + private inline function get_player():StrumLine + return playerStrums; + private inline function set_player(s:StrumLine):StrumLine + return playerStrums = s; + + private inline function get_cpu():StrumLine + return cpuStrums; + private inline function set_cpu(s:StrumLine):StrumLine + return cpuStrums = s; } class ComboRating { diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx index 12b560b8..a70f2730 100644 --- a/source/funkin/game/StrumLine.hx +++ b/source/funkin/game/StrumLine.hx @@ -16,6 +16,10 @@ class StrumLine extends FlxTypedGroup { * Whenever this strumline is controlled by cpu or not. */ public var cpu(default, set):Bool = false; + /** + * Whenever this strumline is from the opponent side or the player side. + */ + public var opponentSide:Bool = false; /** * Controls assigned to this strumline. */ @@ -23,14 +27,17 @@ class StrumLine extends FlxTypedGroup { private var strumOffset:Float = 0.25; - public function new(characters:Array, strumOffset:Float = 0.25, cpu:Bool = false, ?controls:Controls) { + public function new(characters:Array, strumOffset:Float = 0.25, cpu:Bool = false, opponentSide:Bool = true, ?controls:Controls) { super(); this.characters = characters; this.strumOffset = strumOffset; this.cpu = cpu; + this.opponentSide = opponentSide; this.controls = controls; } + public inline function addHealth(health:Float) + PlayState.instance.health += health * (opponentSide ? -1 : 1); public function generateStrums(amount:Int = 4) { for (i in 0...4) diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx index 87cfc923..471c4666 100644 --- a/source/funkin/menus/FreeplayState.hx +++ b/source/funkin/menus/FreeplayState.hx @@ -36,9 +36,11 @@ class FreeplayState extends MusicBeatState var selector:FlxText; var curSelected:Int = 0; var curDifficulty:Int = 1; + var curCoopMode:Int = 0; var scoreText:FlxText; var diffText:FlxText; + var coopText:FlxText; var lerpScore:Int = 0; var intendedScore:Int = 0; @@ -99,10 +101,15 @@ class FreeplayState extends MusicBeatState diffText.font = scoreText.font; add(diffText); + coopText = new FlxText(diffText.x, diffText.y + diffText.height + 2, 0, "[TAB] Solo", 24); + coopText.font = scoreText.font; + add(coopText); + add(scoreText); changeSelection(0, true); - changeDiff(); + changeDiff(0, true); + changeCoopMode(0, true); super.create(); } @@ -130,15 +137,16 @@ class FreeplayState extends MusicBeatState changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0)); changeDiff((controls.LEFT_P ? -1 : 0) + (controls.RIGHT_P ? 1 : 0)); + changeCoopMode((FlxG.keys.justPressed.TAB ? 1 : 0)); // putting it before so that its actually smooth updateOptionsAlpha(); scoreText.text = "PERSONAL BEST:" + lerpScore; - scoreBG.scale.set(Math.max(diffText.width, scoreText.width) + 8, 66); + scoreBG.scale.set(Math.max(diffText.width, scoreText.width) + 8, (coopText.visible ? coopText.y + coopText.height : 66)); scoreBG.updateHitbox(); scoreBG.x = FlxG.width - scoreBG.width; - scoreText.x = scoreBG.x + 4; + scoreText.x = coopText.x = scoreBG.x + 4; diffText.x = Std.int(scoreBG.x + ((scoreBG.width - diffText.width) / 2)); bg.color = CoolUtil.lerpColor(bg.color, songs[curSelected].color, 0.0625); @@ -164,7 +172,17 @@ class FreeplayState extends MusicBeatState if (controls.ACCEPT && !dontPlaySongThisFrame) { - CoolUtil.loadSong(songs[curSelected].songName, songs[curSelected].difficulties[curDifficulty]); + var opponentMode:Bool = false; + var coopMode:Bool = false; + if (songs[curSelected].coopAllowed && songs[curSelected].opponentModeAllowed) { + opponentMode = curCoopMode % 2 == 1; + coopMode = curCoopMode >= 2; + } else if (songs[curSelected].coopAllowed) { + coopMode = curCoopMode == 1; + } else if (songs[curSelected].opponentModeAllowed) { + opponentMode = curCoopMode == 1; + } + CoolUtil.loadSong(songs[curSelected].songName, songs[curSelected].difficulties[curDifficulty], opponentMode, coopMode); FlxG.switchState(new PlayState()); } } @@ -187,6 +205,27 @@ class FreeplayState extends MusicBeatState diffText.text = curSong.difficulties[curDifficulty]; } + private var coopLabels:Array = [ + "[TAB] Solo", + "[TAB] Opponent Mode", + "[TAB] Co-Op Mode", + "[TAB] Co-Op Mode (Switched)" + ]; + function changeCoopMode(change:Int = 0, force:Bool = false) { + if (change == 0 && !force) return; + if (!songs[curSelected].coopAllowed && !songs[curSelected].opponentModeAllowed) return; + + var bothEnabled = songs[curSelected].coopAllowed && songs[curSelected].opponentModeAllowed; + + curCoopMode = FlxMath.wrap(curCoopMode + change, 0, bothEnabled ? 3 : 1); + + if (bothEnabled) { + coopText.text = coopLabels[curCoopMode]; + } else { + coopText.text = coopLabels[curCoopMode * (songs[curSelected].coopAllowed ? 2 : 1)]; + } + } + function changeSelection(change:Int = 0, force:Bool = false) { if (change == 0 && !force) return; @@ -200,6 +239,8 @@ class FreeplayState extends MusicBeatState autoplayElapsed = 0; songInstPlaying = false; #end + + coopText.visible = songs[curSelected].coopAllowed || songs[curSelected].opponentModeAllowed; } function updateOptionsAlpha() { @@ -238,10 +279,16 @@ class FreeplaySonglist { if (e.name == null) continue; if (e.icon == null) e.icon = "bf"; if (e.color == null) e.color = FreeplayState.defaultColor; + if (e.coopAllowed == null) e.coopAllowed = false; + if (e.opponentModeAllowed == null) e.opponentModeAllowed = false; - this.songs.push(new SongMetadata(e.name, + var meta = new SongMetadata(e.name, e.icon.getDefault("bf"), - CoolUtil.getColorFromDynamic(e.color).getDefault(FreeplayState.defaultColor), e.difficulties, source)); + CoolUtil.getColorFromDynamic(e.color).getDefault(FreeplayState.defaultColor), e.difficulties, source); + + meta.coopAllowed = e.coopAllowed; + meta.opponentModeAllowed = e.opponentModeAllowed; + this.songs.push(meta); } } } @@ -305,6 +352,8 @@ typedef FreeplaySong = { public var ?icon:String; public var ?color:Dynamic; public var ?difficulties:Array; + public var ?coopAllowed:Bool; + public var ?opponentModeAllowed:Bool; } class SongMetadata @@ -313,6 +362,8 @@ class SongMetadata public var color:FlxColor = FreeplayState.defaultColor; public var songCharacter:String = ""; public var difficulties:Array = ["EASY", "NORMAL", "HARD"]; + public var coopAllowed:Bool = false; + public var opponentModeAllowed:Bool = false; public function new(song:String, songCharacter:String, color:FlxColor, ?difficulties:Array, fromSource:Bool = false) { diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx index 7e7ba820..59ab994a 100644 --- a/source/funkin/menus/PauseSubState.hx +++ b/source/funkin/menus/PauseSubState.hx @@ -66,26 +66,20 @@ class PauseSubState extends MusicBeatSubstate add(bg); var levelInfo:FlxText = new FlxText(20, 15, 0, PlayState.SONG.song, 32); - levelInfo.scrollFactor.set(); - levelInfo.setFormat(Paths.font("vcr.ttf"), 32); - levelInfo.updateHitbox(); - add(levelInfo); - var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, PlayState.difficulty.toUpperCase(), 32); - levelDifficulty.scrollFactor.set(); - levelDifficulty.setFormat(Paths.font('vcr.ttf'), 32); - levelDifficulty.updateHitbox(); - add(levelDifficulty); + var multiplayerText:FlxText = new FlxText(20, 15 + 32 + 32, 0, PlayState.opponentMode ? 'OPPONENT MODE' : (PlayState.coopMode ? 'CO-OP MODE' : ''), 32); - levelDifficulty.alpha = 0; - levelInfo.alpha = 0; - - levelInfo.x = FlxG.width - (levelInfo.width + 20); - levelDifficulty.x = FlxG.width - (levelDifficulty.width + 20); + for(k=>label in [levelInfo, levelDifficulty, multiplayerText]) { + label.scrollFactor.set(); + label.setFormat(Paths.font('vcr.ttf'), 32); + label.updateHitbox(); + label.alpha = 0; + label.x = FlxG.width - (label.width + 20); + FlxTween.tween(label, {alpha: 1, y: label.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.3 * (k+1)}); + add(label); + } FlxTween.tween(bg, {alpha: 0.6}, 0.4, {ease: FlxEase.quartInOut}); - FlxTween.tween(levelInfo, {alpha: 1, y: 20}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.3}); - FlxTween.tween(levelDifficulty, {alpha: 1, y: levelDifficulty.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.5}); grpMenuShit = new FlxTypedGroup(); add(grpMenuShit); diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx index 3932fdf3..60b18f8d 100644 --- a/source/funkin/options/Options.hx +++ b/source/funkin/options/Options.hx @@ -169,11 +169,17 @@ class Options } public static function applySettings() { - PlayerSettings.player1.setKeyboardScheme(Solo); + applyKeybinds(); FlxG.game.stage.quality = (FlxG.forceNoAntialiasing = !antialiasing) ? LOW : BEST; FlxG.autoPause = autoPause; } + public static function applyKeybinds() { + PlayerSettings.solo.setKeyboardScheme(Solo); + PlayerSettings.player1.setKeyboardScheme(Duo(true)); + PlayerSettings.player2.setKeyboardScheme(Duo(false)); + } + public static function save() { volume = FlxG.sound.volume; for(field in Type.getClassFields(Options)) { diff --git a/source/funkin/options/PlayerSettings.hx b/source/funkin/options/PlayerSettings.hx index d559ccd4..22e7ef6e 100644 --- a/source/funkin/options/PlayerSettings.hx +++ b/source/funkin/options/PlayerSettings.hx @@ -7,10 +7,11 @@ import flixel.util.FlxSignal; // import ui.DeviceManager; // import props.Player; -class PlayerSettings +class PlayerSettings { static public var numPlayers(default, null) = 0; static public var numAvatars(default, null) = 0; + static public var solo(default, null):PlayerSettings; static public var player1(default, null):PlayerSettings; static public var player2(default, null):PlayerSettings; @@ -43,83 +44,21 @@ class PlayerSettings { controls.setKeyboardScheme(scheme); } - - /* - static public function addAvatar(avatar:Player):PlayerSettings - { - var settings:PlayerSettings; - - if (player1 == null) - { - player1 = new PlayerSettings(0, Solo); - ++numPlayers; - } - - if (player1.avatar == null) - settings = player1; - else - { - if (player2 == null) - { - if (player1.controls.keyboardScheme.match(Duo(true))) - player2 = new PlayerSettings(1, Duo(false)); - else - player2 = new PlayerSettings(1, None); - ++numPlayers; - } - - if (player2.avatar == null) - settings = player2; - else - throw throw 'Invalid number of players: ${numPlayers + 1}'; - } - ++numAvatars; - settings.avatar = avatar; - avatar.settings = settings; - - splitCameras(); - - onAvatarAdd.dispatch(settings); - - return settings; - } - - static public function removeAvatar(avatar:Player):Void - { - var settings:PlayerSettings; - - if (player1 != null && player1.avatar == avatar) - settings = player1; - else if (player2 != null && player2.avatar == avatar) - { - settings = player2; - if (player1.controls.keyboardScheme.match(Duo(_))) - player1.setKeyboardScheme(Solo); - } - else - throw "Cannot remove avatar that is not for a player"; - - settings.avatar = null; - while (settings.controls.gamepadsAdded.length > 0) - { - final id = settings.controls.gamepadsAdded.shift(); - settings.controls.removeGamepad(id); - DeviceManager.releaseGamepad(FlxG.gamepads.getByID(id)); - } - - --numAvatars; - - splitCameras(); - - onAvatarRemove.dispatch(avatar.settings); - } - - */ + static public function init():Void { + if (solo == null) + { + solo = new PlayerSettings(0, Solo); + } if (player1 == null) { - player1 = new PlayerSettings(0, Solo); + player1 = new PlayerSettings(0, Duo(true)); + ++numPlayers; + } + if (player2 == null) + { + player2 = new PlayerSettings(0, Duo(false)); ++numPlayers; } diff --git a/source/funkin/options/keybinds/KeybindsOptions.hx b/source/funkin/options/keybinds/KeybindsOptions.hx index ed4fbff1..4fd06d7b 100644 --- a/source/funkin/options/keybinds/KeybindsOptions.hx +++ b/source/funkin/options/keybinds/KeybindsOptions.hx @@ -205,7 +205,7 @@ class KeybindsOptions extends MusicBeatSubstate { close(); else FlxG.switchState(new OptionsMenu()); - controls.setKeyboardScheme(Solo); + Options.applyKeybinds(); Options.save(); return; } diff --git a/source/funkin/options/type/OptionType.hx b/source/funkin/options/type/OptionType.hx index 078e21cd..3c24fd2c 100644 --- a/source/funkin/options/type/OptionType.hx +++ b/source/funkin/options/type/OptionType.hx @@ -14,7 +14,7 @@ class OptionType extends FlxSpriteGroup { this.desc = desc; } - private function get_controls() {return PlayerSettings.player1.controls;} + private function get_controls() {return PlayerSettings.solo.controls;} public function onSelect() { diff --git a/source/funkin/scripting/events/NoteCreationEvent.hx b/source/funkin/scripting/events/NoteCreationEvent.hx index d0298c62..b04531b4 100644 --- a/source/funkin/scripting/events/NoteCreationEvent.hx +++ b/source/funkin/scripting/events/NoteCreationEvent.hx @@ -26,7 +26,7 @@ class NoteCreationEvent extends CancellableEvent { /** * ID of the player. */ - public var playerID:Int; + public var strumLineID:Int; /** * Whenever the note will need to be hit by the player diff --git a/source/funkin/system/MusicBeatState.hx b/source/funkin/system/MusicBeatState.hx index 1c53e6ca..e6fa8733 100644 --- a/source/funkin/system/MusicBeatState.hx +++ b/source/funkin/system/MusicBeatState.hx @@ -58,10 +58,20 @@ class MusicBeatState extends FlxUIState implements IBeatReceiver return Conductor.songPosition; /** - * Game Controls. + * Game Controls. (All players / Solo) */ public var controls(get, never):Controls; + /** + * Game Controls (Player 1 only) + */ + public var controlsP1(get, never):Controls; + + /** + * Game Controls (Player 2 only) + */ + public var controlsP2(get, never):Controls; + /** * Current injected script attached to the state. To add one, create a file at path "data/states/stateName" (ex: data/states/FreeplayState) */ @@ -72,7 +82,11 @@ class MusicBeatState extends FlxUIState implements IBeatReceiver public var scriptName:String = null; inline function get_controls():Controls + return PlayerSettings.solo.controls; + inline function get_controlsP1():Controls return PlayerSettings.player1.controls; + inline function get_controlsP2():Controls + return PlayerSettings.player2.controls; public function new(scriptsAllowed:Bool = true, ?scriptName:String) { super(); diff --git a/source/funkin/system/MusicBeatSubstate.hx b/source/funkin/system/MusicBeatSubstate.hx index 714bb0d0..30450d90 100644 --- a/source/funkin/system/MusicBeatSubstate.hx +++ b/source/funkin/system/MusicBeatSubstate.hx @@ -60,13 +60,27 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver public var scriptName:String = null; + /** + * Game Controls. (All players / Solo) + */ + public var controls(get, never):Controls; + /** - * Game Controls. + * Game Controls (Player 1 only) */ - public var controls(get, never):Controls; + public var controlsP1(get, never):Controls; + + /** + * Game Controls (Player 2 only) + */ + public var controlsP2(get, never):Controls; inline function get_controls():Controls + return PlayerSettings.solo.controls; + inline function get_controlsP1():Controls return PlayerSettings.player1.controls; + inline function get_controlsP2():Controls + return PlayerSettings.player2.controls; public function new(scriptsAllowed:Bool = true, ?scriptName:String) { diff --git a/source/funkin/utils/CoolUtil.hx b/source/funkin/utils/CoolUtil.hx index c2d6f8af..e4704322 100644 --- a/source/funkin/utils/CoolUtil.hx +++ b/source/funkin/utils/CoolUtil.hx @@ -269,9 +269,11 @@ class CoolUtil PlayState.campaignScore = 0; __loadSong(PlayState.storyPlaylist[0], difficulty); } - public static function loadSong(name:String, difficulty:String = "normal") { + public static function loadSong(name:String, difficulty:String = "normal", opponentMode:Bool = false, coopMode:Bool = false) { PlayState.campaignScore = 0; PlayState.isStoryMode = false; + PlayState.opponentMode = opponentMode; + PlayState.coopMode = coopMode; __loadSong(name, difficulty); } public static function __loadSong(name:String, difficulty:String) {