diff --git a/README.md b/README.md index d8f7b65..29428d1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -
@sohomsahaun
--- @@ -20,4 +20,4 @@ You can find downloadable .yyz (project file with demo) and .yymps (SnowState on To know more about SnowState, please visit the [Wiki](https://github.com/sohomsahaun/SnowState/wiki)! ## Note -This version of SnowState is for GameMaker Studio 2.3.2 or higher. If you are using earlier version(s) of GameMaker Studio, please check out earlier version(s) of SnowState. +This version of SnowState is for GameMaker Studio 2.3.6 or higher. If you are using earlier version(s) of GameMaker Studio, please check out earlier version(s) of SnowState. diff --git a/SnowState.yyp b/SnowState.yyp index abf7707..2a5844e 100644 --- a/SnowState.yyp +++ b/SnowState.yyp @@ -1,61 +1,63 @@ { "resources": [ - {"id":{"name":"sSmallCloud2","path":"sprites/sSmallCloud2/sSmallCloud2.yy",},"order":3,}, - {"id":{"name":"sSmallCloud3","path":"sprites/sSmallCloud3/sSmallCloud3.yy",},"order":4,}, - {"id":{"name":"sPlayerSwordJump","path":"sprites/sPlayerSwordJump/sPlayerSwordJump.yy",},"order":12,}, - {"id":{"name":"oPlayer","path":"objects/oPlayer/oPlayer.yy",},"order":4,}, - {"id":{"name":"sPlayerSwordAttack2","path":"sprites/sPlayerSwordAttack2/sPlayerSwordAttack2.yy",},"order":8,}, - {"id":{"name":"sSwordEmbeddedMask","path":"sprites/sSwordEmbeddedMask/sSwordEmbeddedMask.yy",},"order":3,}, - {"id":{"name":"sSwordEmbedded","path":"sprites/sSwordEmbedded/sSwordEmbedded.yy",},"order":2,}, - {"id":{"name":"sSwordEffectAirAttack2","path":"sprites/sSwordEffectAirAttack2/sSwordEffectAirAttack2.yy",},"order":1,}, - {"id":{"name":"oCamera","path":"objects/oCamera/oCamera.yy",},"order":0,}, - {"id":{"name":"sPlayerMask","path":"sprites/sPlayerMask/sPlayerMask.yy",},"order":3,}, - {"id":{"name":"Credits","path":"notes/Credits/Credits.yy",},"order":0,}, + {"id":{"name":"oWall","path":"objects/oWall/oWall.yy",},"order":4,}, + {"id":{"name":"sPlayerIdle","path":"sprites/sPlayerIdle/sPlayerIdle.yy",},"order":1,}, {"id":{"name":"sBackTreeRegular","path":"sprites/sBackTreeRegular/sBackTreeRegular.yy",},"order":0,}, - {"id":{"name":"sSmallCloud1","path":"sprites/sSmallCloud1/sSmallCloud1.yy",},"order":2,}, - {"id":{"name":"oSword","path":"objects/oSword/oSword.yy",},"order":5,}, - {"id":{"name":"sSwordEffectAttack3","path":"sprites/sSwordEffectAttack3/sSwordEffectAttack3.yy",},"order":4,}, - {"id":{"name":"stTerrain","path":"sprites/stTerrain/stTerrain.yy",},"order":2,}, - {"id":{"name":"sPlayerSwordAirAttack2","path":"sprites/sPlayerSwordAirAttack2/sPlayerSwordAirAttack2.yy",},"order":6,}, - {"id":{"name":"sSwordMask","path":"sprites/sSwordMask/sSwordMask.yy",},"order":5,}, - {"id":{"name":"sSwordEffectAirAttack1","path":"sprites/sSwordEffectAirAttack1/sSwordEffectAirAttack1.yy",},"order":0,}, - {"id":{"name":"sSwordSpinning","path":"sprites/sSwordSpinning/sSwordSpinning.yy",},"order":6,}, - {"id":{"name":"sWater","path":"sprites/sWater/sWater.yy",},"order":5,}, + {"id":{"name":"sBackTreeRight","path":"sprites/sBackTreeRight/sBackTreeRight.yy",},"order":1,}, {"id":{"name":"tTerrain","path":"tilesets/tTerrain/tTerrain.yy",},"order":5,}, + {"id":{"name":"sPlayerSwordAttack1","path":"sprites/sPlayerSwordAttack1/sPlayerSwordAttack1.yy",},"order":7,}, + {"id":{"name":"bgBigCloud","path":"sprites/bgBigCloud/bgBigCloud.yy",},"order":0,}, + {"id":{"name":"rDemo","path":"rooms/rDemo/rDemo.yy",},"order":0,}, {"id":{"name":"sPlayerFall","path":"sprites/sPlayerFall/sPlayerFall.yy",},"order":0,}, + {"id":{"name":"sPlayerSwordAirAttack1","path":"sprites/sPlayerSwordAirAttack1/sPlayerSwordAirAttack1.yy",},"order":5,}, + {"id":{"name":"__snowstate_config","path":"scripts/__snowstate_config/__snowstate_config.yy",},"order":0,}, + {"id":{"name":"oCloud","path":"objects/oCloud/oCloud.yy",},"order":1,}, + {"id":{"name":"sPlayerMask","path":"sprites/sPlayerMask/sPlayerMask.yy",},"order":3,}, + {"id":{"name":"sSmallCloud3","path":"sprites/sSmallCloud3/sSmallCloud3.yy",},"order":4,}, + {"id":{"name":"sSwordEffectAttack2","path":"sprites/sSwordEffectAttack2/sSwordEffectAttack2.yy",},"order":3,}, + {"id":{"name":"tGrass","path":"tilesets/tGrass/tGrass.yy",},"order":4,}, + {"id":{"name":"sSmallCloud1","path":"sprites/sSmallCloud1/sSmallCloud1.yy",},"order":2,}, + {"id":{"name":"sSwordEmbeddedMask","path":"sprites/sSwordEmbeddedMask/sSwordEmbeddedMask.yy",},"order":3,}, + {"id":{"name":"sPlayerSwordFall","path":"sprites/sPlayerSwordFall/sPlayerSwordFall.yy",},"order":10,}, + {"id":{"name":"SnowState","path":"scripts/SnowState/SnowState.yy",},"order":1,}, {"id":{"name":"stGrass","path":"sprites/stGrass/stGrass.yy",},"order":1,}, - {"id":{"name":"sSwordEffectAttack1","path":"sprites/sSwordEffectAttack1/sSwordEffectAttack1.yy",},"order":2,}, - {"id":{"name":"sPlayerSwordAttack3","path":"sprites/sPlayerSwordAttack3/sPlayerSwordAttack3.yy",},"order":9,}, - {"id":{"name":"sWaterReflection","path":"sprites/sWaterReflection/sWaterReflection.yy",},"order":6,}, - {"id":{"name":"sPlayerSwordThrowSword","path":"sprites/sPlayerSwordThrowSword/sPlayerSwordThrowSword.yy",},"order":14,}, + {"id":{"name":"sPlayerJump","path":"sprites/sPlayerJump/sPlayerJump.yy",},"order":2,}, + {"id":{"name":"Credits","path":"notes/Credits/Credits.yy",},"order":0,}, + {"id":{"name":"sSwordEffectAirAttack2","path":"sprites/sSwordEffectAirAttack2/sSwordEffectAirAttack2.yy",},"order":1,}, + {"id":{"name":"oPlayerT","path":"objects/oPlayerT/oPlayerT.yy",},"order":0,}, {"id":{"name":"Utility","path":"scripts/Utility/Utility.yy",},"order":1,}, - {"id":{"name":"bgSky","path":"sprites/bgSky/bgSky.yy",},"order":1,}, - {"id":{"name":"SnowState","path":"scripts/SnowState/SnowState.yy",},"order":1,}, - {"id":{"name":"sPlayerSwordFall","path":"sprites/sPlayerSwordFall/sPlayerSwordFall.yy",},"order":10,}, - {"id":{"name":"sPlayerRun","path":"sprites/sPlayerRun/sPlayerRun.yy",},"order":4,}, - {"id":{"name":"sPlayerSwordRun","path":"sprites/sPlayerSwordRun/sPlayerSwordRun.yy",},"order":13,}, - {"id":{"name":"sSwordIdle","path":"sprites/sSwordIdle/sSwordIdle.yy",},"order":4,}, - {"id":{"name":"oCloud","path":"objects/oCloud/oCloud.yy",},"order":1,}, - {"id":{"name":"stFrontTreeBody","path":"sprites/stFrontTreeBody/stFrontTreeBody.yy",},"order":0,}, - {"id":{"name":"MACROS","path":"scripts/MACROS/MACROS.yy",},"order":0,}, - {"id":{"name":"sBackTreeRight","path":"sprites/sBackTreeRight/sBackTreeRight.yy",},"order":1,}, + {"id":{"name":"sWater","path":"sprites/sWater/sWater.yy",},"order":5,}, + {"id":{"name":"sPlayerSwordJump","path":"sprites/sPlayerSwordJump/sPlayerSwordJump.yy",},"order":12,}, + {"id":{"name":"oSwordD","path":"objects/oSwordD/oSwordD.yy",},"order":1,}, {"id":{"name":"sPlayerSwordIdle","path":"sprites/sPlayerSwordIdle/sPlayerSwordIdle.yy",},"order":11,}, + {"id":{"name":"sSwordEffectAttack3","path":"sprites/sSwordEffectAttack3/sSwordEffectAttack3.yy",},"order":4,}, + {"id":{"name":"sPlayerSwordThrowSword","path":"sprites/sPlayerSwordThrowSword/sPlayerSwordThrowSword.yy",},"order":14,}, + {"id":{"name":"sSwordEffectAirAttack1","path":"sprites/sSwordEffectAirAttack1/sSwordEffectAirAttack1.yy",},"order":0,}, + {"id":{"name":"sSmallCloud2","path":"sprites/sSmallCloud2/sSmallCloud2.yy",},"order":3,}, + {"id":{"name":"stTerrain","path":"sprites/stTerrain/stTerrain.yy",},"order":2,}, + {"id":{"name":"sPlayerRun","path":"sprites/sPlayerRun/sPlayerRun.yy",},"order":4,}, + {"id":{"name":"sPlayerSwordAttack2","path":"sprites/sPlayerSwordAttack2/sPlayerSwordAttack2.yy",},"order":8,}, {"id":{"name":"sFrontTreeTop","path":"sprites/sFrontTreeTop/sFrontTreeTop.yy",},"order":2,}, - {"id":{"name":"oGame","path":"objects/oGame/oGame.yy",},"order":3,}, - {"id":{"name":"bgBigCloud","path":"sprites/bgBigCloud/bgBigCloud.yy",},"order":0,}, - {"id":{"name":"sPlayerSwordAirAttack1","path":"sprites/sPlayerSwordAirAttack1/sPlayerSwordAirAttack1.yy",},"order":5,}, - {"id":{"name":"sPlayerJump","path":"sprites/sPlayerJump/sPlayerJump.yy",},"order":2,}, - {"id":{"name":"__snowstate_config","path":"scripts/__snowstate_config/__snowstate_config.yy",},"order":0,}, + {"id":{"name":"oCamera","path":"objects/oCamera/oCamera.yy",},"order":0,}, + {"id":{"name":"sSwordEffectAttack1","path":"sprites/sSwordEffectAttack1/sSwordEffectAttack1.yy",},"order":2,}, + {"id":{"name":"sSwordEmbedded","path":"sprites/sSwordEmbedded/sSwordEmbedded.yy",},"order":2,}, {"id":{"name":"tFrontTreeBody","path":"tilesets/tFrontTreeBody/tFrontTreeBody.yy",},"order":3,}, - {"id":{"name":"rDemo","path":"rooms/rDemo/rDemo.yy",},"order":0,}, - {"id":{"name":"sPlayerSwordAttack1","path":"sprites/sPlayerSwordAttack1/sPlayerSwordAttack1.yy",},"order":7,}, - {"id":{"name":"tGrass","path":"tilesets/tGrass/tGrass.yy",},"order":4,}, - {"id":{"name":"sWall","path":"sprites/sWall/sWall.yy",},"order":5,}, + {"id":{"name":"oSwordT","path":"objects/oSwordT/oSwordT.yy",},"order":1,}, + {"id":{"name":"sSwordMask","path":"sprites/sSwordMask/sSwordMask.yy",},"order":5,}, + {"id":{"name":"MACROS","path":"scripts/MACROS/MACROS.yy",},"order":0,}, {"id":{"name":"oEffect","path":"objects/oEffect/oEffect.yy",},"order":2,}, - {"id":{"name":"sSwordEffectAttack2","path":"sprites/sSwordEffectAttack2/sSwordEffectAttack2.yy",},"order":3,}, - {"id":{"name":"sPlayerIdle","path":"sprites/sPlayerIdle/sPlayerIdle.yy",},"order":1,}, - {"id":{"name":"oWall","path":"objects/oWall/oWall.yy",},"order":6,}, + {"id":{"name":"sPlayerSwordRun","path":"sprites/sPlayerSwordRun/sPlayerSwordRun.yy",},"order":13,}, + {"id":{"name":"bgSky","path":"sprites/bgSky/bgSky.yy",},"order":1,}, {"id":{"name":"fDemo","path":"fonts/fDemo/fDemo.yy",},"order":0,}, + {"id":{"name":"stFrontTreeBody","path":"sprites/stFrontTreeBody/stFrontTreeBody.yy",},"order":0,}, + {"id":{"name":"sPlayerSwordAttack3","path":"sprites/sPlayerSwordAttack3/sPlayerSwordAttack3.yy",},"order":9,}, + {"id":{"name":"sSwordSpinning","path":"sprites/sSwordSpinning/sSwordSpinning.yy",},"order":6,}, + {"id":{"name":"sWall","path":"sprites/sWall/sWall.yy",},"order":5,}, + {"id":{"name":"sWaterReflection","path":"sprites/sWaterReflection/sWaterReflection.yy",},"order":6,}, + {"id":{"name":"oGame","path":"objects/oGame/oGame.yy",},"order":3,}, + {"id":{"name":"sSwordIdle","path":"sprites/sSwordIdle/sSwordIdle.yy",},"order":4,}, + {"id":{"name":"sPlayerSwordAirAttack2","path":"sprites/sPlayerSwordAirAttack2/sPlayerSwordAirAttack2.yy",},"order":6,}, + {"id":{"name":"oPlayerD","path":"objects/oPlayerD/oPlayerD.yy",},"order":0,}, ], "Options": [ {"name":"Amazon Fire","path":"options/amazonfire/options_amazonfire.yy",}, @@ -80,19 +82,21 @@ {"roomId":{"name":"rDemo","path":"rooms/rDemo/rDemo.yy",},}, ], "Folders": [ - {"folderPath":"folders/Fonts.yy","order":1,"resourceVersion":"1.0","name":"Fonts","tags":[],"resourceType":"GMFolder",}, - {"folderPath":"folders/Notes.yy","order":7,"resourceVersion":"1.0","name":"Notes","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Demo Objects - Direct.yy","order":6,"resourceVersion":"1.0","name":"Demo Objects - Direct","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Demo Objects - Triggered Transitions.yy","order":7,"resourceVersion":"1.0","name":"Demo Objects - Triggered Transitions","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Fonts.yy","order":3,"resourceVersion":"1.0","name":"Fonts","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Notes.yy","order":9,"resourceVersion":"1.0","name":"Notes","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Objects.yy","order":5,"resourceVersion":"1.0","name":"Objects","tags":[],"resourceType":"GMFolder",}, - {"folderPath":"folders/Rooms.yy","order":6,"resourceVersion":"1.0","name":"Rooms","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Rooms.yy","order":8,"resourceVersion":"1.0","name":"Rooms","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Scripts.yy","order":4,"resourceVersion":"1.0","name":"Scripts","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/SnowState.yy","order":0,"resourceVersion":"1.0","name":"SnowState","tags":[],"resourceType":"GMFolder",}, - {"folderPath":"folders/Sprites.yy","order":2,"resourceVersion":"1.0","name":"Sprites","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Sprites.yy","order":1,"resourceVersion":"1.0","name":"Sprites","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Sprites/Background.yy","order":1,"resourceVersion":"1.0","name":"Background","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Sprites/Player.yy","order":2,"resourceVersion":"1.0","name":"Player","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Sprites/Sword.yy","order":3,"resourceVersion":"1.0","name":"Sword","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Sprites/Sword/Effects.yy","order":1,"resourceVersion":"1.0","name":"Effects","tags":[],"resourceType":"GMFolder",}, {"folderPath":"folders/Sprites/Tree.yy","order":4,"resourceVersion":"1.0","name":"Tree","tags":[],"resourceType":"GMFolder",}, - {"folderPath":"folders/Tile Sets.yy","order":3,"resourceVersion":"1.0","name":"Tile Sets","tags":[],"resourceType":"GMFolder",}, + {"folderPath":"folders/Tile Sets.yy","order":2,"resourceVersion":"1.0","name":"Tile Sets","tags":[],"resourceType":"GMFolder",}, ], "AudioGroups": [ {"targets":-1,"resourceVersion":"1.3","name":"audiogroup_default","resourceType":"GMAudioGroup",}, @@ -102,7 +106,7 @@ ], "IncludedFiles": [], "MetaData": { - "IDEVersion": "2.3.5.589", + "IDEVersion": "2.3.6.595", }, "resourceVersion": "1.4", "name": "SnowState", diff --git a/objects/oCamera/Create_0.gml b/objects/oCamera/Create_0.gml index 9627333..35e27f0 100644 --- a/objects/oCamera/Create_0.gml +++ b/objects/oCamera/Create_0.gml @@ -5,7 +5,7 @@ width = 480; height = 270; targetPos = [x,y]; -targetInst = oPlayer; +targetInst = (DEMO == "D") ? oPlayerD : oPlayerT; rate = 2; // Resize window and app surface diff --git a/objects/oGame/Alarm_0.gml b/objects/oGame/Alarm_0.gml index 6a063b0..eacc204 100644 --- a/objects/oGame/Alarm_0.gml +++ b/objects/oGame/Alarm_0.gml @@ -6,4 +6,4 @@ with (instance_create_layer(_x, _y, "SmallClouds", oCloud)) { hspeed = -random_range(.2, .4); } -alarm[0] = irandom_range(5, 15) * game_get_speed(gamespeed_fps); +alarm[0] = irandom_range(5, 15) * game_get_speed(gamespeed_fps); \ No newline at end of file diff --git a/objects/oGame/Draw_64.gml b/objects/oGame/Draw_64.gml index 4d65961..b80c638 100644 --- a/objects/oGame/Draw_64.gml +++ b/objects/oGame/Draw_64.gml @@ -27,8 +27,9 @@ if (showHistory) { _x = 10; _y = 10; - var _str, _states, _i; - _states = oPlayer.fsm.history_get(); + var _player, _states, _str, _i, _col; + _player = (DEMO == "D") ? oPlayerD : oPlayerT; + _states = _player.fsm.history_get(); _str = "groundAttack3"; draw_set_alpha(.9); @@ -36,11 +37,15 @@ if (showHistory) { c_black, c_black, c_black, c_black, 0); draw_set_alpha(1); - draw_text_outline(_x, _y, "HISTORY", c_white, c_black, _thickness); + draw_text_color(_x, _y, "HISTORY", c_white, c_white, c_white, c_white, 1); _y += 10; + _col = c_white; _i = 0; repeat (array_length(_states)) { - _y += _diff; draw_text_outline(_x, _y, _states[@ _i], c_white, c_black, _thickness); + _str = _states[_i]; + _y += _diff; + draw_text_color(_x, _y, _str, _col, _col, _col, _col, 1); + _col = c_gray; ++_i; } } \ No newline at end of file diff --git a/objects/oGame/Step_0.gml b/objects/oGame/Step_0.gml index bfdd949..75d9955 100644 --- a/objects/oGame/Step_0.gml +++ b/objects/oGame/Step_0.gml @@ -1,2 +1,2 @@ showControls ^= keyboard_check_released(vk_f2); -showHistory ^= keyboard_check_released(ord("H")); \ No newline at end of file +showHistory ^= keyboard_check_released(ord("H")); diff --git a/objects/oPlayer/KeyRelease_82.gml b/objects/oPlayer/KeyRelease_82.gml deleted file mode 100644 index ec79328..0000000 --- a/objects/oPlayer/KeyRelease_82.gml +++ /dev/null @@ -1 +0,0 @@ -game_restart(); \ No newline at end of file diff --git a/objects/oPlayer/Create_0.gml b/objects/oPlayerD/Create_0.gml similarity index 93% rename from objects/oPlayer/Create_0.gml rename to objects/oPlayerD/Create_0.gml index 99d0742..5943ba7 100644 --- a/objects/oPlayer/Create_0.gml +++ b/objects/oPlayerD/Create_0.gml @@ -69,8 +69,6 @@ fsm vspd = 0; }, step: function() { - check_input(); - // If left or right keys are pressed, run if (abs(input.hdir)) { fsm.change("run"); @@ -97,10 +95,7 @@ fsm } } else { // Recall the sword - if (input.recallSword) { - var _sword = instance_find(oSword, 0); - _sword.recall(); - } + recall_sword(); } // Movement @@ -120,8 +115,6 @@ fsm image_speed = 1; }, step: function() { - check_input(); - var _dir = input.hdir; hspd = spd * _dir; @@ -153,10 +146,7 @@ fsm } } else { // Recall the sword - if (input.recallSword) { - var _sword = instance_find(oSword, 0); - _sword.recall(); - } + recall_sword(); } // Movement @@ -185,8 +175,6 @@ fsm image_index = image_number - 1; } - check_input(); - // Throw the sword if (input.throwSword && hasSword) { fsm.change("throwSword"); @@ -194,10 +182,7 @@ fsm } // Recall the sword - if (input.recallSword && !hasSword) { - var _sword = instance_find(oSword, 0); - _sword.recall(); - } + recall_sword(); // Movement apply_gravity(); @@ -229,7 +214,6 @@ fsm image_index = image_number - 1; } - check_input(); var _dir = input.hdir; hspd = spd * _dir; if (_dir != 0) face = _dir; @@ -248,14 +232,11 @@ fsm } } else { // Recall the sword - if (input.recallSword) { - var _sword = instance_find(oSword, 0); - _sword.recall(); - } + recall_sword(); } // Coyote time - if ((fsm.get_time() <= coyoteDuration) && input.jump) { + if ((fsm.get_time(false) <= coyoteDuration) && input.jump) { // Apply only if we were running if (fsm.get_previous_state() == "run") { fsm.change("jump"); @@ -292,8 +273,6 @@ fsm } }, step: function() { - check_input(); - // If attack key is pressed any time during the current state, // go to the next attack state after the animation ends if (input.attack) { @@ -436,4 +415,4 @@ fsm leave: function() { grav = gravGround; } - }); + }); \ No newline at end of file diff --git a/objects/oPlayer/Draw_0.gml b/objects/oPlayerD/Draw_0.gml similarity index 100% rename from objects/oPlayer/Draw_0.gml rename to objects/oPlayerD/Draw_0.gml diff --git a/objects/oPlayerD/KeyRelease_82.gml b/objects/oPlayerD/KeyRelease_82.gml new file mode 100644 index 0000000..006099b --- /dev/null +++ b/objects/oPlayerD/KeyRelease_82.gml @@ -0,0 +1 @@ +game_restart(); diff --git a/objects/oPlayer/Other_25.gml b/objects/oPlayerD/Other_25.gml similarity index 90% rename from objects/oPlayer/Other_25.gml rename to objects/oPlayerD/Other_25.gml index 7367024..6966074 100644 --- a/objects/oPlayer/Other_25.gml +++ b/objects/oPlayerD/Other_25.gml @@ -58,7 +58,7 @@ move_and_collide = function() { }; spawn_sword = function() { - with (instance_create_depth(x+6*face, y-14, depth, oSword)) { + with (instance_create_depth(x+6*face, y-14, depth, oSwordD)) { owner = other.id; face = owner.face; fsm.change("spinning"); @@ -68,4 +68,11 @@ spawn_sword = function() { equip_sword = function() { hasSword = true; sprite_index = get_sprite(); +}; + +recall_sword = function() { + if (!hasSword && input.recallSword) { + var _sword = instance_find(oSwordD, 0); + _sword.recall(); + } }; \ No newline at end of file diff --git a/objects/oPlayer/Other_76.gml b/objects/oPlayerD/Other_76.gml similarity index 100% rename from objects/oPlayer/Other_76.gml rename to objects/oPlayerD/Other_76.gml diff --git a/objects/oPlayerD/Step_0.gml b/objects/oPlayerD/Step_0.gml new file mode 100644 index 0000000..9336c8c --- /dev/null +++ b/objects/oPlayerD/Step_0.gml @@ -0,0 +1,2 @@ +check_input(); +fsm.step(); \ No newline at end of file diff --git a/objects/oPlayer/oPlayer.yy b/objects/oPlayerD/oPlayerD.yy similarity index 93% rename from objects/oPlayer/oPlayer.yy rename to objects/oPlayerD/oPlayerD.yy index cd52362..f64136d 100644 --- a/objects/oPlayer/oPlayer.yy +++ b/objects/oPlayerD/oPlayerD.yy @@ -31,11 +31,11 @@ "properties": [], "overriddenProperties": [], "parent": { - "name": "Objects", - "path": "folders/Objects.yy", + "name": "Demo Objects - Direct", + "path": "folders/Demo Objects - Direct.yy", }, "resourceVersion": "1.0", - "name": "oPlayer", + "name": "oPlayerD", "tags": [], "resourceType": "GMObject", } \ No newline at end of file diff --git a/objects/oPlayerT/Create_0.gml b/objects/oPlayerT/Create_0.gml new file mode 100644 index 0000000..ca0b942 --- /dev/null +++ b/objects/oPlayerT/Create_0.gml @@ -0,0 +1,251 @@ +// Setup +mask_index = sPlayerMask; + +// Declare methods +event_user(15); + +// Sprite management +sprites = {}; +init_sprites( + "idle", "Idle", + "run", "Run", + "jump", "Jump", + "fall", "Fall", + "groundAttack1", "Attack1", + "groundAttack2", "Attack2", + "groundAttack3", "Attack3", + "airAttack1", "AirAttack1", + "airAttack2", "AirAttack2", + "throwSword", "ThrowSword" +); + +effectSprites = {}; +init_effect_sprites( + "groundAttack1", "Attack1", + "groundAttack2", "Attack2", + "groundAttack3", "Attack3", + "airAttack1", "AirAttack1", + "airAttack2", "AirAttack2" +); + +// Variables +spd = 3; +hspd = 0; +vspd = 0; +vspdMax = 15; + +jspd = 12; +gravGround = .6; // Normal gravity +gravAttack = .05; // Low gravity when air attacking +grav = gravGround; + +face = 1; +hasSword = 1; +coyoteDuration = 8; +nextAttack = false; +canAirAttack = true; + +// Input +input = {}; +check_input(); + +// State Machine +fsm = new SnowState("idle"); + +fsm + .history_enable() + .history_set_max_size(20) + .event_set_default_function("draw", function() { + // Draw this no matter what state we are in + // (Unless it is overridden, ofcourse) + draw_sprite_ext(sprite_index, image_index, x, y, face * image_xscale, image_yscale, image_angle, image_blend, image_alpha); + }) + .add("idle", { + enter: function() { + sprite_index = get_sprite(); + image_speed = 1; + + hspd = 0; + vspd = 0; + }, + step: function() { + recall_sword(); + apply_gravity(); + move_and_collide(); + } + }) + .add("run", { + enter: function() { + sprite_index = get_sprite(); + image_speed = 1; + }, + step: function() { + set_movement(); + recall_sword(); + apply_gravity(); + move_and_collide(); + } + }) + .add("jump", { + enter: function() { + sprite_index = get_sprite(); + image_index = 0; + image_speed = 1; + + vspd = -jspd; // Jump + }, + step: function() { + // Play the animation once + if (animation_end()) { + image_speed = 0; + image_index = image_number - 1; + } + + recall_sword(); + apply_gravity(); + move_and_collide(); + } + }) + .add("fall", { + enter: function() { + sprite_index = get_sprite(); + image_index = 0; + image_speed = 1; + + // If I have not done air attack when falling now, activate air attack + // Air attack can be done once when falling + if (fsm.state_is("airAttack", fsm.get_previous_state())) canAirAttack = false; + else canAirAttack = true; + + }, + step: function() { + // Play the animation once + if (animation_end()) { + image_speed = 0; + image_index = image_number - 1; + } + + set_movement(); + recall_sword(); + apply_gravity(); + move_and_collide(); + } + }) + .add("attack", { + enter: function() { + sprite_index = get_sprite(); + image_index = 0; + image_speed = 1; + + nextAttack = false; + + // Create effect + var _sprite = effectSprites[$ fsm.get_current_state()]; + var _face = face; + var _x = x + _face * 8; + with (instance_create_depth(_x, y, depth, oEffect)) { + sprite_index = _sprite; + image_xscale = _face; + } + }, + step: function() { + // If attack key is pressed any time during the current state, + // go to the next attack state after the animation ends + if (input.attack) { + nextAttack = true; + } + } + }) + .add_child("attack", "groundAttack", { + /// @override + enter: function() { + fsm.inherit(); + + // Stop + hspd = 0; + vspd = 0; + }, + }) + .add_child("groundAttack", "groundAttack1") + .add_child("groundAttack", "groundAttack2") + .add_child("groundAttack", "groundAttack3") + .add_child("attack", "airAttack", { + /// @override + enter: function() { + fsm.inherit(); + + // Lower the gravity + grav = gravAttack; + vspd = 0; + }, + /// @override + step: function() { + fsm.inherit(); + + // Go down, slowly + apply_gravity(); + move_and_collide(); + }, + leave: function() { + grav = gravGround; + } + }) + .add_child("airAttack", "airAttack1") + .add_child("airAttack", "airAttack2", { + /// @override + step: function() { + // Go down, slowly + apply_gravity(); + move_and_collide(); + } + }) + .add("throwSword", { + enter: function() { + sprite_index = get_sprite(); + image_index = 0; + image_speed = 1; + + hspd = 0; + vspd = 0; + + // Lower the gravity + grav = gravAttack; + }, + step: function() { + // Movement + apply_gravity(); + move_and_collide(); + }, + throwSword: function() { + if (event_data[? "event_type"] == "sprite event") { + spawn_sword(); + + // Unequip the sword + hasSword = false; + } + }, + leave: function() { + grav = gravGround; + } + }) + .add_transition("run", "idle", "run") + .add_transition("jump", ["idle", "run"], "jump") + .add_transition("attack", ["idle", "run"], "groundAttack1", function() { return hasSword; }) + .add_transition("attack", "fall", "airAttack1", function() { return (hasSword && canAirAttack); }) + .add_transition("throw", ["idle", "run", "jump", "fall"], "throwSword", function() { return hasSword; }) + .add_transition("coyote", "fall", "jump", function() { + return (input.jump && (fsm.get_previous_state() == "run") && (fsm.get_time(false) <= coyoteDuration)); + }) + .add_transition("transition", ["idle", "run"], "fall", function() { return !on_ground(); }) + .add_transition("transition", "jump", "fall", function() { return (vspd >= 0); }) + .add_transition("transition", "run", "idle", function() { return (input.hdir == 0); }) + .add_transition("transition", ["fall", "airAttack"], "idle", function() { return on_ground(); }) + .add_transition("transition", "groundAttack1", "groundAttack2", function() { return (nextAttack && animation_end()); }) + .add_transition("transition", "groundAttack1", "idle", function() { return animation_end(); }) + .add_transition("transition", "groundAttack2", "groundAttack3", function() { return (nextAttack && animation_end()); }) + .add_transition("transition", ["groundAttack2", "groundAttack3"], "idle", function() { return animation_end(); }) + .add_transition("transition", "airAttack1", "airAttack2", function() { return (nextAttack && animation_end()); }) + .add_transition("transition", ["airAttack1", "airAttack2"], "fall", function() { return animation_end(); }) + .add_transition("transition", "throwSword", "fall", function() { return ((fsm.get_previous_state() == "jump") && animation_end()); }) + .add_transition("transition", "throwSword", "fall", function() { return ((fsm.get_previous_state() == "fall") && animation_end()); }) + .add_transition("transition", "throwSword", "idle", function() { return animation_end(); }); diff --git a/objects/oSword/Draw_0.gml b/objects/oPlayerT/Draw_0.gml similarity index 100% rename from objects/oSword/Draw_0.gml rename to objects/oPlayerT/Draw_0.gml diff --git a/objects/oPlayerT/KeyRelease_82.gml b/objects/oPlayerT/KeyRelease_82.gml new file mode 100644 index 0000000..006099b --- /dev/null +++ b/objects/oPlayerT/KeyRelease_82.gml @@ -0,0 +1 @@ +game_restart(); diff --git a/objects/oPlayerT/Other_25.gml b/objects/oPlayerT/Other_25.gml new file mode 100644 index 0000000..1cfa707 --- /dev/null +++ b/objects/oPlayerT/Other_25.gml @@ -0,0 +1,84 @@ +/// @desc Methods + +init_sprites = function() { + var _i = 0; repeat (argument_count div 2) { + var _noSword = asset_get_index("sPlayer" + argument[_i+1]); + if (_noSword == -1) _noSword = sPlayerIdle; + + var _sword = asset_get_index("sPlayerSword" + argument[_i+1]); + if (_sword == -1) _sword = sPlayerSwordIdle; + + sprites[$ argument[_i]] = [_noSword, _sword]; + _i += 2; + } +}; + +init_effect_sprites = function() { + var _i = 0; repeat (argument_count div 2) { + var _effect = asset_get_index("sSwordEffect" + argument[_i+1]); + effectSprites[$ argument[_i]] = _effect; + _i += 2; + } +}; + +get_sprite = function() { + return sprites[$ fsm.get_current_state()][@ hasSword]; +}; + +check_input = function() { + with (input) { + hdir = max(keyboard_check(ord("D")), keyboard_check(vk_right)) - + max(keyboard_check(ord("A")), keyboard_check(vk_left)); + jump = max(keyboard_check_pressed(ord("W")), keyboard_check_pressed(vk_up)); + attack = max(keyboard_check_pressed(ord("Z")), keyboard_check_pressed(vk_space)); + throwSword = max(keyboard_check_pressed(ord("E")), keyboard_check_pressed(ord("X"))); + recallSword = max(keyboard_check_pressed(ord("Q")), keyboard_check_pressed(ord("C"))); + } +}; + +on_ground = function() { + return (place_meeting(x, y+1, oWall)); +}; + +apply_gravity = function() { + vspd = min(vspd+grav, vspdMax); +}; + +set_movement = function() { + var _dir = input.hdir; + hspd = spd * _dir; + if (_dir != 0) face = _dir; +}; + +move_and_collide = function() { + if (place_meeting(x+hspd, y, oWall)) { + while (!place_meeting(x+sign(hspd), y, oWall)) x += sign(hspd); + hspd = 0; + } + x += hspd; + if (place_meeting(x, y+vspd, oWall)) { + while (!place_meeting(x, y+sign(vspd), oWall)) y += sign(vspd); + vspd = 0; + } + y += vspd; +}; + +spawn_sword = function() { + with (instance_create_depth(x+6*face, y-14, depth, oSwordT)) { + owner = other.id; + face = owner.face; + fsm.trigger("t_spin"); + } +}; + +equip_sword = function() { + hasSword = true; + sprite_index = get_sprite(); +}; + +recall_sword = function() { + if (!hasSword && input.recallSword) { + var _sword = instance_find(oSwordT, 0); + _sword.recall(); + } +}; \ No newline at end of file diff --git a/objects/oPlayerT/Other_76.gml b/objects/oPlayerT/Other_76.gml new file mode 100644 index 0000000..e032452 --- /dev/null +++ b/objects/oPlayerT/Other_76.gml @@ -0,0 +1 @@ +fsm.throwSword(); \ No newline at end of file diff --git a/objects/oPlayerT/Step_0.gml b/objects/oPlayerT/Step_0.gml new file mode 100644 index 0000000..7447224 --- /dev/null +++ b/objects/oPlayerT/Step_0.gml @@ -0,0 +1,9 @@ +check_input(); + +fsm.trigger("coyote"); +fsm.step(); +if (abs(input.hdir)) fsm.trigger("run"); +if (input.jump) fsm.trigger("jump"); +if (input.throwSword) fsm.trigger("throw"); +if (input.attack) fsm.trigger("attack"); +fsm.trigger("transition"); \ No newline at end of file diff --git a/objects/oPlayerT/oPlayerT.yy b/objects/oPlayerT/oPlayerT.yy new file mode 100644 index 0000000..e7ada95 --- /dev/null +++ b/objects/oPlayerT/oPlayerT.yy @@ -0,0 +1,41 @@ +{ + "spriteId": { + "name": "sPlayerIdle", + "path": "sprites/sPlayerIdle/sPlayerIdle.yy", + }, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 1, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":25,"eventType":7,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":8,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":82,"eventType":10,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":76,"eventType":7,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "Demo Objects - Triggered Transitions", + "path": "folders/Demo Objects - Triggered Transitions.yy", + }, + "resourceVersion": "1.0", + "name": "oPlayerT", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/objects/oSword/Step_0.gml b/objects/oSword/Step_0.gml deleted file mode 100644 index 65fa6dd..0000000 --- a/objects/oSword/Step_0.gml +++ /dev/null @@ -1 +0,0 @@ -fsm.step(); \ No newline at end of file diff --git a/objects/oSword/Create_0.gml b/objects/oSwordD/Create_0.gml similarity index 100% rename from objects/oSword/Create_0.gml rename to objects/oSwordD/Create_0.gml diff --git a/objects/oSwordD/Draw_0.gml b/objects/oSwordD/Draw_0.gml new file mode 100644 index 0000000..12cc60f --- /dev/null +++ b/objects/oSwordD/Draw_0.gml @@ -0,0 +1 @@ +fsm.draw(); \ No newline at end of file diff --git a/objects/oSword/Other_25.gml b/objects/oSwordD/Other_25.gml similarity index 100% rename from objects/oSword/Other_25.gml rename to objects/oSwordD/Other_25.gml diff --git a/objects/oPlayer/Step_0.gml b/objects/oSwordD/Step_0.gml similarity index 100% rename from objects/oPlayer/Step_0.gml rename to objects/oSwordD/Step_0.gml diff --git a/objects/oSword/oSword.yy b/objects/oSwordD/oSwordD.yy similarity index 92% rename from objects/oSword/oSword.yy rename to objects/oSwordD/oSwordD.yy index 2c2fb17..f501c89 100644 --- a/objects/oSword/oSword.yy +++ b/objects/oSwordD/oSwordD.yy @@ -29,11 +29,11 @@ "properties": [], "overriddenProperties": [], "parent": { - "name": "Objects", - "path": "folders/Objects.yy", + "name": "Demo Objects - Direct", + "path": "folders/Demo Objects - Direct.yy", }, "resourceVersion": "1.0", - "name": "oSword", + "name": "oSwordD", "tags": [], "resourceType": "GMObject", } \ No newline at end of file diff --git a/objects/oSwordT/Create_0.gml b/objects/oSwordT/Create_0.gml new file mode 100644 index 0000000..ff85e13 --- /dev/null +++ b/objects/oSwordT/Create_0.gml @@ -0,0 +1,84 @@ +// Setup +mask_index = sSwordMask; + +// Declare methods +event_user(15); + +// Variables +owner = noone; +spd = 6; +hspd = 0; +face = 1; + +// State Machine +fsm = new SnowState("NULL"); + +fsm + .event_set_default_function("draw", function() { + // Draw this no matter what state we are in + // (Unless it is overridden, ofcourse) + draw_sprite_ext(sprite_index, image_index, x, y, face * image_xscale, image_yscale, image_angle, image_blend, image_alpha); + }) + .add("NULL") + .add("spinning", { + enter: function() { + sprite_index = sSwordSpinning; + mask_index = sSwordMask; + image_speed = 1; + image_index = 0; + + hspd = face * spd; + }, + step: function() { + x += hspd; + } + }) + .add("embedded", { + enter: function() { + sprite_index = sSwordEmbedded; + mask_index = sSwordEmbeddedMask; + image_speed = 1; + image_index = 0; + + // Embed into the wall + while (!place_meeting(x+hspd, y, oWall)) x += hspd; + while (!place_meeting(x+sign(hspd), y, oWall)) x += sign(hspd); + + hspd = 0; + }, + step: function() { + // Play the animation once + if (animation_end()) { + image_speed = 0; + image_index = image_number - 1; + } + } + }) + .add("recall", { + enter: function() { + sprite_index = sSwordSpinning; + mask_index = sSwordMask; + image_speed = 1; + image_index = 0; + + speed = spd; + }, + step: function() { + if (instance_exists(owner)) { + direction = point_direction(x, y, owner.x, owner.y-owner.sprite_height/2); + face = (x > xprevious) * 2 - 1; + if (place_meeting(x, y, owner)) { + owner.equip_sword(); + instance_destroy(); + return; + } + } + } + }) + .add_wildcard_transition("t_spin", "spinning") + .add_wildcard_transition("t_recall", "recall", function() { + return(instance_exists(owner) && fsm.state_is("embedded")); + }) + .add_transition("t_pre_step", "spinning", "embedded", function() { + return place_meeting(x+hspd, y, oWall); + }); \ No newline at end of file diff --git a/objects/oSwordT/Draw_0.gml b/objects/oSwordT/Draw_0.gml new file mode 100644 index 0000000..12cc60f --- /dev/null +++ b/objects/oSwordT/Draw_0.gml @@ -0,0 +1 @@ +fsm.draw(); \ No newline at end of file diff --git a/objects/oSwordT/Other_25.gml b/objects/oSwordT/Other_25.gml new file mode 100644 index 0000000..96caa37 --- /dev/null +++ b/objects/oSwordT/Other_25.gml @@ -0,0 +1,5 @@ +/// @desc Methods + +recall = function() { + fsm.trigger("t_recall"); +}; \ No newline at end of file diff --git a/objects/oSwordT/Step_0.gml b/objects/oSwordT/Step_0.gml new file mode 100644 index 0000000..ad23542 --- /dev/null +++ b/objects/oSwordT/Step_0.gml @@ -0,0 +1,3 @@ +fsm.trigger("t_pre_step"); + +fsm.step(); \ No newline at end of file diff --git a/objects/oSwordT/oSwordT.yy b/objects/oSwordT/oSwordT.yy new file mode 100644 index 0000000..10462f8 --- /dev/null +++ b/objects/oSwordT/oSwordT.yy @@ -0,0 +1,39 @@ +{ + "spriteId": { + "name": "sSwordIdle", + "path": "sprites/sSwordIdle/sSwordIdle.yy", + }, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 1, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":8,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":25,"eventType":7,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "Demo Objects - Triggered Transitions", + "path": "folders/Demo Objects - Triggered Transitions.yy", + }, + "resourceVersion": "1.0", + "name": "oSwordT", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/rooms/rDemo/RoomCreationCode.gml b/rooms/rDemo/RoomCreationCode.gml new file mode 100644 index 0000000..61a5b63 --- /dev/null +++ b/rooms/rDemo/RoomCreationCode.gml @@ -0,0 +1,2 @@ +var _player = (DEMO == "D") ? oPlayerD : oPlayerT; +instance_create_layer(384, 288, "Instances", _player); \ No newline at end of file diff --git a/rooms/rDemo/rDemo.yy b/rooms/rDemo/rDemo.yy index 5c7f1bd..f1bab75 100644 --- a/rooms/rDemo/rDemo.yy +++ b/rooms/rDemo/rDemo.yy @@ -58,9 +58,7 @@ 2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648, 2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648,2147483648, ],},"visible":true,"depth":300,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Grass","tags":[],"resourceType":"GMRTileLayer",}, - {"instances":[ - {"properties":[],"isDnd":false,"objectId":{"name":"oPlayer","path":"objects/oPlayer/oPlayer.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":384.0,"y":288.0,"resourceVersion":"1.0","name":"inst_270EEDC0","tags":[],"resourceType":"GMRInstance",}, - ],"visible":true,"depth":400,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Instances","tags":[],"resourceType":"GMRInstanceLayer",}, + {"instances":[],"visible":true,"depth":400,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Instances","tags":[],"resourceType":"GMRInstanceLayer",}, {"instances":[ {"properties":[],"isDnd":false,"objectId":{"name":"oCamera","path":"objects/oCamera/oCamera.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":32.0,"y":0.0,"resourceVersion":"1.0","name":"inst_66E3BDE1","tags":[],"resourceType":"GMRInstance",}, {"properties":[],"isDnd":false,"objectId":{"name":"oGame","path":"objects/oGame/oGame.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":0.0,"y":0.0,"resourceVersion":"1.0","name":"inst_4A28008F","tags":[],"resourceType":"GMRInstance",}, @@ -95,11 +93,10 @@ {"spriteId":{"name":"bgSky","path":"sprites/bgSky/bgSky.yy",},"colour":4294967295,"x":0,"y":0,"htiled":true,"vtiled":false,"hspeed":0.0,"vspeed":0.0,"stretch":false,"animationFPS":30.0,"animationSpeedType":0,"userdefinedAnimFPS":false,"visible":true,"depth":1100,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Background","tags":[],"resourceType":"GMRBackgroundLayer",}, ], "inheritLayers": false, - "creationCodeFile": "", + "creationCodeFile": "${project_dir}/rooms/rDemo/RoomCreationCode.gml", "inheritCode": false, "instanceCreationOrder": [ {"name":"inst_4A28008F","path":"rooms/rDemo/rDemo.yy",}, - {"name":"inst_270EEDC0","path":"rooms/rDemo/rDemo.yy",}, {"name":"inst_66E3BDE1","path":"rooms/rDemo/rDemo.yy",}, {"name":"inst_1B3D8657","path":"rooms/rDemo/rDemo.yy",}, {"name":"inst_64520098","path":"rooms/rDemo/rDemo.yy",}, diff --git a/scripts/MACROS/MACROS.gml b/scripts/MACROS/MACROS.gml index 29d80f6..d1e1efa 100644 --- a/scripts/MACROS/MACROS.gml +++ b/scripts/MACROS/MACROS.gml @@ -1,3 +1,6 @@ +#macro DEMO "D" // D = Changing States Directly + // T = Changing States Using Triggered Transitions + #macro CAM view_camera[0] // Main camera view #macro CAM_W camera_get_view_width(CAM) // Width of the camera #macro CAM_H camera_get_view_height(CAM) // Height of the camera diff --git a/scripts/SnowState/SnowState.gml b/scripts/SnowState/SnowState.gml index c3f56a2..7332eb4 100644 --- a/scripts/SnowState/SnowState.gml +++ b/scripts/SnowState/SnowState.gml @@ -1,5 +1,5 @@ /** -* SnowState | v2.4.0 +* SnowState | v3.0.0 * Documentation: https://github.com/sohomsahaun/SnowState/wiki * * Author: Sohom Sahaun | @sohomsahaun @@ -7,8 +7,8 @@ /// @func SnowState(initial_state, [execute_enter]) /// @param {string} initial_state Initial state for the state machine -/// @param {bool} [execute_enter] Whether to execute the "enter" event for the initial state (true) or not (false) [Default: true] -function SnowState(_initState) constructor { +/// @param {bool} [execute_enter] Whether to execute the "enter" event for the initial state (true) or not (false) [Default: true] +function SnowState(_initState, _execEnter = true) constructor { #region SnowState System @@ -19,25 +19,31 @@ function SnowState(_initState) constructor { DEFAULT = 4, } - var _execEnter = (argument_count > 1) ? argument[1] : true; - var _owner = other; + enum SNOWSTATE_TRIGGER { + NOT_DEFINED = 0, + DEFINED = 1, + INHERITED = 2, + } - __this = {}; + var _owner = other; + __this = {}; // Container for "private" members with (__this) { - owner = _owner; - states = {}; - stateStartTime = get_timer(); - initState = _initState; - execEnter = _execEnter; - currEvent = undefined; - tempEvent = undefined; - parent = {}; - childQueue = []; - history = array_create(2, undefined); - historyMaxSize = max(0, SNOWSTATE_DEFAULT_HISTORY_MAX_SIZE); - historyEnabled = SNOWSTATE_HISTORY_ENABLED; - defaultEvents = { + owner = _owner; // Context of the SnowState instances + states = {}; // Struct holding states + transitions = {}; // Struct holding transitions + wildTransitions = {}; // Struct holding wildcard transitions + initState = _initState; // Initial state of the SnowState instance + execEnter = _execEnter; // If the "enter" event should be executed by default or not + currEvent = undefined; // Current event + tempEvent = undefined; // Temporary event - Used when changing states + parent = {}; // Inheritance tree + childQueue = []; // Path from current state to it's ancestor(s) + stateStartTime = get_timer(); // Start time of the current state (in microseconds) + history = array_create(2, undefined); // Array holding the history + historyMaxSize = max(0, SNOWSTATE_DEFAULT_HISTORY_MAX_SIZE); // Maximum size of history + historyEnabled = SNOWSTATE_HISTORY_ENABLED; // If history is enabled or not + defaultEvents = { // Default functions for events enter: { exists: SNOWSTATE_EVENT.NOT_DEFINED, func: function() {} @@ -47,7 +53,15 @@ function SnowState(_initState) constructor { func: function() {} }, }; + invalidStateNames = [ // It is what it is + SNOWSTATE_WILDCARD_TRANSITION_NAME, + SNOWSTATE_REFLEXIVE_TRANSITION_NAME, + ]; + /// @param {string} state_name + /// @param {struct} state_struct + /// @param {bool} has_parent + /// @returns {SnowState} self add = method(other, function(_name, _struct, _hasParent) { var _events, _state, _event, _i; var _self = self; @@ -56,9 +70,10 @@ function SnowState(_initState) constructor { _state = create_events_struct(_struct); states[$ _name] = _state; - // Replace all events with parent's + // Update from parent if (_hasParent) { - update_from_parent(_name); + // Get events from parent + update_events_from_parent(_name); // Replace parent's events with defined ones _events = variable_struct_get_names(_struct); @@ -84,18 +99,69 @@ function SnowState(_initState) constructor { } } }); + + /// @param {string} name + /// @param {string} from + /// @param {string} to + /// @param {function} condition + /// @param {function} leave_func + /// @param {function} enter_func + /// @returns {SnowState} self + add_transition = method(other, function(_transitionName, _from, _to, _condition, _leave, _enter) { + with (__this) { + // Define the transition + var _transition = { + from : _from, + to : _to, + condition : _condition, + exists : SNOWSTATE_TRIGGER.DEFINED, + leave : _leave, + enter : _enter + }; + + if (_from == SNOWSTATE_WILDCARD_TRANSITION_NAME) { + // Wildcard transition + if (!variable_struct_exists(wildTransitions, _transitionName)) { + wildTransitions[$ _transitionName] = []; + } + + array_push(wildTransitions[$ _transitionName], _transition); + } else { + // Normal transition + if (!variable_struct_exists(transitions, _from)) { + transitions[$ _from] = {}; + } + if (!variable_struct_exists(transitions[$ _from], _transitionName)) { + transitions[$ _from][$ _transitionName] = []; + } + + array_push(transitions[$ _from][$ _transitionName], _transition); + } + } + + return self; + }) + /// @param {string} event + /// @returns {SnowState} self add_event_method = method(other, function(_event) { var _temp = { exec : __this.execute, event: _event }; self[$ _event] = method(_temp, function() { - exec(event); + var _args = array_create(argument_count); + var _i = 0; repeat(argument_count) { + _args[_i] = argument[_i]; + ++_i; + } + exec(event, undefined, _args); }); return self; }); + /// @param {string} event + /// @returns {SnowState} self assert_event_available = method(other, function(_event) { with (__this) { if (!variable_struct_exists(defaultEvents, _event)) { @@ -105,6 +171,8 @@ function SnowState(_initState) constructor { return self; }); + /// @param {string} event + /// @returns {SnowState} self assert_event_name_valid = method(other, function(_event) { with (__this) { if (variable_struct_exists(defaultEvents, _event)) return true; @@ -115,7 +183,58 @@ function SnowState(_initState) constructor { } return true; }); + + /// @param {string} state_name + /// @param {bool} [show_error] + /// @returns {bool} Whether the name is valid (true), or not (false) + assert_state_name_valid = method(other, function(_state, _error = true) { + with (__this) { + var _func = snowstate_error; + if (!_error) { + _func = SNOWSTATE_DEBUG_WARNING ? snowstate_trace : undefined; + } + + if (!is_string(_state) || (_state == "")) { + if (_func != undefined) _func("State name should be a non-empty string."); + return false; + } + + var _name, _i; + _i = 0; repeat (array_length(invalidStateNames)) { + _name = invalidStateNames[@ _i]; ++_i; + if (_state == _name) { + if (_func != undefined) _func("State name can not be \"", _name, "\"."); + return false; + } + } + + return true; + } + }); + + /// @param {string} transition_name + /// @param {bool} [show_error] + /// @returns {bool} Whether the name is valid (true), or not (false) + assert_transition_name_valid = method(other, function(_state, _error = true) { + with (__this) { + var _func = snowstate_error; + if (!_error) { + _func = SNOWSTATE_DEBUG_WARNING ? snowstate_trace : undefined; + } + + if (!is_string(_state) || (_state == "")) { + if (_func != undefined) _func("Transition name should be a non-empty string."); + return false; + } + + return true; + } + }); + /// @param {string} state_name + /// @param {function} leave_func + /// @param {function} enter_func + /// @returns {SnowState} self change = method(other, function(_state, _leave, _enter) { var _defLeave, _defEnter, _self; _self = self; @@ -152,7 +271,9 @@ function SnowState(_initState) constructor { return self; }); - + + /// @param {struct} state_struct + /// @return {struct} Struct filled with all possible events create_events_struct = method(other, function(_struct) { var _events = {}; var _arr, _i, _event, _defEvent; @@ -186,23 +307,27 @@ function SnowState(_initState) constructor { return _events; }); - - execute = method(other, function(_event, _state) { + + /// @param {string} event + /// @param {string} [state_name] + /// @param {array} [args] + /// @returns {SnowState} self + execute = method(other, function(_event, _state = __this.history[@ 0], _args = []) { with (__this) { - if (_state == undefined) _state = history[@ 0]; - currEvent = _event; - if (!is_state_defined(_state)) { snowstate_error("State \"", _state, "\" is not defined."); return undefined; } - states[$ _state][$ _event].func(); + currEvent = _event; + var _func = states[$ _state][$ _event].func; + with (owner) script_execute_ext(method_get_index(_func), _args); } return self; }); - + + /// @returns {string} The current state get_current_state = method(other, function() { with (__this) { var _state = ((array_length(history) > 0) ? history[@ 0] : undefined); @@ -210,7 +335,9 @@ function SnowState(_initState) constructor { return _state; } }); - + + /// @param {string} state + /// @returns {SnowState} self history_add = method(other, function(_state) { with (__this) { if (historyEnabled) { @@ -228,14 +355,16 @@ function SnowState(_initState) constructor { } return self; }); - + + /// @returns {SnowState} self history_fit_contents = method(other, function() { with (__this) { array_resize(history, max(2, min(historyMaxSize, array_length(history)))); } return self; }); - + + /// @returns {bool} Whether the argument is a method or a function (true), or not (false) is_really_a_method = method(other, function(_method) { try { return is_method(method(undefined, _method)); @@ -244,10 +373,18 @@ function SnowState(_initState) constructor { } }); + /// @param {string} state_name + /// @return {bool} Whether the state is defined (true), or not (false) is_state_defined = method(other, function(_state) { - return (is_string(_state) && variable_struct_exists(__this.states, _state)); + with (__this) { + return (is_string(_state) && variable_struct_exists(states, _state)); + } }); - + + /// @param {string} event + /// @param {function} method + /// @param {int} defined + /// @returns {SnowState} self set_default_event = method(other, function(_event, _method, _defined) { with (__this) { defaultEvents[$ _event] = { @@ -258,7 +395,9 @@ function SnowState(_initState) constructor { } return self; }); - + + /// @param {any} [args] + /// @returns {SnowState} self snowstate_error = method(other, function() { var _str = "[SnowState]\n"; var _i = 0; repeat(argument_count) { @@ -266,20 +405,78 @@ function SnowState(_initState) constructor { } _str += "\n\n\n"; show_error(_str, true); + return self; }); - + + /// @param {any} [args] + /// @returns {SnowState} self snowstate_trace = method(other, function() { var _str = "[SnowState] "; var _i = 0; repeat(argument_count) { _str += string(argument[_i++]); } show_debug_message(_str); + return self; + }); + + /// @param {string} transition_name + /// @param {string} from_state + /// @returns {int} SNOWSTATE_TRIGGER + transition_exists = method(other, function(_transitionName, _from) { + with (__this) { + if (_from == SNOWSTATE_WILDCARD_TRANSITION_NAME) { + // Wildcard transition + if (variable_struct_exists(wildTransitions, _transitionName)) { + return SNOWSTATE_TRIGGER.DEFINED; + } + } else { + // Default + if (variable_struct_exists(transitions, _from) && variable_struct_exists(transitions[$ _from], _transitionName)) { + return SNOWSTATE_TRIGGER.DEFINED; + } + while (variable_struct_exists(parent, _from)) { + _from = parent[$ _from]; + if (variable_struct_exists(transitions, _from) && variable_struct_exists(transitions[$ _from], _transitionName)) { + return SNOWSTATE_TRIGGER.INHERITED; + } + } + } + + return SNOWSTATE_TRIGGER.NOT_DEFINED; + } }); - update_from_parent = method(other, function(_name) { - var _parent, _state, _events, _event, _exists, _parEvent, _i; - + /// @param {array} transitions + /// @param {string} source_state + /// @param {string} trigger_name + /// @returns {bool} Whether the trigger is successful (true), or not (false) + try_triggers = method(other, function(_transitions, _source, _trigger) { with (__this) { + var _transition, _dest, _i; + _i = 0; repeat(array_length(_transitions)) { + _transition = _transitions[@ _i]; ++_i; + + // For reflexive wildcard transitions, change to source + _dest = _transition.to; + if (_dest == SNOWSTATE_REFLEXIVE_TRANSITION_NAME) _dest = _source; + + // Check condition + if (_transition.condition(_trigger, _source, _dest)) { + change(_dest, _transition.leave, _transition.enter); + return true; + } + } + + return false; + } + }); + + /// @param {string} state_name + /// @returns {SnowState} self + update_events_from_parent = method(other, function(_name) { + with (__this) { + var _parent, _state, _events, _event, _exists, _parEvent, _i; + _parent = states[$ parent[$ _name]]; _state = states[$ _name]; @@ -306,11 +503,12 @@ function SnowState(_initState) constructor { return self; }); - + + /// @param {bool} has_parent + /// @returns {SnowState} self update_states = method(other, function(_hasParent) { - var _states, _events, _state, _event, _defEvent, _i, _j; - with (__this) { + var _states, _events, _state, _event, _defEvent, _i, _j; _states = variable_struct_get_names(states); _events = variable_struct_get_names(defaultEvents); @@ -339,26 +537,41 @@ function SnowState(_initState) constructor { #region Basics - add = function(_name, _struct) { - if (_struct == undefined) _struct = {}; - __this.add(_name, _struct, false); - return self; - }; + /// @param {string} state_name + /// @param {struct} [state_struct] + /// @returns {SnowState} self + add = function(_name, _struct = {}) { + with (__this) { + if (!assert_state_name_valid(_name)) return undefined; + + if (!is_struct(_struct)) { + snowstate_error("State struct should be a struct."); + return undefined; + } - change = function(_state, _leave, _enter) { - if (_leave == undefined) _leave = -1; - if (_enter == undefined) _enter = -1; - if (_leave == -1) _leave = leave; - if (_enter == -1) _enter = enter; + if (SNOWSTATE_DEBUG_WARNING && is_state_defined(_name)) { + snowstate_trace("State \"", _name, "\" has been defined already. Replacing the previous definition."); + } + + add(_name, _struct, false); + } + return self; + }; + + /// @param {string} state_name + /// @param {function} [leave_func] + /// @param {function} [enter_func] + /// @returns {SnowState} self + change = function(_state, _leave = leave, _enter = enter) { with (__this) { if (!is_really_a_method(_leave)) { - snowstate_error("Invalid command \"", _leave, "\" in change()."); + snowstate_error("Invalid value for \"leave_func\" in change(). Should be a function."); return undefined; } if (!is_really_a_method(_enter)) { - snowstate_error("Invalid command \"", _enter, "\" in change()."); + snowstate_error("Invalid value for \"enter_func\" in change(). Should be a function."); return undefined; } @@ -367,21 +580,16 @@ function SnowState(_initState) constructor { return self; }; - - state_is = function(_target, _source) { - if (_source == undefined) _source = get_current_state(); + + /// @param {string} state_name + /// @param {string} [state_to_check] + /// @returns {bool} Whether state_name is state_to_check or a parent of state_to_check (true), or not (false) + state_is = function(_target, _source = get_current_state()) { var _state = _source; with (__this) { - if (!is_string(_target) || (_target == "")) { - snowstate_error("State name should be a non-empty string."); - return undefined; - } - - if (!is_string(_source) || (_source == "")) { - snowstate_error("State name should be a non-empty string."); - return undefined; - } + if (!assert_state_name_valid(_target)) return false; + if (!assert_state_name_valid(_source)) return false; while (_state != undefined) { if (_state == _target) return true; @@ -392,36 +600,40 @@ function SnowState(_initState) constructor { return false; }; + /// @returns {array} Array containing the states defined get_states = function() { with (__this) { return variable_struct_get_names(states); } }; + /// @returns {string} The current state get_current_state = function() { with (__this) { return get_current_state(); } }; + /// @returns {string} The previous state get_previous_state = function() { with (__this) { return ((array_length(history) > 1) ? history[@ 1] : undefined); } }; - get_time = function(_seconds) { - if (_seconds == undefined) _seconds = false; - + /// @param {bool} [seconds] + /// @returns {number} Number of steps (or seconds) the current state has been running for + get_time = function(_seconds = true) { with (__this) { var _time = (get_timer()-stateStartTime) * 1/1000000; return (_seconds ? _time : (_time * game_get_speed(gamespeed_fps))); } }; - set_time = function(_time, _seconds) { - if (_seconds == undefined) _seconds = false; - + /// @param {number} time + /// @param {bool} [seconds] + /// @returns {SnowState} self + set_time = function(_time, _seconds = true) { with (__this) { if (!is_real(_time)) { snowstate_error("Time should be a number"); @@ -438,14 +650,14 @@ function SnowState(_initState) constructor { #region Inheritance - add_child = function(_parent, _name, _struct) { - if (_struct == undefined) _struct = {}; - + /// @param {string} parent_state_name + /// @param {string} state_name + /// @param {struct} [state_struct] + /// @return {SnowState} self + add_child = function(_parent, _name, _struct = {}) { with (__this) { - if (!is_string(_parent) || (_parent == "")) { - snowstate_error("State name should be a non-empty string."); - return undefined; - } + if (!assert_state_name_valid(_name)) return undefined; + if (!assert_state_name_valid(_parent)) return undefined; if (!is_state_defined(_parent)) { snowstate_error("State \"", _parent, "\" is not defined."); @@ -456,11 +668,22 @@ function SnowState(_initState) constructor { snowstate_error("Cannot set a state as a parent to itself."); return undefined; } + + if (!is_struct(_struct)) { + snowstate_error("State struct should be a struct."); + return undefined; + } - if (SNOWSTATE_DEBUG_WARNING && variable_struct_exists(parent, _name)) { - if (parent[$ _name] == _parent) { - snowstate_trace("State \"", _name, "\" is already a child of \"", _parent, "\"."); - break; + if (SNOWSTATE_DEBUG_WARNING) { + if (is_state_defined(_name)) { + snowstate_trace("State \"", _name, "\" has been defined already. The previous definition has been replaced."); + } + + if (variable_struct_exists(parent, _name)) { + if (parent[$ _name] == _parent) { + snowstate_trace("State \"", _name, "\" is already a child of \"", _parent, "\"."); + break; + } } } @@ -471,12 +694,15 @@ function SnowState(_initState) constructor { return self; }; + /// @returns {SnowState} self inherit = function() { with (__this) { var _state = history[@ 0]; - if (SNOWSTATE_DEBUG_WARNING && !variable_struct_exists(parent, _state)) { - snowstate_trace("State \"", _state, "\" has no parent state."); + if (!variable_struct_exists(parent, _state)) { + if (SNOWSTATE_DEBUG_WARNING) { + snowstate_trace("State \"", _state, "\" has no parent state."); + } break; } @@ -516,6 +742,9 @@ function SnowState(_initState) constructor { #region Events + /// @param {string} event + /// @param {function} function + /// @returns {SnowState} self event_set_default_function = function(_event, _function) { with (__this) { if (SNOWSTATE_DEBUG_WARNING && (variable_struct_names_count(states) > 0)) { @@ -540,34 +769,176 @@ function SnowState(_initState) constructor { return self; }; + /// NOTE: This function is only meant to be used in change() + /// @returns {function} event_get_current_function = function() { with (__this) { return tempEvent; } } + /// @param {string} event + /// @returns {int} SNOWSTATE_EVENT event_exists = function(_event) { - try { - return __this.states[$ get_current_state()][$ _event].exists; - } catch(_e) {} - - return SNOWSTATE_EVENT.NOT_DEFINED; + with (__this) { + if (!is_string(_event) || (_event == "")) { + if (SNOWSTATE_DEBUG_WARNING) { + snowstate_trace("Event should be a non-empty string."); + } + return SNOWSTATE_EVENT.NOT_DEFINED; + } + + var _state = get_current_state(); + if (!variable_struct_exists(states[$ _state], _event)) return SNOWSTATE_EVENT.NOT_DEFINED; + return states[$ get_current_state()][$ _event].exists; + } }; - + + /// @returns {SnowState} self enter = function() { - __this.execute("enter"); + with (__this) { + execute("enter"); + } + return self; }; + /// @returns {SnowState} self leave = function() { - __this.execute("leave"); + with (__this) { + execute("leave"); + } + return self; }; #endregion + #region Transitions + + /// @param {string} transition_name + /// @param {string/array} source_state + /// @param {string} dest_state + /// @param {function} [condition] + /// @param {function} [leave_func] + /// @param {function} [enter_func] + /// @returns {SnowState} self + add_transition = function(_transitionName, _source, _dest, _condition = function() { return true; }, _leave = leave, _enter = enter) { + with (__this) { + if (!assert_transition_name_valid(_transitionName)) return undefined; + if (!is_string(_dest) || (_dest == "")) { + snowstate_error("State name should be a non-empty string."); + return undefined; + } + if (_dest == SNOWSTATE_WILDCARD_TRANSITION_NAME) { + snowstate_error("Destination state name can not be the same as SNOWSTATE_WILDCARD_TRANSITION_NAME."); + return undefined; + } + + if (!is_really_a_method(_condition)) { + snowstate_error("Invalid value for \"condition\" in add_transition(). Should be a function."); + return undefined; + } + if (!is_really_a_method(_leave)) { + snowstate_error("Invalid value for \"leave_func\" in add_transition(). Should be a function."); + return undefined; + } + if (!is_really_a_method(_enter)) { + snowstate_error("Invalid value for \"enter_func\" in add_transition(). Should be a function."); + return undefined; + } + + if (!is_array(_source)) _source = [_source]; + + var _i, _from; + _i = 0; repeat (array_length(_source)) { + _from = _source[@ _i]; ++_i; + if (!is_string(_from) || (_from == "")) { + if (SNOWSTATE_DEBUG_WARNING) { + snowstate_trace("State name should be a non-empty string. Transition not added."); + } + } else if (_from == SNOWSTATE_REFLEXIVE_TRANSITION_NAME) { + if (SNOWSTATE_DEBUG_WARNING) { + snowstate_trace("Source state name can not be the same as SNOWSTATE_REFLEXIVE_TRANSITION_NAME. Transition not added."); + } + } else { + add_transition(_transitionName, _from, _dest, _condition, _leave, _enter); + } + } + } + + return self; + }; + + /// @param {string} transition_name + /// @param {string} dest_state + /// @param {function} [condition] + /// @param {function} [leave_func] + /// @param {function} [enter_func] + /// @returns {SnowState} self + add_wildcard_transition = function(_transitionName, _dest, _condition = function() { return true; }, _leave, _enter) { + return add_transition(_transitionName, SNOWSTATE_WILDCARD_TRANSITION_NAME, _dest, _condition, _leave, _enter); + }; + + /// @param {string} transition_name + /// @param {string/array} source_state + /// @param {function} [condition] + /// @param {function} [leave_func] + /// @param {function} [enter_func] + /// @returns {SnowState} self + add_reflexive_transition = function(_transitionName, _source, _condition = function() { return true; }, _leave, _enter) { + return add_transition(_transitionName, _source, SNOWSTATE_REFLEXIVE_TRANSITION_NAME, _condition, _leave, _enter); + }; + + /// @param {string} transition_name + /// @param {string} source_state + /// @returns {int} SNOWSTATE_TRIGGER + transition_exists = function(_transitionName, _source) { + with (__this) { + if (!assert_state_name_valid(_source, false)) return false; + if (!assert_transition_name_valid(_transitionName, false)) return false; + + return transition_exists(_transitionName, _source); + } + }; + + /// @param {string} transition_name + /// @returns {bool} Whether the transition has been triggered (true), or not (false) + trigger = function(_transitionName) { + with (__this) { + if (!assert_transition_name_valid(_transitionName)) return false; + + var _currState, _source; + _currState = get_current_state(); + _source = _currState; + + // My triggers + if (transition_exists(_transitionName, _source) == SNOWSTATE_TRIGGER.DEFINED) { + if (try_triggers(transitions[$ _source][$ _transitionName], _currState, _transitionName)) return true; + } + + // Wild triggers + if (transition_exists(_transitionName, SNOWSTATE_WILDCARD_TRANSITION_NAME) == SNOWSTATE_TRIGGER.DEFINED) { + if (try_triggers(wildTransitions[$ _transitionName], _currState, _transitionName)) return true; + } + + // Parent triggers + while (variable_struct_exists(parent, _source)) { + _source = parent[$ _source]; + if (transition_exists(_transitionName, _source) == SNOWSTATE_TRIGGER.DEFINED) { + if (try_triggers(transitions[$ _source][$ _transitionName], _currState, _transitionName)) return true; + } + } + + return false; + } + }; + + #endregion + #region History + /// @returns {SnowState} self history_enable = function() { with (__this) { if (!historyEnabled) { @@ -575,9 +946,11 @@ function SnowState(_initState) constructor { history_fit_contents(); } } + return self; }; + /// @returns {SnowState} self history_disable = function() { with (__this) { if (historyEnabled) { @@ -585,13 +958,19 @@ function SnowState(_initState) constructor { array_resize(history, 2); } } + return self; }; + /// @returns {bool} Whether state history is enabled (true), or not (false) history_is_enabled = function() { - return __this.historyEnabled; + with (__this) { + return historyEnabled; + } }; + /// @param {int} size + /// @returns {SnowState} self history_set_max_size = function(_size) { with (__this) { if (!is_real(_size)) { @@ -610,19 +989,21 @@ function SnowState(_initState) constructor { return self; }; - set_history_max_size = history_set_max_size; + /// @returns {int} The maximum storage capacity of state history history_get_max_size = function() { - return __this.historyMaxSize; + with (__this) { + return historyMaxSize; + } }; - get_history_max_size = history_get_max_size; + /// @returns {array} Array containing the state history history_get = function() { var _prev = get_previous_state(); with (__this) { if (!historyEnabled) { if (SNOWSTATE_DEBUG_WARNING) { - snowstate_trace("History is disabled, can not history_get()."); + snowstate_trace("History is disabled, can not get_history()."); } return []; } @@ -634,22 +1015,32 @@ function SnowState(_initState) constructor { return _arr; } }; - get_history = history_get; #endregion // Initialization with (__this) { - if (!is_string(_initState) || (_initState == "")) { - snowstate_error("State name should be a non-empty string."); - } - + assert_state_name_valid(_initState); history_add(_initState); } +} +// Startup errors +if (!is_string(SNOWSTATE_WILDCARD_TRANSITION_NAME) || (string_length(SNOWSTATE_WILDCARD_TRANSITION_NAME) != 1)) { + var _str = "[SnowState]\n"; + _str += "SNOWSTATE_WILDCARD_TRANSITION_NAME should be a string of length 1." + _str += "\n\n\n"; + show_error(_str, true); +} +if (!is_string(SNOWSTATE_REFLEXIVE_TRANSITION_NAME) || (string_length(SNOWSTATE_REFLEXIVE_TRANSITION_NAME) != 1)) { + var _str = "[SnowState]\n"; + _str += "SNOWSTATE_REFLEXIVE_TRANSITION_NAME should be a string of length 1." + _str += "\n\n\n"; + show_error(_str, true); } -#macro SNOWSTATE_VERSION "v2.4.0" -#macro SNOWSTATE_DATE "11-10-2021" +// Some info +#macro SNOWSTATE_VERSION "v3.0.0" +#macro SNOWSTATE_DATE "15-11-2021" show_debug_message("[SnowState] You are using SnowState by @sohomsahaun (Version: " + string(SNOWSTATE_VERSION) + " | Date: " + string(SNOWSTATE_DATE) + ")"); diff --git a/scripts/__snowstate_config/__snowstate_config.gml b/scripts/__snowstate_config/__snowstate_config.gml index 30e1cf1..a712722 100644 --- a/scripts/__snowstate_config/__snowstate_config.gml +++ b/scripts/__snowstate_config/__snowstate_config.gml @@ -3,14 +3,9 @@ * Documentation: https://github.com/sohomsahaun/SnowState/wiki/Configuration */ -// Whether to show warning messages in Output (true) or not (false) -#macro SNOWSTATE_DEBUG_WARNING true - -// Whether history should be tracked by default (true) or not (false) -#macro SNOWSTATE_HISTORY_ENABLED false - -// Default maxmimum history count -#macro SNOWSTATE_DEFAULT_HISTORY_MAX_SIZE 5 - -// Whether to throw an error when circular inheritance is found (true) or not (false) -#macro SNOWSTATE_CIRCULAR_INHERITANCE_ERROR true \ No newline at end of file +#macro SNOWSTATE_DEBUG_WARNING true // Whether to show warning messages in Output (true) or not (false) +#macro SNOWSTATE_HISTORY_ENABLED false // Whether history should be tracked by default (true) or not (false) +#macro SNOWSTATE_DEFAULT_HISTORY_MAX_SIZE 5 // Default maxmimum history count +#macro SNOWSTATE_CIRCULAR_INHERITANCE_ERROR true // Whether to throw an error when circular inheritance is found (true) or not (false) +#macro SNOWSTATE_WILDCARD_TRANSITION_NAME "*" // Default wildcard transition name +#macro SNOWSTATE_REFLEXIVE_TRANSITION_NAME "=" // Default reflexive transition name \ No newline at end of file diff --git a/sprites/bgBigCloud/bgBigCloud.yy b/sprites/bgBigCloud/bgBigCloud.yy index e9d06cd..4e289d7 100644 --- a/sprites/bgBigCloud/bgBigCloud.yy +++ b/sprites/bgBigCloud/bgBigCloud.yy @@ -42,7 +42,7 @@ "tracks": [ {"name":"frames","spriteId":null,"keyframes":{"Keyframes":[ {"id":"dc3a3b2a-b268-4cca-b9f4-21b05927f91d","Key":0.0,"Length":1.0,"Stretch":false,"Disabled":false,"IsCreationKey":false,"Channels":{"0":{"Id":{"name":"d71a5bdd-0bcb-4831-9ce4-30b6348dc4c1","path":"sprites/bgBigCloud/bgBigCloud.yy",},"resourceVersion":"1.0","resourceType":"SpriteFrameKeyframe",},},"resourceVersion":"1.0","resourceType":"Keyframe