Well, I think the simple answer is that you need a different way to start dialogue. Namely, you need to wrap your result up in some sort of trigger, ie:
Then, if you need to start a dialogue from somewhere else, you can do so by calling that object. As for how to get the id of something, well, there are a lot of options, but GMS2 provides a constant for every object that is in the room when it is created, it's usually something like "inst_64FAS99" and you can use that,
GML:
start_dialogue( inst_64FAS99 );
Now, this does not make a case for the merits of this system or any potential pitfalls (ie: hard-linking can be problematic while the game is in development), so a "soft" solution would be to give every object a flag, like a name, you can check for. You can use the with() statement to iterate over a type of object (including child objects). For example, you can use with() to iterate over the objects and look for your flag, if found use that to start your dialogue:
GML:
with ( oPerson ) {
if ( objectName == "start_dialogue" ) {
start_dialogue( id );
break;
}
}
This is a "safer" method because if there
is no object with the proper flag, it will just be ignored altogether (though may could lead to troubleshooting why it isn't firing). However, it is simple because it will check all of the given objects, and allows you to easily add or change starting dialogues since you just need to include this flag on an object to make it fire. However, this also relies on ensuring EVERY object of type oPerson, in the above example,
has this variable defined or it will crash. This is generally as easy as defining a variable as part of the object, GMS2 Object Variables even allow you to edit them directly in the room editor, but if you aren't used to this kind of programming pattern you might find it awkward at first.
All of that said, it's probably best to not couple your dialogue system
directly to the objects themselves. Rather than the above example, perhaps using the same variable method you instead have the objects call something like:
GML:
if ( player_activates_me ) {
start_dialogue( myDialogue );
}
What "myDialogue" is will be up to you to decide, but it allows you to get rid of the previous pattern and start dialogue by simply calling something like:
GML:
start_dialogue( DIALOGUE.ROOM_1_START );
Then, your object-initiated dialogue and your room start dialogue is handled in the same way, but don't require intermediate objects to function. After all, the purpose of the NPC or sign in this case is to start a dialogue when the player interacts with it. That isn't the function of the dialogue system: the dialogue system should just handle the opening, closing and user input for the boxes themselves. I imagine you are doing it this way because you are probably attaching some dialogue information to the object itself, but It might be advantageous to store that information somewhere, and just allow it to be looked up. As an example we might have something like:
GML:
// when your game starts, you create some dialogues
dialogueLibrary = ds_map_create();
dialogue_create( "cindy.hello.1", spr_cindy, 0, "Cindy", "Hello!" );
GML:
/// @func dialogue_create( id, portrait_sprite, portrait_index, name, lines... )
/// @params portrait_sprite,portrait_index,name
var _new_dialogue = ds_map_create();
ds_map_add( _new_dialogue, "sprite", argument1 );
ds_map_add( _new_dialogue, "index", argument2 );
ds_map_add( _new_dialogue, "name", argument3 );
ds_map_add( _new_dialogue, "text", argument4 );
ds_map_add( dialogueLibrary, argument0, _new_dialogue );
In this way you create dialogue to be stored in this map somewhere, and you can get at it by providing that "id", in this case "cindy.hello.1"
GML:
start_dialogue( "cindy.hello.1" );
GML:
/// @func start_dialogue( key )
/// @params key
with ( instance_create_layer( 24, 24, "Speech", oDialogueBox ) {
var _dialogue = Game.dialogueLibrary[? argument0 ];
// the given key didn't exist in the library
if ( is_undefined( _dialogue ) ) {
// provide some generic text or an error message
} else {
sprite_index = _dialogue[? "sprite" ];
image_index = _dialogue[? "index" ];
speakerName = _dialogue[? "name" ];
dialogueText = _dialogue[? "text" ];
}
// return the id of the new dialogue box if successful so you can manipulate it from the calling code if needed
return id;
}
Some food for thought. I've left out a few things, this is hardly copy-paste, but should illustrate how you can store your text somewhere else and then get at it to create your boxes using a key, instead of relying on an object in your room to hold that information. As a nice little bonus, this behavior also makes it a little easier to proofread your text because you don't have to go looking through different objects to find it, you'll have some library of text you can more easily peruse.