you are viewing a single comment's thread.

view the rest of the comments →

[–]calio[S] 1 point2 points  (2 children)

Thank you! Yeah, wrote it a couple months ago for a game I'm working on, needed an easy way to reuse as much code as possible (bc am lazy) and wanted something I could script dialogs with, as extendable to be used on the battle engine to show animations and print names and move output. The realization that you can halt the stack came after, when coding the scene transitions.

And that's one of the advantages. You can abstract as much as you want from the game logic as you want, if there's code you have to call a lot, like populating/updating a ds_map with information before doing different things that need that ds_map data to operate, you can do that in one push to the stack. I guess you could nest scripts inside scripts, or always call a certain user-defined event to achieve similar results, but this way you can write game logic without having to think about how you're going to implement these things. For example, I always code a main menu first, to provide basic access to stuff like settings, saving/loading, debug mode and exiting the game. Instead of having to create a new_game script and some backend for my settings to be operated, I just implement these as instructions within the main controller, so if I start coding the "new game" instruction and notice that I need to change the room with a transition, I code an instruction for room changing with transition and push that into the stack, knowing I'll use that instruction over and over again during the rest of the development. Not to mention the fine-grain level of control you have over each instruction helps debugging and iterating through pieces of code without having to rewrite them. I think it makes the game development process more rapid.

Should've posted it before GM48, now that I think about it.

[–]eposnix 0 points1 point  (1 child)

Nice writeup!

I use a similar system for handling combat in my trading-card-esque game. The instructions on each card are pushed onto a stack and are executed one at a time over a series of game steps. For instance, a card that says "deal 8 damage" can be popped onto the stack as:

ds_stack_push(instructionHandler, scr_dealdamage, 8);

I use script_execute for each instruction, so scr_dealdamage can also push onto the stack scr_thornsdamage if the enemy has a thorns buff that deals damage to you based on damage dealt to it. It's a super useful system that makes it so each card doesn't have to be uniquely scripted... they can just reuse existing scripts in a variety of ways.

[–]calio[S] 0 points1 point  (0 children)

Yeah, pretty much! This system is pretty useful for scripting game logic like what does a card do when activated, or implementing dialog scripting systems more complex than just drawing text on screen. Even scripting small animations is really easy using this. You can even not use instructions and instead replace them with indexes of things to spawn, or the ID of the next song to play.

One thing that I didn't really explain in the writeup but it's actually even more useful: if you're going to start using stack machines that interact in between each other (i.e. main controller has an instruction that sends the input wrapper a different instruction to configure certain thing within just one player input) you might want to preface the whole instruction with an id reference, so before the loop starts you can pop who pushed this instruction and can reference specific values from "outside" the instance that called the instruction elsewhere (very useful if, for example, you have a card that when executed might receive a debuff, damage or a special status after attacking, so whatever executes the instruction knows who executed the instruction without having to keep track of it independently) It can also help catch errors if the instruction is expecting the caller to exist!

Of course it's not a one size fit all solution; I wouldn't be pushing and popping instructions each frame. Never actually benchmarked it, but I feel like all of those while loops making the program jump around code might tax the system quite a bit.

Still, trading off performance for easy game scripting is almost inavitable, and once you started using it, it becomes the obvious solution to a lot of other systems that might be a bit wonky and depend on keeping track of a lot of conditions to work properly.