diff --git a/source/PlayState.hx b/source/PlayState.hx index 3c5484e7d..b7d900238 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -833,6 +833,9 @@ class PlayState extends MusicBeatState curStage.addCharacter(boyfriend, BF); curStage.addCharacter(gf, GF); curStage.addCharacter(dad, DAD); + + // Redo z-indexes. + curStage.refresh(); } else { @@ -2910,18 +2913,6 @@ class PlayState extends MusicBeatState startedMoving = false; } - function lightningStrikeShit():Void - { - FlxG.sound.play(Paths.soundRandom('thunder_', 1, 2)); - halloweenBG.animation.play('lightning'); - - lightningStrikeBeat = curBeat; - lightningOffset = FlxG.random.int(8, 24); - - boyfriend.playAnim('scared', true); - gf.playAnim('scared', true); - } - override function stepHit() { super.stepHit(); @@ -2930,10 +2921,13 @@ class PlayState extends MusicBeatState { resyncVocals(); } - } - var lightningStrikeBeat:Int = 0; - var lightningOffset:Int = 8; + if (curStage != null) + { + // We're using Eric's stage handler. The stage should know that a beat has been hit. + curStage.onStepHit(curBeat); + } + } override function beatHit() { @@ -3078,10 +3072,11 @@ class PlayState extends MusicBeatState tankWatchtower.dance(); } - // if (isHalloween && FlxG.random.bool(10) && curBeat > lightningStrikeBeat + lightningOffset) - // { - // lightningStrikeShit(); - // } + if (curStage != null) + { + // We're using Eric's stage handler. The stage should know that a beat has been hit. + curStage.onBeatHit(curBeat); + } } var curLight:Int = 0; diff --git a/source/modding/PolymodHandler.hx b/source/modding/PolymodHandler.hx index e0c7009c5..9c8e7939e 100644 --- a/source/modding/PolymodHandler.hx +++ b/source/modding/PolymodHandler.hx @@ -85,6 +85,9 @@ class PolymodHandler // Parsing rules for various data formats. parseRules: buildParseRules(), + + // Parse hxc files and register the scripted classes in them. + useScriptedClasses: true, }); if (loadedModList == null) @@ -140,6 +143,7 @@ class PolymodHandler output.addType("txt", TextFileFormat.LINES); // Ensure script files have merge support. output.addType("hscript", TextFileFormat.PLAINTEXT); + output.addType("hxs", TextFileFormat.PLAINTEXT); // You can specify the format of a specific file, with file extension. // output.addFile("data/introText.txt", TextFileFormat.LINES) diff --git a/source/play/stage/ScriptedStage.hx b/source/play/stage/ScriptedStage.hx index 40bbdb30e..a8124bd30 100644 --- a/source/play/stage/ScriptedStage.hx +++ b/source/play/stage/ScriptedStage.hx @@ -10,8 +10,8 @@ import modding.IHook; * In the meantime though, I want to get stages working just with JSON. * -Eric */ -// @:hscriptClass -// class ScriptedStage extends Stage implements IHook -// { -// // No body needed for this class, it's magic ;) -// } +@:hscriptClass +class ScriptedStage extends Stage implements IHook +{ + // No body needed for this class, it's magic ;) +} diff --git a/source/play/stage/Stage.hx b/source/play/stage/Stage.hx index b6960f5c9..3a2d2b578 100644 --- a/source/play/stage/Stage.hx +++ b/source/play/stage/Stage.hx @@ -1,6 +1,5 @@ package play.stage; -import flixel.FlxObject; import flixel.FlxSprite; import flixel.group.FlxSpriteGroup; import flixel.util.FlxSort; @@ -23,7 +22,7 @@ class Stage extends FlxSpriteGroup implements IHook public var camZoom:Float = 1.0; - var namedProps:Map = new Map(); + var namedProps:Map = new Map(); var characters:Map = new Map(); /** @@ -55,8 +54,20 @@ class Stage extends FlxSpriteGroup implements IHook for (dataProp in _data.props) { trace(' Placing prop: ${dataProp.name} (${dataProp.assetPath})'); - var imagePath = Paths.image(dataProp.assetPath); - var propSprite = new FlxSprite().loadGraphic(imagePath); + + var isAnimated = dataProp.animations.length > 0; + var propSprite = new FlxSprite(); + + if (isAnimated) + { + // Initalize sprite frames. + propSprite.frames = Paths.getSparrowAtlas(dataProp.assetPath); + } + else + { + // Initalize static sprite. + propSprite.loadGraphic(Paths.image(dataProp.assetPath)); + } if (Std.isOfType(dataProp.scale, Array)) { @@ -107,6 +118,36 @@ class Stage extends FlxSpriteGroup implements IHook sort(SortUtil.byZIndex, FlxSort.ASCENDING); } + /** + * A function that gets called every frame. + * @param elapsed The number of + */ + public function onUpdate(elapsed:Float):Void + { + // Override me in your scripted stage to perform custom behavior! + } + + /** + * A function that gets called once per step in the song. + * @param curStep The current step number. + */ + public function onStepHit(curStep:Int):Void + { + // Override me in your scripted stage to perform custom behavior! + } + + /** + * A function that gets called once per beat in the song (once every four steps). + * @param curStep The current beat number. + */ + public function onBeatHit(curBeat:Int):Void + { + // Override me in your scripted stage to perform custom behavior! + } + + /** + * Used by the PlayState to add a character to the stage. + */ public function addCharacter(character:Character, charType:CharacterType) { // Apply position and z-index. @@ -135,6 +176,11 @@ class Stage extends FlxSpriteGroup implements IHook this.add(character); } + /** + * Retrieves a given character from the stage. + * @param id + * @return Character + */ public function getCharacter(id:String):Character { return this.characters.get(id); @@ -142,17 +188,27 @@ class Stage extends FlxSpriteGroup implements IHook public function getBoyfriend():Character { - return this.characters.get("bf"); + return getCharacter('bf'); } public function getGirlfriend():Character { - return this.characters.get("gf"); + return getCharacter('gf'); } public function getDad():Character { - return this.characters.get("dad"); + return getCharacter('dad'); + } + + /** + * Retrieve a specific prop by the name assigned in the JSON file. + * @param name The name of the prop to retrieve. + * @return The corresponding FlxSprite. + */ + public function getNamedProp(name:String):FlxSprite + { + return this.namedProps.get(name); } public function cleanup() diff --git a/source/play/stage/StageData.hx b/source/play/stage/StageData.hx index 0ecf3a8cf..c64acee19 100644 --- a/source/play/stage/StageData.hx +++ b/source/play/stage/StageData.hx @@ -21,19 +21,57 @@ class StageDataParser static final stageCache:Map = new Map(); + static final DEFAULT_STAGE_ID = 'UNKNOWN'; + + /** + * Parses and preloads the game's stage data and scripts when the game starts. + * + * If you want to force stages to be reloaded, you can just call this function again. + */ public static function loadStageCache():Void { + stageCache.clear(); + trace("Loading stage cache..."); + + // + // SCRIPTED STAGES + // + var scriptedStageClassNames:Array = ScriptedStage.listScriptClasses(); + trace(' Instantiating ${scriptedStageClassNames.length} scripted stages...'); + for (stageCls in scriptedStageClassNames) + { + var stage:Stage = ScriptedStage.init(stageCls, DEFAULT_STAGE_ID); + if (stage != null) + { + trace(' Loaded scripted stage: ${stage.stageName}'); + stageCache.set(stage.stageId, stage); + } + else + { + trace(' Failed to instantiate scripted stage class: ${stageCls}'); + } + } + + // + // UNSCRIPTED STAGES + // var stageIdList:Array = DataAssets.listDataFilesInPath('stages/'); - for (stageId in stageIdList) + var unscriptedStageIds:Array = stageIdList.filter(function(stageId:String):Bool + { + return !stageCache.exists(stageId); + }); + trace(' Instantiating ${unscriptedStageIds.length} non-scripted stages...'); + for (stageId in unscriptedStageIds) { var stage:Stage = new Stage(stageId); if (stage != null) { - trace(' Loaded stage data: ${stage.stageName}'); + trace(' Loaded stage data: ${stage.stageName}'); stageCache.set(stageId, stage); } } + trace(' Successfully loaded ${Lambda.count(stageCache)} stages.'); }