new chart system implementation progress
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
2286
|
||||
2313
|
||||
@@ -6,17 +6,23 @@ import openfl.utils.Assets;
|
||||
|
||||
class Chart {
|
||||
public static function parse(songName:String, difficulty:String = "normal"):ChartData {
|
||||
var chartPath = Paths.chart(songName, difficulty);
|
||||
var base:ChartData = {
|
||||
strumLines: [],
|
||||
noteTypes: [],
|
||||
events: [],
|
||||
meta: {
|
||||
name: songName,
|
||||
bpm: 0
|
||||
bpm: 0,
|
||||
beatsPerMesure: 4,
|
||||
stepsPerBeat: 4
|
||||
},
|
||||
scrollSpeed: 2,
|
||||
stage: "stage",
|
||||
codenameChart: true
|
||||
codenameChart: true,
|
||||
fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS)
|
||||
};
|
||||
var chartPath = Paths.chart(songName, difficulty);
|
||||
|
||||
if (!Assets.exists(chartPath)) {
|
||||
Logs.trace('Chart for song ${songName} ($difficulty) at "$chartPath" was not found.', ERROR, RED);
|
||||
return base;
|
||||
@@ -39,6 +45,7 @@ class Chart {
|
||||
data = field;
|
||||
}
|
||||
|
||||
base.scrollSpeed = data.speed;
|
||||
base.stage = data.stage;
|
||||
base.meta.name = data.song;
|
||||
base.meta.bpm = data.bpm;
|
||||
@@ -46,13 +53,25 @@ class Chart {
|
||||
base.strumLines.push({
|
||||
characters: [data.player2],
|
||||
opponent: true,
|
||||
position: "dad",
|
||||
notes: []
|
||||
});
|
||||
base.strumLines.push({
|
||||
characters: [data.player1],
|
||||
opponent: false,
|
||||
position: "boyfriend",
|
||||
notes: []
|
||||
});
|
||||
if (data.gf != "none") {
|
||||
base.strumLines.push({
|
||||
characters: [data.gf != null ? data.gf : "gf"],
|
||||
opponent: true,
|
||||
position: "girlfriend",
|
||||
notes: [],
|
||||
visible: false,
|
||||
strumLinePos: 0.5
|
||||
});
|
||||
}
|
||||
|
||||
var camFocusedBF:Bool = false;
|
||||
var beatsPerMesure:Float = data.beatsPerMesure.getDefault(4);
|
||||
@@ -61,10 +80,12 @@ class Chart {
|
||||
var curCrochet:Float = ((60 / curBPM) * 1000);
|
||||
|
||||
if (data.notes != null) for(section in data.notes) {
|
||||
if (section == null) continue; // Yoshi Engine charts crash fix
|
||||
if (section == null) {
|
||||
curTime += curCrochet * beatsPerMesure;
|
||||
continue; // Yoshi Engine charts crash fix
|
||||
}
|
||||
|
||||
if (camFocusedBF != (camFocusedBF = section.mustHitSection)) {
|
||||
// TODO: auto-add event for cam movement
|
||||
base.events.push({
|
||||
time: curTime,
|
||||
type: CAM_MOVEMENT,
|
||||
@@ -73,10 +94,22 @@ class Chart {
|
||||
}
|
||||
|
||||
if (section.sectionNotes != null) for(note in section.sectionNotes) {
|
||||
if (note[1] < 0) continue;
|
||||
|
||||
var daStrumTime:Float = note[0];
|
||||
var daNoteData:Int = Std.int(note[1] % 8);
|
||||
var daNoteType:Int = Std.int(note[1] / 8);
|
||||
var gottaHitNote:Bool = daNoteData >= 4 ? !section.mustHitSection : section.mustHitSection;
|
||||
|
||||
if (note.length > 2) {
|
||||
if (note[3] is Int)
|
||||
daNoteType = addNoteType(base, data.noteTypes[Std.int(note[3])-1]);
|
||||
else if (note[3] is String)
|
||||
daNoteType = addNoteType(base, note[3]);
|
||||
} else {
|
||||
daNoteType = addNoteType(base, data.noteTypes[daNoteType-1]);
|
||||
}
|
||||
|
||||
|
||||
base.strumLines[gottaHitNote ? 1 : 0].notes.push({
|
||||
time: daStrumTime,
|
||||
@@ -88,7 +121,7 @@ class Chart {
|
||||
|
||||
if (section.changeBPM && section.bpm != curBPM) {
|
||||
// TODO: BPM CHANGE EVENT
|
||||
curCrochet = ((60 / section.bpm) * 1000);
|
||||
curCrochet = ((60 / (curBPM = section.bpm)) * 1000);
|
||||
}
|
||||
|
||||
curTime += curCrochet * beatsPerMesure;
|
||||
@@ -96,6 +129,19 @@ class Chart {
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
private static function addNoteType(chart:ChartData, noteTypeName:String):Int {
|
||||
switch(noteTypeName.trim()) {
|
||||
case "Default Note" | null | "":
|
||||
return 0;
|
||||
default:
|
||||
var index = chart.noteTypes.indexOf(noteTypeName);
|
||||
if (index > -1)
|
||||
return index+1;
|
||||
chart.noteTypes.push(noteTypeName);
|
||||
return chart.noteTypes.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef ChartData = {
|
||||
@@ -104,11 +150,17 @@ typedef ChartData = {
|
||||
public var meta:ChartMetaData;
|
||||
public var codenameChart:Bool;
|
||||
public var stage:String;
|
||||
public var scrollSpeed:Float;
|
||||
public var fromMods:Bool;
|
||||
public var noteTypes:Array<String>;
|
||||
}
|
||||
|
||||
typedef ChartMetaData = {
|
||||
public var name:String;
|
||||
public var bpm:Float;
|
||||
public var ?beatsPerMesure:Float;
|
||||
public var ?stepsPerBeat:Float;
|
||||
public var ?needsVoices:Bool;
|
||||
public var ?icon:String;
|
||||
public var ?color:Dynamic;
|
||||
public var ?difficulties:Array<String>;
|
||||
@@ -120,7 +172,9 @@ typedef ChartStrumLine = {
|
||||
var characters:Array<String>;
|
||||
var opponent:Bool;
|
||||
var notes:Array<ChartNote>;
|
||||
var position:String;
|
||||
var ?strumLinePos:Float; // 0.25 = default opponent pos, 0.75 = default boyfriend pos
|
||||
var ?visible:Null<Bool>;
|
||||
}
|
||||
|
||||
typedef ChartNote = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,7 @@ class GameOverSubstate extends MusicBeatSubstate
|
||||
lossSFX = FlxG.sound.play(Paths.sound(lossSFXName));
|
||||
Conductor.changeBPM(100);
|
||||
|
||||
DiscordUtil.changePresence('Game Over', PlayState.SONG.song + " (" + PlayState.difficulty + ")");
|
||||
DiscordUtil.changePresence('Game Over', PlayState.SONG.meta.name + " (" + PlayState.difficulty + ")");
|
||||
}
|
||||
|
||||
override function update(elapsed:Float)
|
||||
|
||||
+22
-20
@@ -1,5 +1,6 @@
|
||||
package funkin.game;
|
||||
|
||||
import funkin.chart.Chart.ChartNote;
|
||||
import openfl.utils.Assets;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxCamera;
|
||||
@@ -19,17 +20,21 @@ class Note extends FlxSprite
|
||||
public var strumTime:Float = 0;
|
||||
|
||||
public var mustPress(get, never):Bool;
|
||||
public var strumLine(get, never):StrumLine;
|
||||
private function get_strumLine() {
|
||||
if (PlayState.instance != null)
|
||||
return PlayState.instance.players[strumLineID];
|
||||
return null;
|
||||
public var strumLine(default, set):StrumLine;
|
||||
private function set_strumLine(strLine:StrumLine) {
|
||||
if (this.strumLine != null) {
|
||||
if (this.strumLine.notes != null)
|
||||
this.strumLine.notes.remove(this, true);
|
||||
strLine.notes.add(this);
|
||||
strLine.notes.sortNotes();
|
||||
}
|
||||
return strumLine = strLine;
|
||||
}
|
||||
|
||||
private function get_mustPress():Bool {
|
||||
if (PlayState.instance != null)
|
||||
return PlayState.instance.players[strumLineID] != null && !PlayState.instance.players[strumLineID].cpu;
|
||||
return strumLineID == 1;
|
||||
// if (PlayState.instance != null)
|
||||
// return PlayState.instance.players[strumLineID] != null && !PlayState.instance.players[strumLineID].cpu;
|
||||
return false;
|
||||
}
|
||||
public var noteData:Int = 0;
|
||||
public var canBeHit:Bool = false;
|
||||
@@ -72,7 +77,6 @@ class Note extends FlxSprite
|
||||
public var flipSustain:Bool = true;
|
||||
|
||||
public var noteTypeID:Int = 0;
|
||||
public var strumLineID:Int = 0;
|
||||
|
||||
// TO APPLY THOSE ON A SINGLE NOTE
|
||||
public var scrollSpeed:Null<Float> = null;
|
||||
@@ -93,27 +97,25 @@ class Note extends FlxSprite
|
||||
|
||||
public var animSuffix:String = "";
|
||||
|
||||
public function new(strumTime:Float, noteData:Int, noteType:Int = 0, strumLineID:Int = 1, ?prevNote:Note, ?sustainNote:Bool = false, animSuffix:String = "")
|
||||
public function new(strumLine:StrumLine, noteData:ChartNote, isSustainNote:Bool)
|
||||
{
|
||||
super();
|
||||
|
||||
if (prevNote == null)
|
||||
prevNote = this;
|
||||
|
||||
this.prevNote = prevNote;
|
||||
this.strumLineID = strumLineID;
|
||||
this.noteTypeID = noteType;
|
||||
isSustainNote = sustainNote;
|
||||
// TODO: Sustain note
|
||||
this.prevNote = strumLine.notes.members.last();
|
||||
this.noteTypeID = noteData.type.getDefault(0);
|
||||
this.isSustainNote = false;
|
||||
this.strumLine = strumLine;
|
||||
|
||||
x += 50;
|
||||
// MAKE SURE ITS DEFINITELY OFF SCREEN?
|
||||
y -= 2000;
|
||||
this.strumTime = strumTime;
|
||||
this.strumTime = noteData.time.getDefault(0);
|
||||
|
||||
this.noteData = noteData;
|
||||
this.noteData = noteData.id.getDefault(0);
|
||||
|
||||
var customType = Paths.image('game/notes/${this.noteType}');
|
||||
var event = EventManager.get(NoteCreationEvent).recycle(this, strumID, this.noteType, noteTypeID, strumLineID, mustPress, Assets.exists(customType) ? 'game/notes/${this.noteType}' : 'game/notes/default', 0.7, animSuffix);
|
||||
var event = EventManager.get(NoteCreationEvent).recycle(this, strumID, this.noteType, noteTypeID, PlayState.instance.players.indexOf(strumLine), mustPress, Assets.exists(customType) ? 'game/notes/${this.noteType}' : 'game/notes/default', 0.7, animSuffix);
|
||||
|
||||
if (PlayState.instance != null)
|
||||
event = PlayState.instance.scripts.event("onNoteCreation", event);
|
||||
|
||||
+188
-326
@@ -1,7 +1,7 @@
|
||||
package funkin.game;
|
||||
|
||||
import funkin.chart.Chart;
|
||||
import funkin.game.SplashHandler;
|
||||
import funkin.editors.CharacterEditor;
|
||||
import funkin.scripting.DummyScript;
|
||||
import funkin.menus.StoryMenuState.WeekData;
|
||||
import funkin.ui.FunkinText;
|
||||
@@ -9,49 +9,26 @@ import flixel.group.FlxSpriteGroup;
|
||||
import funkin.options.Options;
|
||||
import funkin.scripting.Script;
|
||||
import flixel.util.FlxDestroyUtil;
|
||||
import funkin.system.Section.SwagSection;
|
||||
import funkin.system.Song.SwagSong;
|
||||
import funkin.scripting.ScriptPack;
|
||||
import funkin.shaders.WiggleEffect.WiggleEffectType;
|
||||
import flixel.FlxBasic;
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxGame;
|
||||
import flixel.FlxObject;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxState;
|
||||
import flixel.FlxSubState;
|
||||
import flixel.addons.display.FlxGridOverlay;
|
||||
import flixel.addons.effects.FlxTrail;
|
||||
import flixel.addons.effects.FlxTrailArea;
|
||||
import flixel.addons.effects.chainable.FlxEffectSprite;
|
||||
import flixel.addons.effects.chainable.FlxWaveEffect;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.graphics.atlas.FlxAtlas;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.system.FlxSound;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.ui.FlxBar;
|
||||
import flixel.util.FlxCollision;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxSort;
|
||||
import flixel.util.FlxStringUtil;
|
||||
import flixel.util.FlxTimer;
|
||||
import haxe.Json;
|
||||
import haxe.io.Path;
|
||||
import lime.utils.Assets;
|
||||
import openfl.display.BlendMode;
|
||||
import openfl.display.StageQuality;
|
||||
import openfl.filters.ShaderFilter;
|
||||
import funkin.system.Conductor;
|
||||
import funkin.system.Song;
|
||||
import funkin.editors.ChartingState;
|
||||
import funkin.cutscenes.*;
|
||||
|
||||
import funkin.menus.*;
|
||||
@@ -60,6 +37,7 @@ import funkin.scripting.events.*;
|
||||
using StringTools;
|
||||
|
||||
@:access(flixel.text.FlxText.FlxTextFormatRange)
|
||||
@:access(funkin.game.StrumLine)
|
||||
class PlayState extends MusicBeatState
|
||||
{
|
||||
/**
|
||||
@@ -68,9 +46,9 @@ class PlayState extends MusicBeatState
|
||||
public static var instance:PlayState = null;
|
||||
|
||||
/**
|
||||
* SONG METADATA
|
||||
* SONG DATA (Chart, Metadata)
|
||||
*/
|
||||
public static var SONG:SwagSong;
|
||||
public static var SONG:ChartData;
|
||||
/**
|
||||
* Whenever the song is being played in Story Mode.
|
||||
*/
|
||||
@@ -127,6 +105,10 @@ class PlayState extends MusicBeatState
|
||||
* Current Stage.
|
||||
*/
|
||||
public var stage:Stage;
|
||||
/**
|
||||
* Current Stage.
|
||||
*/
|
||||
public var validScore:Bool = true;
|
||||
/**
|
||||
* Whenever the player can die.
|
||||
*/
|
||||
@@ -164,20 +146,15 @@ class PlayState extends MusicBeatState
|
||||
/**
|
||||
* Dad character
|
||||
*/
|
||||
public var dad(default, set):Character;
|
||||
public var dad(get, set):Character;
|
||||
/**
|
||||
* Girlfriend character
|
||||
*/
|
||||
public var gf:Character;
|
||||
public var gf(get, set):Character;
|
||||
/**
|
||||
* Boyfriend character
|
||||
*/
|
||||
public var boyfriend(default, set):Character;
|
||||
|
||||
/**
|
||||
* Group of all of the notes. Using `forEach` on this group will only loop through the first notes.
|
||||
*/
|
||||
public var notes:NoteGroup;
|
||||
public var boyfriend(get, set):Character;
|
||||
|
||||
/**
|
||||
* Strum line position
|
||||
@@ -197,19 +174,14 @@ class PlayState extends MusicBeatState
|
||||
* Previous cam follow.
|
||||
*/
|
||||
private static var smoothTransitionData:PlayStateTransitionData;
|
||||
|
||||
/**
|
||||
* All of the strum line notes.
|
||||
*/
|
||||
public var strumLineNotes:FlxTypedGroup<Strum>;
|
||||
/**
|
||||
* Player strums.
|
||||
*/
|
||||
public var playerStrums:StrumLine;
|
||||
public var playerStrums(get, null):StrumLine;
|
||||
/**
|
||||
* CPU strums.
|
||||
*/
|
||||
public var cpuStrums:StrumLine;
|
||||
public var cpuStrums(get, null):StrumLine;
|
||||
/**
|
||||
* Shortcut to `playerStrums`.
|
||||
*/
|
||||
@@ -393,7 +365,14 @@ class PlayState extends MusicBeatState
|
||||
* Timer for the start countdown
|
||||
*/
|
||||
public var startTimer:FlxTimer;
|
||||
|
||||
/**
|
||||
* Remaining events
|
||||
*/
|
||||
public var events:Array<ChartEvent> = [];
|
||||
/**
|
||||
* Current camera target. -1 means no automatic camera targetting.
|
||||
*/
|
||||
public var curCameraTarget:Int = 0;
|
||||
/**
|
||||
* Length of the intro countdown.
|
||||
*/
|
||||
@@ -420,10 +399,6 @@ class PlayState extends MusicBeatState
|
||||
*/
|
||||
public var canPause:Bool = true;
|
||||
|
||||
/**
|
||||
* Current section (can be `null` when using YoshiCrafter Engine charts).
|
||||
*/
|
||||
public var curSection(get, null):SwagSection;
|
||||
/**
|
||||
* Format for the accuracy rating.
|
||||
*/
|
||||
@@ -524,17 +499,17 @@ class PlayState extends MusicBeatState
|
||||
persistentDraw = true;
|
||||
|
||||
if (SONG == null)
|
||||
SONG = Song.loadFromJson('tutorial', 'normal');
|
||||
SONG = Chart.parse('tutorial', 'normal');
|
||||
|
||||
scrollSpeed = SONG.speed;
|
||||
scrollSpeed = SONG.scrollSpeed;
|
||||
|
||||
Conductor.setupSong(SONG);
|
||||
|
||||
detailsText = isStoryMode ? ("Story Mode: " + storyWeek.name) : "Freeplay";
|
||||
|
||||
// Checks if cutscene files exists
|
||||
var cutscenePath = Paths.script('songs/${SONG.song.toLowerCase()}/cutscene');
|
||||
var endCutscenePath = Paths.script('songs/${SONG.song.toLowerCase()}/cutscene-end');
|
||||
var cutscenePath = Paths.script('songs/${SONG.meta.name.toLowerCase()}/cutscene');
|
||||
var endCutscenePath = Paths.script('songs/${SONG.meta.name.toLowerCase()}/cutscene-end');
|
||||
if (Assets.exists(cutscenePath)) cutscene = cutscenePath;
|
||||
if (Assets.exists(endCutscenePath)) endCutscene = endCutscenePath;
|
||||
|
||||
@@ -544,29 +519,7 @@ class PlayState extends MusicBeatState
|
||||
|
||||
// CHARACTER INITIALISATION
|
||||
#if REGION
|
||||
// Updating Discord Rich Presence.
|
||||
dad = new Character(100, 100, SONG.player2);
|
||||
|
||||
|
||||
if (dad != null && dad.isGF) {
|
||||
dad.setPosition(400, 130);
|
||||
gf = dad;
|
||||
dad.scrollFactor.set(0.95, 0.95);
|
||||
} else {
|
||||
var gfVersion = SONG.gf;
|
||||
if (gfVersion == null) gfVersion = "gf";
|
||||
if (gfVersion != "none") {
|
||||
gf = new Character(400, 130, gfVersion);
|
||||
gf.scrollFactor.set(0.95, 0.95);
|
||||
}
|
||||
}
|
||||
|
||||
var dadMidpoint = dad.getGraphicMidpoint();
|
||||
|
||||
|
||||
comboGroup = new FlxSpriteGroup(FlxG.width * 0.55, (FlxG.height * 0.5) - 60);
|
||||
|
||||
boyfriend = new Character(770, 100, SONG.player1, true);
|
||||
#end
|
||||
|
||||
// SCRIPTS & STAGE INITIALISATION
|
||||
@@ -574,16 +527,17 @@ class PlayState extends MusicBeatState
|
||||
if (SONG.stage == null || SONG.stage.trim() == "") SONG.stage = "stage";
|
||||
add(stage = new Stage(SONG.stage));
|
||||
|
||||
var camPos:FlxPoint = new FlxPoint(dadMidpoint.x, dadMidpoint.y);
|
||||
dadMidpoint.put();
|
||||
// var camPos:FlxPoint = new FlxPoint(dadMidpoint.x, dadMidpoint.y);
|
||||
// dadMidpoint.put();
|
||||
var camPos:FlxPoint = new FlxPoint(0, 0);
|
||||
|
||||
|
||||
switch(SONG.song) {
|
||||
switch(SONG.meta.name) {
|
||||
// case "":
|
||||
// ADD YOUR HARDCODED SCRIPTS HERE!
|
||||
default:
|
||||
for(content in [
|
||||
Paths.getFolderContent('songs/${SONG.song.toLowerCase()}/scripts', true, fromMods ? MODS : SOURCE),
|
||||
Paths.getFolderContent('songs/${SONG.meta.name.toLowerCase()}/scripts', true, fromMods ? MODS : SOURCE),
|
||||
Paths.getFolderContent('data/charts/', true, fromMods ? MODS : SOURCE)]) {
|
||||
for(file in content) {
|
||||
var ext = Path.extension(file).toLowerCase();
|
||||
@@ -593,18 +547,7 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
}
|
||||
|
||||
scripts.load();
|
||||
scripts.call("create");
|
||||
|
||||
if (gf != null) {
|
||||
gf.danceOnBeat = false;
|
||||
add(gf);
|
||||
}
|
||||
|
||||
add(comboGroup);
|
||||
|
||||
if (dad != null) add(dad);
|
||||
if (boyfriend != null) add(boyfriend);
|
||||
#end
|
||||
|
||||
// PRECACHING
|
||||
@@ -617,17 +560,48 @@ class PlayState extends MusicBeatState
|
||||
#if REGION
|
||||
strumLine = new FlxObject(0, 50, FlxG.width, 10);
|
||||
strumLine.scrollFactor.set();
|
||||
|
||||
strumLineNotes = new FlxTypedGroup<Strum>();
|
||||
add(strumLineNotes);
|
||||
|
||||
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));
|
||||
generateSong(SONG);
|
||||
|
||||
trace(SONG.noteTypes);
|
||||
for(noteType in SONG.noteTypes) {
|
||||
var scriptPath = Paths.script('data/notes/${noteType}');
|
||||
if (Assets.exists(scriptPath) && !scripts.contains(scriptPath)) {
|
||||
var script = Script.create(scriptPath);
|
||||
if (!(script is DummyScript)) {
|
||||
scripts.add(script);
|
||||
script.load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(strumLine in SONG.strumLines) {
|
||||
if (strumLine == null) continue;
|
||||
|
||||
var chars = [];
|
||||
var charPosName:String = strumLine.position == null ? (strumLine.opponent ? "dad" : "boyfriend") : strumLine.position;
|
||||
if (strumLine.characters != null) for(k=>charName in strumLine.characters) {
|
||||
var char = new Character(0, 0, charName, !strumLine.opponent);
|
||||
stage.applyCharStuff(char, charPosName);
|
||||
char.x += k * 50;
|
||||
chars.push(char);
|
||||
}
|
||||
|
||||
var strOffset:Float = strumLine.strumLinePos == null ? (strumLine.opponent ? 0.25 : 0.75) : strumLine.strumLinePos;
|
||||
var strLine = new StrumLine(chars, strOffset, !coopMode && (strumLine.opponent != opponentMode), strumLine.opponent, coopMode ? (strumLine.opponent ? controlsP2 : controlsP1) : controls);
|
||||
strLine.cameras = [camHUD];
|
||||
players.push(strLine);
|
||||
if (strumLine.visible != false)
|
||||
add(strLine);
|
||||
|
||||
strLine.generate(strumLine);
|
||||
}
|
||||
|
||||
splashHandler = new SplashHandler();
|
||||
add(splashHandler);
|
||||
|
||||
generateSong(SONG);
|
||||
scripts.load();
|
||||
scripts.call("create");
|
||||
#end
|
||||
|
||||
// CAMERA & HUD INITIALISATION
|
||||
@@ -686,7 +660,7 @@ class PlayState extends MusicBeatState
|
||||
missesTxt.alignment = CENTER;
|
||||
accuracyTxt.alignment = LEFT;
|
||||
|
||||
for(e in [strumLineNotes, notes, healthBar, healthBarBG, iconP1, iconP2, scoreTxt, missesTxt, accuracyTxt])
|
||||
for(e in [healthBar, healthBarBG, iconP1, iconP2, scoreTxt, missesTxt, accuracyTxt])
|
||||
e.cameras = [camHUD];
|
||||
#end
|
||||
|
||||
@@ -709,7 +683,7 @@ class PlayState extends MusicBeatState
|
||||
* This function is dynamic, which means you can do `updateDiscordPresence = function() {}` in scripts.
|
||||
*/
|
||||
public dynamic function updateDiscordPresence()
|
||||
DiscordUtil.changeSongPresence(detailsText, (paused ? "Paused - " : "") + SONG.song + " (" + difficulty + ")", inst, getIconRPC());
|
||||
DiscordUtil.changeSongPresence(detailsText, (paused ? "Paused - " : "") + SONG.meta.name + " (" + difficulty + ")", inst, getIconRPC());
|
||||
|
||||
/**
|
||||
* Starts a cutscene.
|
||||
@@ -721,13 +695,13 @@ class PlayState extends MusicBeatState
|
||||
if (callback == null)
|
||||
callback = startCountdown;
|
||||
if (cutsceneScriptPath == null)
|
||||
cutsceneScriptPath = Paths.script('songs/${SONG.song.toLowerCase()}/${prefix}cutscene');
|
||||
cutsceneScriptPath = Paths.script('songs/${SONG.meta.name.toLowerCase()}/${prefix}cutscene');
|
||||
|
||||
if (playCutscenes) {
|
||||
inCutscene = true;
|
||||
var videoCutscene = Paths.video('${PlayState.SONG.song.toLowerCase()}-${prefix}cutscene');
|
||||
var videoCutsceneAlt = Paths.file('songs/${PlayState.SONG.song.toLowerCase()}/${prefix}cutscene.mp4');
|
||||
var dialogue = Paths.file('songs/${PlayState.SONG.song.toLowerCase()}/${prefix}dialogue.xml');
|
||||
var videoCutscene = Paths.video('${PlayState.SONG.meta.name.toLowerCase()}-${prefix}cutscene');
|
||||
var videoCutsceneAlt = Paths.file('songs/${PlayState.SONG.meta.name.toLowerCase()}/${prefix}cutscene.mp4');
|
||||
var dialogue = Paths.file('songs/${PlayState.SONG.meta.name.toLowerCase()}/${prefix}dialogue.xml');
|
||||
persistentUpdate = true;
|
||||
if (cutsceneScriptPath != null) {
|
||||
openSubState(new ScriptedCutscene(cutsceneScriptPath, function() {
|
||||
@@ -870,131 +844,35 @@ class PlayState extends MusicBeatState
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public function generateNotes(songData:SwagSong) {
|
||||
// TODO: redo with proper chart parser & codename chart format
|
||||
|
||||
if (songData == null) return;
|
||||
if (songData.noteTypes == null) songData.noteTypes = [];
|
||||
|
||||
var noteData:Array<SwagSection> = songData.notes;
|
||||
var stepCrochet = Conductor.stepCrochet;
|
||||
|
||||
for (section in noteData)
|
||||
{
|
||||
if (section == null || section.sectionNotes == null) continue;
|
||||
|
||||
if (section.changeBPM && section.bpm > 0)
|
||||
stepCrochet = ((60 / section.bpm) * 250);
|
||||
|
||||
for (songNotes in section.sectionNotes)
|
||||
{
|
||||
if (songNotes == null) continue;
|
||||
var daStrumTime:Float = songNotes[0];
|
||||
var daNoteData:Int = Std.int(songNotes[1] % 8);
|
||||
|
||||
if (daNoteData < 0) continue;
|
||||
var daNoteType:Int = Std.int(songNotes[1] / 8);
|
||||
var gottaHitNote:Bool = daNoteData >= 4 ? !section.mustHitSection : section.mustHitSection;
|
||||
|
||||
if (songNotes.length > 2) {
|
||||
if (songNotes[3] is Int)
|
||||
daNoteType = addNoteType(songData.noteTypes[Std.int(songNotes[3])-1], songNotes[3] == 0);
|
||||
else if (songNotes[3] is String)
|
||||
daNoteType = addNoteType(songNotes[3]);
|
||||
} else {
|
||||
daNoteType = addNoteType(songData.noteTypes[daNoteType-1], daNoteType == 0);
|
||||
}
|
||||
|
||||
var swagNote:Note;
|
||||
if (notes.length > 0)
|
||||
swagNote = notes.members[Std.int(notes.members.length - 1)];
|
||||
else
|
||||
swagNote = null;
|
||||
|
||||
swagNote.nextNote = (swagNote = new Note(daStrumTime, daNoteData % 4, daNoteType, gottaHitNote ? 1 : 0, swagNote, false, section.altAnim ? "-alt" : ""));
|
||||
swagNote.sustainLength = songNotes[2];
|
||||
swagNote.scrollFactor.set(0, 0);
|
||||
swagNote.stepLength = stepCrochet;
|
||||
notes.add(swagNote);
|
||||
|
||||
// calculate sustain length and fix
|
||||
var susLength:Float = swagNote.sustainLength / stepCrochet;
|
||||
if (susLength > 0.75) susLength++;
|
||||
|
||||
// create sustains
|
||||
for (susNote in 0...Math.floor(susLength))
|
||||
{
|
||||
swagNote = new Note(daStrumTime + (stepCrochet * susNote), daNoteData % 4, daNoteType, gottaHitNote ? 1 : 0, swagNote, true, section.altAnim ? "-alt" : "");
|
||||
swagNote.scrollFactor.set();
|
||||
swagNote.stepLength = stepCrochet;
|
||||
notes.add(swagNote);
|
||||
}
|
||||
|
||||
// preload splash
|
||||
if (Options.splashesEnabled)
|
||||
splashHandler.getSplashGroup(swagNote.splash);
|
||||
}
|
||||
}
|
||||
notes.sortNotes();
|
||||
}
|
||||
|
||||
@:dox(hide) private function generateSong(?songData:SwagSong):Void
|
||||
@:dox(hide) private function generateSong(?songData:ChartData):Void
|
||||
{
|
||||
if (songData == null) songData = SONG;
|
||||
|
||||
if (songData.maxHealth != null && songData.maxHealth > 0)
|
||||
maxHealth = songData.maxHealth;
|
||||
events = songData.events != null ? [for(e in songData.events) e] : [];
|
||||
events.sort(function(p1, p2) {
|
||||
return FlxSort.byValues(FlxSort.ASCENDING, p1.time, p2.time);
|
||||
});
|
||||
|
||||
camZoomingInterval = cast songData.beatsPerMesure.getDefault(4);
|
||||
camZoomingInterval = cast songData.meta.beatsPerMesure.getDefault(4);
|
||||
|
||||
Conductor.changeBPM(songData.bpm);
|
||||
Conductor.changeBPM(songData.meta.bpm);
|
||||
|
||||
curSong = songData.song.toLowerCase();
|
||||
curSong = songData.meta.name.toLowerCase();
|
||||
|
||||
inst = FlxG.sound.load(Paths.inst(SONG.song, difficulty));
|
||||
inst = FlxG.sound.load(Paths.inst(SONG.meta.name, difficulty));
|
||||
vocals = FlxG.sound.list.recycle(FlxSound);
|
||||
@:privateAccess {
|
||||
vocals.reset();
|
||||
vocals.exists = true;
|
||||
}
|
||||
if (SONG.needsVoices)
|
||||
vocals.loadEmbedded(Paths.voices(SONG.song, difficulty));
|
||||
if (SONG.meta.needsVoices != false) // null or true
|
||||
vocals.loadEmbedded(Paths.voices(SONG.meta.name, difficulty));
|
||||
FlxG.sound.list.add(vocals);
|
||||
|
||||
inst.persist = vocals.persist = false;
|
||||
|
||||
notes = new NoteGroup();
|
||||
add(notes);
|
||||
|
||||
generateNotes(songData);
|
||||
|
||||
generatedMusic = true;
|
||||
}
|
||||
|
||||
public function addNoteType(name:String, addAsDefaultIfUnknown:Bool = false):Int {
|
||||
if (name == null) {
|
||||
if (addAsDefaultIfUnknown)
|
||||
return 0;
|
||||
else
|
||||
name = "Unknown";
|
||||
}
|
||||
|
||||
for(k=>e in noteTypesArray)
|
||||
if (e == name) return k;
|
||||
|
||||
noteTypesArray.push(name);
|
||||
|
||||
// loads script
|
||||
var scriptPath = Paths.script('data/notes/${name}');
|
||||
if (Assets.exists(scriptPath) && !scripts.contains(scriptPath)) {
|
||||
var script = Script.create(scriptPath);
|
||||
if (!(script is DummyScript)) {
|
||||
scripts.add(script);
|
||||
script.load();
|
||||
}
|
||||
}
|
||||
return noteTypesArray.length-1;
|
||||
}
|
||||
|
||||
@:dox(hide) function sortByShit(Obj1:Note, Obj2:Note):Int {
|
||||
return FlxSort.byValues(FlxSort.ASCENDING, Obj1.strumTime, Obj2.strumTime);
|
||||
@@ -1057,7 +935,7 @@ class PlayState extends MusicBeatState
|
||||
* Returns the Discord RPC icon.
|
||||
*/
|
||||
public inline function getIconRPC():String
|
||||
return (dad != null ? (dad.icon != null ? dad.icon : dad.curCharacter) : SONG.player2);
|
||||
return (dad != null ? (dad.icon != null ? dad.icon : dad.curCharacter) : null);
|
||||
|
||||
var __songPlaying:Bool = false;
|
||||
var __wasAutoPause:Bool = false;
|
||||
@@ -1105,11 +983,6 @@ class PlayState extends MusicBeatState
|
||||
scripts.call("onVocalsResync");
|
||||
}
|
||||
|
||||
@:dox(hide)
|
||||
public function get_curSection() {
|
||||
return PlayState.SONG.notes[curMeasure];
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the game.
|
||||
*/
|
||||
@@ -1166,19 +1039,11 @@ class PlayState extends MusicBeatState
|
||||
pauseGame();
|
||||
|
||||
if (canAccessDebugMenus) {
|
||||
if (FlxG.keys.justPressed.SEVEN)
|
||||
{
|
||||
FlxG.switchState(new ChartingState());
|
||||
}
|
||||
if (FlxG.keys.justPressed.F5) {
|
||||
Logs.trace('Reloading scripts...', WARNING, YELLOW);
|
||||
scripts.reload();
|
||||
Logs.trace('Song scripts successfully reloaded.', WARNING, GREEN);
|
||||
}
|
||||
if (FlxG.keys.justPressed.EIGHT)
|
||||
FlxG.switchState(new CharacterEditor(SONG.player2));
|
||||
if (FlxG.keys.justPressed.NINE)
|
||||
FlxG.switchState(new CharacterEditor(SONG.player1));
|
||||
}
|
||||
|
||||
iconP1.scale.set(lerp(iconP1.scale.x, 1, 0.33), lerp(iconP1.scale.y, 1, 0.33));
|
||||
@@ -1213,28 +1078,31 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
}
|
||||
|
||||
if (generatedMusic && curSection != null)
|
||||
while(events.length > 0 && events[0].time <= Conductor.songPosition)
|
||||
executeEvent(events.shift());
|
||||
|
||||
if (generatedMusic && players[curCameraTarget] != null)
|
||||
{
|
||||
var dadPos = dad != null ? dad.getCameraPosition() : FlxPoint.get(0,0);
|
||||
var bfPos = boyfriend != null ? boyfriend.getCameraPosition() : FlxPoint.get(0,0);
|
||||
var section = curSection;
|
||||
|
||||
// from dad to bf
|
||||
var ratio:Float = 0;
|
||||
if (section.camTarget != null)
|
||||
ratio = section.camTarget;
|
||||
else
|
||||
ratio = section.mustHitSection ? 1 : 0;
|
||||
|
||||
var event = scripts.event("onCameraMove", EventManager.get(CamMoveEvent).recycle(FlxPoint.get(FlxMath.lerp(dadPos.x, bfPos.x, ratio), FlxMath.lerp(dadPos.y, bfPos.y, ratio)), bfPos, dadPos, ratio, ratio >= 0.5));
|
||||
|
||||
if (!event.cancelled) {
|
||||
camFollow.setPosition(
|
||||
event.position.x, event.position.y
|
||||
);
|
||||
var strumLine = players[curCameraTarget];
|
||||
var pos = FlxPoint.get();
|
||||
var r = 0;
|
||||
for(c in strumLine.characters) {
|
||||
if (c == null) continue;
|
||||
var cpos = c.getCameraPosition();
|
||||
pos.x += cpos.x;
|
||||
pos.y += cpos.y;
|
||||
r++;
|
||||
cpos.put();
|
||||
}
|
||||
for(e in [event.position, event.bfCamPos, event.dadCamPos])
|
||||
e.put();
|
||||
if (r > 0) {
|
||||
pos.x /= r;
|
||||
pos.y /= r;
|
||||
|
||||
var event = scripts.event("onCameraMove", EventManager.get(CamMoveEvent).recycle(pos, strumLine, r));
|
||||
if (!event.cancelled)
|
||||
camFollow.setPosition(pos.x, pos.y);
|
||||
}
|
||||
pos.put();
|
||||
}
|
||||
|
||||
if (camZooming)
|
||||
@@ -1253,10 +1121,6 @@ class PlayState extends MusicBeatState
|
||||
gameOver(dad);
|
||||
|
||||
|
||||
if (generatedMusic) {
|
||||
__updateNote_event = EventManager.get(NoteUpdateEvent);
|
||||
notes.forEachAlive(updateNote);
|
||||
}
|
||||
|
||||
if (!inCutscene)
|
||||
keyShit();
|
||||
@@ -1269,49 +1133,28 @@ class PlayState extends MusicBeatState
|
||||
scripts.call("postUpdate", [elapsed]);
|
||||
}
|
||||
|
||||
var __updateNote_strum:Strum = null;
|
||||
var __updateNote_event:NoteUpdateEvent = null;
|
||||
@:dox(hide)
|
||||
function updateNote(daNote:Note)
|
||||
{
|
||||
for(e in players[daNote.strumLineID].members) {
|
||||
if (e.ID == daNote.noteData % 4) {
|
||||
__updateNote_strum = e;
|
||||
break; //ing bad
|
||||
}
|
||||
public function executeEvent(event:ChartEvent) {
|
||||
if (event == null) return;
|
||||
if (event.params == null) return;
|
||||
|
||||
switch(event.type) {
|
||||
case CUSTOM:
|
||||
var d = [for(d in event.params) d];
|
||||
scripts.call(d.shift(), d);
|
||||
case CAM_MOVEMENT:
|
||||
if (event.params.length > 0 && event.params[0] is Int)
|
||||
curCameraTarget = event.params[0];
|
||||
case BPM_CHANGE:
|
||||
// todo!!
|
||||
case ALT_ANIM_TOGGLE:
|
||||
// todo!!!
|
||||
default:
|
||||
}
|
||||
PlayState.instance.scripts.event("onNoteUpdate", __updateNote_event.recycle(daNote, FlxG.elapsed, __updateNote_strum));
|
||||
if (__updateNote_event.cancelled) return;
|
||||
|
||||
if (__updateNote_event.__updateHitWindow) {
|
||||
daNote.canBeHit = (daNote.strumTime > Conductor.songPosition - (hitWindow * daNote.latePressWindow)
|
||||
&& daNote.strumTime < Conductor.songPosition + (hitWindow * daNote.earlyPressWindow));
|
||||
|
||||
if (daNote.strumTime < Conductor.songPosition - hitWindow && !daNote.wasGoodHit)
|
||||
daNote.tooLate = true;
|
||||
}
|
||||
|
||||
if (__updateNote_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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (daNote.tooLate && !(daNote.strumLine != null && daNote.strumLine.cpu)) {
|
||||
noteMiss(daNote);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (__updateNote_event.strum == null) return;
|
||||
|
||||
if (__updateNote_event.__reposNote) __updateNote_event.strum.updateNotePosition(daNote);
|
||||
__updateNote_event.strum.updateSustain(daNote);
|
||||
|
||||
PlayState.instance.scripts.event("onNotePostUpdate", __updateNote_event);
|
||||
}
|
||||
|
||||
@:dox(hide)
|
||||
public var __updateNote_event:NoteUpdateEvent = null;
|
||||
|
||||
/**
|
||||
* Forces a game over.
|
||||
* @param character Character which died. Default to `boyfriend`.
|
||||
@@ -1353,10 +1196,10 @@ class PlayState extends MusicBeatState
|
||||
inst.pause();
|
||||
vocals.pause();
|
||||
|
||||
if (SONG.validScore)
|
||||
if (validScore)
|
||||
{
|
||||
#if !switch
|
||||
Highscore.saveScore(SONG.song, {
|
||||
Highscore.saveScore(SONG.meta.name, {
|
||||
score: songScore,
|
||||
misses: misses,
|
||||
accuracy: accuracy
|
||||
@@ -1380,7 +1223,7 @@ class PlayState extends MusicBeatState
|
||||
{
|
||||
FlxG.switchState(new StoryMenuState());
|
||||
|
||||
if (SONG.validScore)
|
||||
if (validScore)
|
||||
{
|
||||
// TODO: more week info saving
|
||||
Highscore.saveWeekScore(storyWeek.name, {
|
||||
@@ -1425,7 +1268,13 @@ class PlayState extends MusicBeatState
|
||||
var __justReleased:Array<Bool> = [];
|
||||
private function keyShit():Void
|
||||
{
|
||||
if (generatedMusic) {
|
||||
__updateNote_event = EventManager.get(NoteUpdateEvent);
|
||||
}
|
||||
|
||||
for(id=>p in players) {
|
||||
p.updateNotes();
|
||||
|
||||
if (p.cpu) continue;
|
||||
|
||||
__funcsToExec.clear();
|
||||
@@ -1447,8 +1296,8 @@ class PlayState extends MusicBeatState
|
||||
|
||||
if (__pressed.contains(true)) {
|
||||
__funcsToExec.push(function(note:Note) {
|
||||
if (note.strumLineID == id && __pressed[note.strumID] && note.isSustainNote && note.canBeHit && !note.wasGoodHit) {
|
||||
goodNoteHit(note);
|
||||
if (__pressed[note.strumID] && note.isSustainNote && note.canBeHit && !note.wasGoodHit) {
|
||||
goodNoteHit(p, note);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1456,25 +1305,25 @@ class PlayState extends MusicBeatState
|
||||
var notePerStrum = [for(_ in 0...4) null];
|
||||
if (__justPressed.contains(true)) {
|
||||
__funcsToExec.push(function(note:Note) {
|
||||
if (__justPressed[note.strumID] && !note.isSustainNote && note.strumLineID == id && !note.wasGoodHit && note.canBeHit) {
|
||||
if (__justPressed[note.strumID] && !note.isSustainNote && !note.wasGoodHit && note.canBeHit) {
|
||||
if (notePerStrum[note.strumID] == null) notePerStrum[note.strumID] = note;
|
||||
else if (Math.abs(notePerStrum[note.strumID].strumTime - note.strumTime) <= 2) deleteNote(note);
|
||||
else if (Math.abs(notePerStrum[note.strumID].strumTime - note.strumTime) <= 2) p.deleteNote(note);
|
||||
else if (note.strumTime < notePerStrum[note.strumID].strumTime) notePerStrum[note.strumID] = note;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (__funcsToExec.length > 0) {
|
||||
notes.forEachAlive(function(note:Note) {
|
||||
p.notes.forEachAlive(function(note:Note) {
|
||||
for(e in __funcsToExec) e(note);
|
||||
});
|
||||
}
|
||||
|
||||
if (!p.ghostTapping) for(k=>p in __justPressed) if (p && notePerStrum[k] == null) {
|
||||
if (!p.ghostTapping) for(k=>pr in __justPressed) if (pr && notePerStrum[k] == null) {
|
||||
// FUCK YOU
|
||||
noteMiss(null, k, id);
|
||||
noteMiss(p, null, k, id);
|
||||
}
|
||||
for(e in notePerStrum) if (e != null) goodNoteHit(e);
|
||||
for(e in notePerStrum) if (e != null) goodNoteHit(p, e);
|
||||
|
||||
p.forEach(function(str:Strum) {
|
||||
str.updatePlayerInput(__pressed[str.ID], __justPressed[str.ID], __justReleased[str.ID]);
|
||||
@@ -1489,18 +1338,17 @@ class PlayState extends MusicBeatState
|
||||
* @param direction Specify a custom direction in case note is null.
|
||||
* @param player Specify a custom player in case note is null.
|
||||
*/
|
||||
public function noteMiss(note:Note, ?direction:Int, ?player:Int):Void
|
||||
public function noteMiss(strumLine:StrumLine, note:Note, ?direction:Int, ?player:Int):Void
|
||||
{
|
||||
var playerID:Null<Int> = note == null ? player : note.strumLineID;
|
||||
var playerID:Null<Int> = note == null ? player : players.indexOf(strumLine);
|
||||
var directionID:Null<Int> = note == null ? direction : note.strumID;
|
||||
if (playerID == null || directionID == null) return;
|
||||
|
||||
var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, players[player].characters, true, note != null ? note.noteType : null, "", "", "", directionID, -10, 0, -0.04, "shit"));
|
||||
|
||||
var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, players[playerID].characters, true, note != null ? note.noteType : null, "", "", "", directionID, -10, 0, -0.04, "shit"));
|
||||
if (event.cancelled) return;
|
||||
|
||||
|
||||
if (event.note != null && event.note.strumLine != null) event.note.strumLine.addHealth(event.healthGain);
|
||||
if (event.note != null && strumLine != null) strumLine.addHealth(event.healthGain);
|
||||
if (gf != null && combo > 5 && gf.hasAnimation('sad'))
|
||||
gf.playAnim('sad', event.forceAnim, MISS);
|
||||
combo = 0;
|
||||
@@ -1525,21 +1373,22 @@ class PlayState extends MusicBeatState
|
||||
char.stunned = true;
|
||||
char.playSingAnim(directionID, "miss", MISS);
|
||||
}
|
||||
// boyfriend.stunned = true;
|
||||
|
||||
deleteNote(note);
|
||||
if (strumLine != null && note != null) {
|
||||
strumLine.deleteNote(note);
|
||||
}
|
||||
}
|
||||
|
||||
@:dox(hide)
|
||||
public function getNoteType(id:Int):String {
|
||||
return noteTypesArray[id];
|
||||
return SONG.noteTypes[id-1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hits a note
|
||||
* @param note Note to hit.
|
||||
*/
|
||||
public function goodNoteHit(note:Note):Void
|
||||
public function goodNoteHit(strumLine:StrumLine, note:Note):Void
|
||||
{
|
||||
if(note == null || note.wasGoodHit) return;
|
||||
|
||||
@@ -1573,10 +1422,10 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
|
||||
var event:NoteHitEvent;
|
||||
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, note.animSuffix, "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating, Options.splashesEnabled && !note.isSustainNote && daRating == "sick"));
|
||||
if (strumLine != null && !strumLine.cpu)
|
||||
event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, strumLine.characters, true, note.noteType, note.animSuffix, "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating, Options.splashesEnabled && !note.isSustainNote && daRating == "sick"));
|
||||
else
|
||||
event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, note.strumLine.characters, false, note.noteType, note.animSuffix, "game/score/", "", note.strumID, 0, null, 0, daRating, false));
|
||||
event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, strumLine.characters, false, note.noteType, note.animSuffix, "game/score/", "", note.strumID, 0, null, 0, daRating, false));
|
||||
scripts.event("onNoteHit", event);
|
||||
|
||||
if (!event.cancelled) {
|
||||
@@ -1664,7 +1513,7 @@ class PlayState extends MusicBeatState
|
||||
ratingNum += 1;
|
||||
}
|
||||
|
||||
if (event.note.strumLine != null) event.note.strumLine.addHealth(event.healthGain);
|
||||
if (strumLine != null) strumLine.addHealth(event.healthGain);
|
||||
|
||||
if (!event.animCancelled)
|
||||
for(char in event.characters)
|
||||
@@ -1686,24 +1535,13 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
}
|
||||
|
||||
if (event.deleteNote && !note.isSustainNote) deleteNote(note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a note.
|
||||
* @param note Note to delete
|
||||
*/
|
||||
public function deleteNote(note:Note) {
|
||||
if (note == null) return;
|
||||
var event:SimpleNoteEvent = scripts.event("onNoteDelete", EventManager.get(SimpleNoteEvent).recycle(note));
|
||||
if (!event.cancelled) {
|
||||
scripts.call("onNoteDelete", [note]);
|
||||
note.kill();
|
||||
notes.remove(note, true);
|
||||
note.destroy();
|
||||
}
|
||||
if (event.deleteNote && !note.isSustainNote) strumLine.deleteNote(note);
|
||||
}
|
||||
|
||||
public inline function deleteNote(note:Note)
|
||||
if (note.strumLine != null)
|
||||
note.strumLine.deleteNote(note);
|
||||
|
||||
@:dox(hide)
|
||||
override function stepHit(curStep:Int)
|
||||
{
|
||||
@@ -1752,16 +1590,40 @@ class PlayState extends MusicBeatState
|
||||
private inline function set_cpu(s:StrumLine):StrumLine
|
||||
return cpuStrums = s;
|
||||
|
||||
private function get_boyfriend():Character {
|
||||
if (players != null && players[1] != null)
|
||||
return players[1].characters[0];
|
||||
return null;
|
||||
}
|
||||
private function set_boyfriend(bf:Character):Character {
|
||||
if (players != null && players[1] != null)
|
||||
players[1].characters = [bf];
|
||||
return this.boyfriend = bf;
|
||||
return bf;
|
||||
}
|
||||
private function get_dad():Character {
|
||||
if (players != null && players[0] != null)
|
||||
return players[0].characters[0];
|
||||
return null;
|
||||
}
|
||||
private function set_dad(dad:Character):Character {
|
||||
if (players != null && players[0] != null)
|
||||
players[0].characters = [dad];
|
||||
return this.dad = dad;
|
||||
return dad;
|
||||
}
|
||||
private function get_gf():Character {
|
||||
if (players != null && players[2] != null)
|
||||
return players[2].characters[0];
|
||||
return null;
|
||||
}
|
||||
private function set_gf(gf:Character):Character {
|
||||
if (players != null && players[2] != null)
|
||||
players[2].characters = [gf];
|
||||
return gf;
|
||||
}
|
||||
private inline function get_cpuStrums():StrumLine
|
||||
return players[0];
|
||||
private inline function get_playerStrums():StrumLine
|
||||
return players[1];
|
||||
}
|
||||
|
||||
class ComboRating {
|
||||
|
||||
+68
-13
@@ -19,6 +19,8 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
public var stagePath:String;
|
||||
public var stageSprites:Map<String, FlxSprite> = [];
|
||||
public var stageScript:Script;
|
||||
public var state:FlxState;
|
||||
public var characterPoses:Map<String, StageCharPos> = [];
|
||||
|
||||
public function getSprite(name:String) {
|
||||
return stageSprites[name];
|
||||
@@ -29,6 +31,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
|
||||
if (state == null) state = PlayState.instance;
|
||||
if (state == null) state = FlxG.state;
|
||||
this.state = state;
|
||||
|
||||
stagePath = Paths.xml('stages/$stage');
|
||||
try {
|
||||
@@ -89,15 +92,18 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
state.add(spr);
|
||||
spr;
|
||||
case "boyfriend" | "bf":
|
||||
if (PlayState.instance == null || PlayState.instance.boyfriend == null) continue;
|
||||
doCharNodeShit(PlayState.instance.boyfriend, node);
|
||||
PlayState.instance.add(PlayState.instance.boyfriend);
|
||||
PlayState.instance.boyfriend;
|
||||
addCharPos("boyfriend", node);
|
||||
null;
|
||||
case "girlfriend" | "gf":
|
||||
if (PlayState.instance == null || PlayState.instance.gf == null) continue;
|
||||
doCharNodeShit(PlayState.instance.gf, node);
|
||||
PlayState.instance.add(PlayState.instance.gf);
|
||||
PlayState.instance.gf;
|
||||
addCharPos("girlfriend", node);
|
||||
null;
|
||||
case "dad" | "opponent":
|
||||
addCharPos("dad", node);
|
||||
null;
|
||||
case "character":
|
||||
if (!node.has.name) continue;
|
||||
addCharPos(node.att.name, node);
|
||||
null;
|
||||
case "ratings" | "combo":
|
||||
if (PlayState.instance == null) continue;
|
||||
PlayState.instance.comboGroup.setPosition(
|
||||
@@ -106,11 +112,6 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
);
|
||||
PlayState.instance.add(PlayState.instance.comboGroup);
|
||||
PlayState.instance.comboGroup;
|
||||
case "dad" | "opponent":
|
||||
if (PlayState.instance == null || PlayState.instance.dad == null || PlayState.instance.dad.isGF) continue;
|
||||
doCharNodeShit(PlayState.instance.dad, node);
|
||||
PlayState.instance.add(PlayState.instance.dad);
|
||||
PlayState.instance.dad;
|
||||
default: null;
|
||||
}
|
||||
if (sprite != null) {
|
||||
@@ -120,6 +121,24 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
if (characterPoses["girlfriend"] == null)
|
||||
addCharPos("girlfriend", null, {
|
||||
x: 400,
|
||||
y: 130
|
||||
});
|
||||
|
||||
if (characterPoses["dad"] == null)
|
||||
addCharPos("dad", null, {
|
||||
x: 100,
|
||||
y: 100
|
||||
});
|
||||
|
||||
if (characterPoses["boyfriend"] == null)
|
||||
addCharPos("boyfriend", null, {
|
||||
x: 770,
|
||||
y: 100
|
||||
});
|
||||
|
||||
if (PlayState.instance == null) return;
|
||||
stageScript = Script.create(Paths.script('data/stages/$stage'));
|
||||
for(k=>e in stageSprites) {
|
||||
@@ -128,7 +147,32 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
PlayState.instance.scripts.add(stageScript);
|
||||
}
|
||||
|
||||
public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo) {
|
||||
var dummyBasic:FlxBasic = new FlxBasic();
|
||||
dummyBasic.active = false;
|
||||
state.add(dummyBasic);
|
||||
|
||||
characterPoses[name] = {
|
||||
node: node,
|
||||
nonXMLInfo: nonXMLInfo,
|
||||
dummy: dummyBasic
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public function applyCharStuff(char:Character, posName:String) {
|
||||
if (characterPoses[posName] == null)
|
||||
state.add(char);
|
||||
else {
|
||||
var charPos = characterPoses[posName];
|
||||
if (charPos.node != null) {
|
||||
doCharNodeShit(char, charPos.node);
|
||||
} else if (charPos.nonXMLInfo != null) {
|
||||
char.setPosition(charPos.nonXMLInfo.x, charPos.nonXMLInfo.y);
|
||||
}
|
||||
state.insert(state.members.indexOf(charPos.dummy), char);
|
||||
}
|
||||
}
|
||||
private static function doCharNodeShit(char:Character, node:Access) {
|
||||
if (node.has.x) {
|
||||
var x:Null<Float> = Std.parseFloat(node.att.x);
|
||||
@@ -157,4 +201,15 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
public function stepHit(curStep:Int) {}
|
||||
|
||||
public function measureHit(curMeasure:Int) {}
|
||||
}
|
||||
|
||||
typedef StageCharPos = {
|
||||
var node:Access;
|
||||
var dummy:FlxBasic;
|
||||
var ?nonXMLInfo:StageCharPosInfo;
|
||||
}
|
||||
|
||||
typedef StageCharPosInfo = {
|
||||
var x:Float;
|
||||
var y:Float;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package funkin.game;
|
||||
|
||||
import funkin.scripting.events.SimpleNoteEvent;
|
||||
import funkin.system.Conductor;
|
||||
import funkin.chart.Chart.ChartStrumLine;
|
||||
import funkin.system.Controls;
|
||||
import funkin.scripting.events.StrumCreationEvent;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
@@ -28,6 +31,10 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
* Whenever Ghost Tapping is enabled.
|
||||
*/
|
||||
@:isVar public var ghostTapping(get, set):Null<Bool> = null;
|
||||
/**
|
||||
* Group of all of the notes in this strumline. Using `forEach` on this group will only loop through the first notes for performance reasons.
|
||||
*/
|
||||
public var notes:NoteGroup;
|
||||
|
||||
private function get_ghostTapping() {
|
||||
if (this.ghostTapping != null) return this.ghostTapping;
|
||||
@@ -47,6 +54,70 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
this.cpu = cpu;
|
||||
this.opponentSide = opponentSide;
|
||||
this.controls = controls;
|
||||
this.notes = new NoteGroup();
|
||||
}
|
||||
|
||||
public function generate(strumLine:ChartStrumLine) {
|
||||
if (strumLine.notes != null) for(note in strumLine.notes) {
|
||||
notes.add(new Note(this, note, false));
|
||||
}
|
||||
notes.sortNotes();
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
notes.update(elapsed);
|
||||
}
|
||||
|
||||
public override function draw() {
|
||||
super.draw();
|
||||
notes.cameras = cameras;
|
||||
notes.draw();
|
||||
}
|
||||
|
||||
public function updateNotes() {
|
||||
notes.forEach(updateNote);
|
||||
}
|
||||
|
||||
var __updateNote_strum:Strum;
|
||||
public function updateNote(daNote:Note) {
|
||||
|
||||
for(e in members) {
|
||||
if (e.ID == daNote.noteData % 4) {
|
||||
__updateNote_strum = e;
|
||||
break; //ing bad
|
||||
}
|
||||
}
|
||||
PlayState.instance.scripts.event("onNoteUpdate", PlayState.instance.__updateNote_event.recycle(daNote, FlxG.elapsed, __updateNote_strum));
|
||||
if (PlayState.instance.__updateNote_event.cancelled) return;
|
||||
|
||||
if (PlayState.instance.__updateNote_event.__updateHitWindow) {
|
||||
daNote.canBeHit = (daNote.strumTime > Conductor.songPosition - (PlayState.instance.hitWindow * daNote.latePressWindow)
|
||||
&& daNote.strumTime < Conductor.songPosition + (PlayState.instance.hitWindow * daNote.earlyPressWindow));
|
||||
|
||||
if (daNote.strumTime < Conductor.songPosition - PlayState.instance.hitWindow && !daNote.wasGoodHit)
|
||||
daNote.tooLate = true;
|
||||
}
|
||||
|
||||
if (PlayState.instance.__updateNote_event.__autoCPUHit && cpu && !daNote.wasGoodHit && daNote.strumTime < Conductor.songPosition) PlayState.instance.goodNoteHit(this, daNote);
|
||||
|
||||
if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.stepLength) < Conductor.songPosition) {
|
||||
deleteNote(daNote);
|
||||
return;
|
||||
}
|
||||
|
||||
if (daNote.tooLate && !cpu) {
|
||||
PlayState.instance.noteMiss(this, daNote);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (PlayState.instance.__updateNote_event.strum == null) return;
|
||||
|
||||
if (PlayState.instance.__updateNote_event.__reposNote) PlayState.instance.__updateNote_event.strum.updateNotePosition(daNote);
|
||||
PlayState.instance.__updateNote_event.strum.updateSustain(daNote);
|
||||
|
||||
PlayState.instance.scripts.event("onNotePostUpdate", PlayState.instance.__updateNote_event);
|
||||
}
|
||||
|
||||
public inline function addHealth(health:Float)
|
||||
@@ -103,12 +174,25 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
}
|
||||
|
||||
add(babyArrow);
|
||||
PlayState.instance.strumLineNotes.add(babyArrow);
|
||||
|
||||
babyArrow.playAnim('static');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a note from this strumline.
|
||||
* @param note Note to delete
|
||||
*/
|
||||
public function deleteNote(note:Note) {
|
||||
if (note == null) return;
|
||||
var event:SimpleNoteEvent = PlayState.instance.scripts.event("onNoteDelete", EventManager.get(SimpleNoteEvent).recycle(note));
|
||||
if (!event.cancelled) {
|
||||
note.kill();
|
||||
notes.remove(note, true);
|
||||
note.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SETTERS & GETTERS
|
||||
*/
|
||||
|
||||
@@ -108,6 +108,12 @@ class FreeplayState extends MusicBeatState
|
||||
*/
|
||||
public var iconArray:Array<HealthIcon> = [];
|
||||
|
||||
/**
|
||||
* FlxInterpolateColor object for smooth transition between Freeplay colors.
|
||||
*/
|
||||
public var interpColor:FlxInterpolateColor;
|
||||
|
||||
|
||||
override function create()
|
||||
{
|
||||
songList = FreeplaySonglist.get();
|
||||
@@ -165,6 +171,7 @@ class FreeplayState extends MusicBeatState
|
||||
changeDiff(0, true);
|
||||
changeCoopMode(0, true);
|
||||
|
||||
interpColor = new FlxInterpolateColor(bg.color);
|
||||
super.create();
|
||||
}
|
||||
|
||||
@@ -213,7 +220,8 @@ class FreeplayState extends MusicBeatState
|
||||
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);
|
||||
interpColor.fpsLerpTo(songs[curSelected].color, 0.0625);
|
||||
bg.color = interpColor.color;
|
||||
|
||||
|
||||
var dontPlaySongThisFrame = false;
|
||||
|
||||
@@ -65,7 +65,7 @@ class PauseSubState extends MusicBeatSubstate
|
||||
bg.scrollFactor.set();
|
||||
add(bg);
|
||||
|
||||
var levelInfo:FlxText = new FlxText(20, 15, 0, PlayState.SONG.song, 32);
|
||||
var levelInfo:FlxText = new FlxText(20, 15, 0, PlayState.SONG.meta.name, 32);
|
||||
var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, PlayState.difficulty.toUpperCase(), 32);
|
||||
var multiplayerText:FlxText = new FlxText(20, 15 + 32 + 32, 0, PlayState.opponentMode ? 'OPPONENT MODE' : (PlayState.coopMode ? 'CO-OP MODE' : ''), 32);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.scripting.events;
|
||||
|
||||
import funkin.game.StrumLine;
|
||||
import flixel.math.FlxPoint;
|
||||
|
||||
class CamMoveEvent extends CancellableEvent {
|
||||
@@ -9,25 +10,12 @@ class CamMoveEvent extends CancellableEvent {
|
||||
public var position:FlxPoint;
|
||||
|
||||
/**
|
||||
* Boyfriend's camera position.
|
||||
* Currently focused strumline.
|
||||
*/
|
||||
public var bfCamPos:FlxPoint;
|
||||
|
||||
/**
|
||||
* Dad's camera position.
|
||||
*/
|
||||
public var dadCamPos:FlxPoint;
|
||||
public var strumLine:StrumLine;
|
||||
|
||||
/**
|
||||
* Ratio for lerping between Dad and BF.
|
||||
* 0 = Camera focuses dad
|
||||
* 0.5 = Duet Camera
|
||||
* 1 = Camera focuses BF
|
||||
* Number of focused characters
|
||||
*/
|
||||
public var ratio:Float = 0;
|
||||
|
||||
/**
|
||||
* Whenever the camera focuses BF more than dad.
|
||||
*/
|
||||
public var focusBF:Bool = false;
|
||||
public var focusedCharacters:Int;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.system;
|
||||
|
||||
import funkin.chart.Chart;
|
||||
import flixel.math.FlxMath;
|
||||
import openfl.Lib;
|
||||
import flixel.FlxState;
|
||||
@@ -121,10 +122,10 @@ class Conductor
|
||||
changeBPM(0);
|
||||
}
|
||||
|
||||
public static function setupSong(SONG:SwagSong) {
|
||||
public static function setupSong(SONG:ChartData) {
|
||||
reset();
|
||||
mapBPMChanges(SONG);
|
||||
changeBPM(SONG.bpm, cast SONG.beatsPerMesure.getDefault(4), cast SONG.stepsPerBeat.getDefault(4));
|
||||
// mapBPMChanges(SONG); // TODO!!!
|
||||
changeBPM(SONG.meta.bpm, cast SONG.meta.beatsPerMesure.getDefault(4), cast SONG.meta.stepsPerBeat.getDefault(4));
|
||||
}
|
||||
/**
|
||||
* Maps BPM changes from a song.
|
||||
|
||||
@@ -24,6 +24,7 @@ import flixel.util.FlxAxes;
|
||||
import flixel.graphics.frames.FlxFrame;
|
||||
import flixel.graphics.frames.FlxFramesCollection;
|
||||
import flash.geom.ColorTransform;
|
||||
import funkin.chart.Chart;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@@ -294,7 +295,8 @@ class CoolUtil
|
||||
public static function __loadSong(name:String, difficulty:String) {
|
||||
PlayState.difficulty = difficulty;
|
||||
|
||||
PlayState.SONG = Song.loadFromJson(name, difficulty);
|
||||
PlayState.SONG = Chart.parse(name, difficulty);
|
||||
PlayState.fromMods = PlayState.SONG.fromMods;
|
||||
}
|
||||
public static function setSpriteSize(sprite:FlxSprite, width:Float, height:Float) {
|
||||
sprite.scale.set(width / sprite.frameWidth, height / sprite.frameHeight);
|
||||
|
||||
@@ -3,6 +3,10 @@ package funkin.utils;
|
||||
import flixel.FlxG;
|
||||
import flixel.util.FlxColor;
|
||||
|
||||
/**
|
||||
* Additional class for FlxColor lerping.
|
||||
* Gets rid of precision issues with `FlxColor.interpolate`
|
||||
*/
|
||||
class FlxInterpolateColor {
|
||||
public var red:Float = 0;
|
||||
public var green:Float = 0;
|
||||
|
||||
Reference in New Issue
Block a user