<div dir="ltr"><div><br>I was working on the new script intepreter, but got distracted and<br>have now resumed work on script fibres/multitasking (turns out it's<br>related to script profiling).  However the roadblock to working on this is<br>that it requires making tricky decisions about how fibres will act, so<br></div>prepare for rambling without concluding anything.<br><div><br>[To recap: There will be multiple lists of script fibres<br>(coroutines/green threads, each of which is a stack of called scripts<br>that can 'wait' independently). Each group is ordered (the fibres run<br>in a certain order until hitting a wait). There are at least two lists<br>of fibres: the existing main group that runs before the game logic<br>(hero, NPC movement, etc), and the "per-frame" group that runs<br>immediately before drawing the screen (where you should put scripts<br>for parallax and so forth). Battles will effectively also have<br>separate fibre groups, though it would be equivalent to just suspend<br>all out-of-battle fibres.]<br><br>The big undecided issue is determining the order in which fibres execute<br>and other issues with suspending them.<br><br>Currently:<br>1) Newly triggered scripts pause all existing ones<br>2) Multiple scripts triggered on the same tick run in some order<br>   according to historical accident, which is sometimes weird, like<br>   on-keypress scripts running before the new game script, and the<br>   priority of a map autorun script depends on how it is triggered<br>   (new game, stepping on a door, use door textbox conditional,<br>   "teleport to map" are all different!)<br>3) If a script is triggered due to something another does, like "use<br>   menu item" or "advance textbox", then that script runs immediately.<br>4) But a script triggered while not already inside the script<br>   interpreter doesn't run until the *next* tick, unless it's either<br>   an on-keypress, menu item, or menu close script, which get<br>   triggered early so run the same tick.<br><br>In practice 2) and 4) don't seem to be that much of a problem, except<br>for map autorun scripts.  The fact that those are delayed for a tick<br>means we had to add the hacks of delaying music changes and screen<br>fade ins by an extra tick to let the script run first, and made the<br>queued fades cancellable.)  I also hate the fact that some game logic<br>(that for user-editable menus) happens before the script interpreter,<br>and everything else happens afterwards, which causes 4). Maybe that<br>can be fixed at the same time.<br><br>Translating behaviours 1) to 4) to fibres would mean that new fibres<br>always get inserted at the front of the fibre group, and also that<br>when a script gets triggered while inside the interpreter, the<br>interpreter temporarily switches to that fibre until it waits before<br>resuming the normal order. This would probably slightly reduce the<br>difficulty of translating existing scripts to multitasking, because at<br>least the order doesn't change.<br><br>But since multitasking is a major change, it's an opportunity to<br>switch to something more organised.  Since there will eventually be<br>commands for reordering fibres anyway, we don't need to do more than<br>provide a sane default.  The scheduling behaviours you might expect:<br>- a script triggered to initialise something like a map or the game<br>  should run before other scripts for that map.<br>- if you have a whole lot of npc movement (AI) scripts, you probably<br>  want them to all run together, rather than possibly some before and<br>  some after a main logic loop script.  For example, the "create NPC"<br>  command might start a new npc AI fibre, and you probably don't want<br>  that to suspend your current script before you can even call "set<br>  NPC position".<br>  (In reality, it seems best if NPC scripts aren't started until the<br>  engine does NPC movement processing)<br>- a lot of scripts will be cutscenes, and want top priority, so they<br>  can pause other fibres as needed<br>- most scripts will just have an immediate effect, like incrementing a<br>  global, and these should also have priority over already running<br>  scripts like your main loop<br><br>One solution might be to let you optionally assign numerical<br>priorities to fibres, or otherwise (the default) it is set to always<br>run before anything else. This could be an option in Custom next to<br>every script trigger. Then, when a script is triggered:<br>- if it has a numerical priority, insert it in the list of fibres in<br>  the right spot.<br>- if it doesn't, put it in the front<br>- if we're already in the script interpreter, and it's ahead of the<br>  current script, then as a special case this tick, immediately<br>  execute it instead of delaying it for a tick.  Otherwise, we wait<br>  until it gets its normal turn.<br><br>Or maybe when a script is triggered, e.g. by a textbox, it should be<br>run immediately instead of inserted into a fibre group to be run after<br>the engine has finished its logic. If it waits rather than returning,<br>it can go to the front of the main fibre group, to run before the<br>engine logic next tick. This also gives the script 1 tick to place<br>itself in some other fibre group or some other position in the order,<br>and matches how you would expect an event-based game engine to<br>work.<br><br>But then there's the need to provide a way to transition an existing<br>game with a lot of scripts depending on the current suspension<br>behaviour to multitasking.  The solution I wrote on the wiki long ago<br>(that page needs a major overhaul) is to add "blocking script" as an<br>alternative to "plotscript". Only one blocking script can be active at<br>a time.  And I guess only a blocking script would be delayed a tick<br>instead of running immediately.<br><br>And what about commands that cause implicit waits? It seems dubious to<br>make them suspend all other script fibres too. It would be possible to<br>add a backcompat bit to remove implicit waits (or combine it with<br>the bit to enable multitasking, if any).<br><br><br></div></div>