Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Crimson Wizard

#2801
The solution to a non-linear story tracking (may be used for linear as well) is a Node Graph. You already sort of have one, only scripted in a workaround way. If scripted literally, it may also solve an issue of having to script story switches "in place".

Following is a very rough outline, but I hope it should illustrate the idea. I apologize for a messy reply beforehand, but I fear to not have enough spare time to write all this thoroughly.




A Node Graph consists of Nodes. A Node is (in pseudocode):

Code: ags

// pseudo code!!!
struct Node {
    ID - some way to identify it when calling a function, a number, a string, and so on.
    Name - a human-readable node name, useful for debugging.
    Description - game specific parameters, as become necessary.
    Links - list of connected node IDs, or whatever allows to reference them.
        There may be separate arrays of Forward links and Backward links too, if you need to let a node know which prerequisite nodes connect to it.
};


You may store these nodes any way you prefer, or any way the current scripting/programming language allows. It may be one huge array, or separate Node objects linked to others using pointers (currently impossible in AGS, sadly).

This kind of structure makes it trivial to setup a complex story. You no longer have to make huge "if/else if" lists when deciding what stage to switch to. Instead, you configure the node list at the start of the game (or when loading some data), where you create and link nodes.

Code: ags

// pseudo code!!!
    NodeGraph.CreateNode("John Story 1");
    NodeGraph.CreateNode("John Story 2");
    NodeGraph.LinkNodes("John Story 1", "John Story 2");


And then have a single function, let's say "CompleteNode", that marks particular node as completed and advance to others, found by this node links.

This is where we meet a question of how to track active nodes. The most dumb straightforward way is to make each Node have "Completed" and "Active" parameters. In which case the progression may look like:

Code: ags

// pseudo code!!!
function CompleteNode( Node node ) {
     node.Active = false;
     node.Completed = true;
     // Check and update each *following* node
     for each fwnode in node.ForwardLinks {
        bool must_activate = true;
        // For each of the forward node, check if all the preceding nodes are completed
        for each bwnode in fwnode.BackwardLinks
            if (!bwnode.Completed) {
                must_activate = false;
            }
        }
        // If all is completed, then activate this forward node
        if (must_activate) {
            fwnode.Active = true;
        }
     }
}


This approach is very simple, but it has one issue: we don't have a easily accessed list of active nodes.
(Actually, there's another: a node graph describes a "current position" in itself, which is conceptually wrong in my opinion, but in practice this does not matter so long as there's only one protagonist that may traverse a graph.)

How this may be solved?

Firstly, you may have a literal array of active nodes, which you update in "CompleteNode".

Secondly, following your current idea of having separate "Stories", a Node may have a Story Branch reference (a "Story branch" it belongs to). If it does, then you may have some kind of a Story Branch object, pointing to the active Node:

Code: ags

// pseudo code!!!
function CompleteNode( Node node ) {
    <............>
        // If all is completed, then activate this forward node
        if (must_activate) {
            fwnode.Active = true;
            StoryBranch story = fwnode.Story;
            story.CurrentNode = fwnode;
        }
}


Then, when testing for the current story stage, you could do something like:

Code: ags

// pseudo code!!!
function GetStoryNodeID( StoryBranch story ) {
     return story.CurrentNode.ID;
}

function DoSomethingForJohn() {
    int id = GetStoryNodeID(eStory_John);
    if (id == eStory_John_Begins) {
        // do this
    } else if (id == eStory_John_Continues) {
        // do that
    }
}


Another approach to tracking active nodes is Node Cursors. Node Cursor (or Story Cursor) is a struct that references current node, and then advanced by "node completed" command, along the links. The problem here is to invent a solution of having multiple cursors restricted to subbranches. So I won't go there now, as above Story references may already suffice (actually, it may be very similar thing).




The biggest advantage of a node graph, in my opinion, is that you don't have to keep the whole story in mind when scripting a reaction to some interaction. Say, if there's an object, and interacting with it advanced a story, all you have to do is to create a new Node for this object and connect it to the story.

Code: ags

// pseudo code!!!

    NodeGraph.CreateNode("Yellow Door Node");
    NodeGraph.LinkNodes("Yellow Door Node", "John Story 10");



Then, when an object is interacted, you simply do "CompleteNode( my_node )", and the whole system will be updated accordingly.
#2802
Usually you'd just add a condition in on_mouse_click, saying that if certain GUIs are shown, then don't process clicks in the room.
#2803
You need to use "else if" in the second case:

Code: ags

if (Knocked == 0)
{
   // code
}
else if (Knocked == 1)
{
   // code
}


In general, each time you write "if" - that's a start of a completely new conditional sequence. Each "if" is tested separately from others. So in your previous code it worked like that:
* Knocked == 0? it is, so set Knocked = 1 and do first action
* Knocked == 1? it is (!), so do second action

"else if" allows to create a list of options, only one of which is selected (the first one which is calculated as true).
#2804
Quote from: Jess McD on Thu 21/07/2022 04:43:37
I tried to use this plug in on my test game, but received an error "undefined token 'video'".  I was attempting to play the video clip on room load before the fade in.

Please post your script where you are using this plugin?

Quote from: Jess McD on Thu 21/07/2022 04:43:37
Is there anything I need to do beyond copying the plug-in file to the ags directory?

You also need to activate the plugin in the game's project tree.
#2805
Full rewritten documentation for this module is now available here:
https://github.com/ivan-mogilko/ags-script-modules/wiki/Drag-&-Drop-module

I tried to explain things in more simple words where possible, and give more practical script examples to illustrate the concepts.
Still might add more real use examples later.
#2806
I guess it's pretty much okay to add Custom Properties to all remaining object types (including GUI, Regions, walkable areas, and whatnot).

I should only note that for "AGS 4" we had an idea of creating a full object hierarchy, where everything goes from same parent type(s), similar to how every gui control inherits GUIControl base type. In that case Get/SetProperty functions might be added to the parent and become available for all at once.
#2807
Fixed above bugs and reuploaded Beta 11 again, but this is probably the last quick fix, because I'm abusing releases. If there are more bugs found, I'll be fixing them later.

Updated to Beta 11
(use download links in the first post)

Editor:
- Added zoom control on Character pane. On View panel the animation preview is now scaling along with the loops.
- Fixed editor silently enabling all available Build Targets when upgrading a pre-3.4.0 project. This could be very inconvenient as there are several of them supported now.
- Fixed scripts were preloaded using incorrect encoding when opening a ANSI/ASCII project.
- Fixed editor was not preventing from entering Character's and AudioClip's ScriptName too long for the engine to handle.
- Fixed View animation preview stopping at frame 100 (if loop contains over 100 frames).
- Fixed script autocomplete sometimes was not updated right after opening a script.
- Fixed extender methods not showing up in the function combolist in the script editor.

Script API:
- Key mod flags are now included packed in the Wait* functions return value.
Please refer to update article in the manual: https://github.com/adventuregamestudio/ags-manual/wiki/Globalfunctions_Wait#global-functions-wait

Engine:
- Fixed Wait* functions returning incorrect mouse button values when skipped by the mouse click.
#2808
Alright, I will have to fix more
#2809
[deleted]
#2810
Quote from: eri0o on Tue 19/07/2022 16:43:37
Erh, just a guess, in game_run, if agskey is 0 we could skip everything in check_keyboard_controls.

The "no key" case is already skipped. But I'm using "CompatKey" for special controls, and it happens to be 0 in some cases when the normal key value is not 0.
#2811
I will have to remake the update and upload again later when I fix this.

Restored old links for now.
#2812
@PaxAnimo, do you have a call to SaveGameDialog anywhere in the script? If yes, please post it here. Or you don't and it just appears for no reason?

Also please tell if you have the "Use old-style keyboard handling" in the general Settings set to true or false? (it's in Backwards Compatibility)

EDIT: Oh, I actually see, it appears on any key...
#2813
Quote from: Pax Animo on Tue 19/07/2022 12:19:05
The download links are not working for me.

Fixed now.
#2814
[deleted]
#2815
Player character is used to tell which room is currently active, there's no way around this in AGS.

Different ways to hide the character forever:
1. "player.on = false;"
2. "player.Transparency = 100".
3. Make a 1x1 transparent sprite, and assign it to view with 4 first loops, each having 1 frame.
#2816
Updated with fixed Mouse.IsButtonDown
https://cirrus-ci.com/build/6534401537343488
#2817
@LauraHunt, here's the fixed build:
https://cirrus-ci.com/task/6597896589017088
#2818
Could you send me a script that causes the problems, and a font?
Also, what is the locale for non-unicode programs set on your system; and what locale is mentioned at the top of the Game.agf, where it sais "encoding"?


Quote from: Laura Hunt on Mon 18/07/2022 05:12:34
The interesting thing is that if I switch to Unicode, the wrong character being displayed is ^, not ?. So it will display Luc^a rather than Luc?a. It's almost as if the engine is not able to render or access the extended ASCII characters after 127 for some reason

This depends on whether the font has the character in a slot, which unicode index corresponds to that letter.
#2819
Quote from: Laura Hunt on Mon 18/07/2022 04:16:07
I've done some more testing, and it turns out it doesn't have to do specifically with custom text properties. Any extended characters in any non-room scripts will display the same issue.

So if I simply do player.Say("My name is Lucía"); in the Global Script, it will get displayed as "My name is Luc?a".

If I change anything in that script, even if it's just adding a commented line like //this is a comment, the issue is fixed temporarily untl the next time I open the engine.

When you say "next time I open the engine", do you mean "editor"?

Overall, this sounds as the problem is in reading the scripts from the file and/or writing them back to file. As when compiling the game editor probably uses the scripts in memory if available, so when you edit the script, the version in memory gets fixed, but if they are not memory and loaded from the file - then a broken version is used.

So, two things should be tested: how the script is saved and how it's loaded. Can you open the script in a separate text editor and see what encoding is it saved in, and if the letter is correct there?

Additionally, do you use any editor plugins, or any extra tools, which may affect a script file?
#2820
@greg, I think this may be fixed by editing Game.agf in any text editor and doing "replace all":
what : <Sound>-1</Sound>
replace to: <Sound>0</Sound>
SMF spam blocked by CleanTalk