Skip to content

Commit

Permalink
Improve Creating Extensions.
Browse files Browse the repository at this point in the history
Adds more information about saving and loading an Event.
Improves grammar.
  • Loading branch information
CakeVR authored May 30, 2024
1 parent 06e11e1 commit e50e796
Showing 1 changed file with 52 additions and 40 deletions.
92 changes: 52 additions & 40 deletions documentation/creating-extensions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="header-banner ocean">
     <div class="header-label ocean">Creating Extensions</div>
<div class="header-label ocean">Creating Extensions</div>
</div>

*Sometimes Dialogic is just not enough*.
Expand Down Expand Up @@ -28,18 +28,18 @@ The best way to create an extension is to use the extension creator in the dialo

<img src="/media/extension_creator.png" width="600"/>

By clicking the `Create New Extension` button, you can set up an extension folder and custom event script. Enter a name for the new module and select what you would like to add. Then click `Create`.
By clicking the `Create New Extension` button, you can set up an extension folder and a custom event script. Enter a name for the new module and select what you would like to add. Then click `Create`.

---

## 2. The essential part: `index.gd`

The central piece of any extension is the `index.gd` script. It is the only thing your extension is required to have. It has to extend `DialogicIndexer` and can overwrite that class's methods to let Dialogic know about what things to add.
The central piece of any extension is the `index.gd` script. It is the only thing your extension is required to have. It has to extend `DialogicIndexer` and can overwrite that class's methods to let Dialogic know what things to add.
For example, this code registers a custom event:

```gdscript
func _get_events() -> Array:
    return [this_folder.path_join('event_print.gd')]
return [this_folder.path_join('event_print.gd')]
```

*Check out the `DialogicIndexer`'s other methods to learn how to register other things.*
Expand All @@ -56,13 +56,13 @@ Often, events work together with subsystems.

## Your custom event

The Extension creator allows you to get a basic event script. It already has set some values for you.
The Extension Creator allows you to get a basic event script. It already set some values for you.

These are the things you need to do to make your event fully functional:

#### 1. Event settings:

All options of your event should be stored in variables. Define these at the top.
All options for your event should be stored in variables. Define these at the top.

```gdscript
var print_text: String = ""
Expand All @@ -75,12 +75,12 @@ Add whatever should happen when your event is reached in the `_execute()` method

```gdscript
func _execute() -> void:
    print(print_text)
print(print_text)
    if in_game and Dialogic.has_subsystem('Text'):
        Dialogic.Text.update_dialog_text(print_text)
    else:
        finish()
if in_game and Dialogic.has_subsystem('Text'):
Dialogic.Text.update_dialog_text(print_text)
else:
finish()
```

*The `finish()` method lets Dialogic know to continue with the next event.*
Expand All @@ -96,9 +96,14 @@ func _init() -> void:
event_category = "Godot"
```

#### 4. Saving/Loading:
#### 4. Saving & Loading

To implement shortcode saving, return a shortcode identifier in `get_shortcode()` and fill out `get_shortcode_parameters()`:
We will cover working with shortcodes now. They are pretty much the text view of an event inside the timeline.
The following is the shortcode for the Background event.
```
[background arg="res://Graphics/Backgrounds/sunset.png" fade="1.5"]
```
To implement saving your shortcuts, return a shortcode identifier in `get_shortcode()` and fill out `get_shortcode_parameters()`:

```gdscript
func get_shortcode() -> String:
Expand All @@ -114,11 +119,18 @@ func get_shortcode_parameters() -> Dictionary:
```

*The above event might be saved as `[print text="Some text to print" in_game="true"]`*
*You can implement a custom saving syntax by overriding `to_text() -> String`, `from_text(@string)` and `is_valid_event(@string) -> bool`. This is what the text-, character-, choice-, condition-, and variable events do, so take a look at them if this is something you are interested in.*

## 4.1 Custom Saving & Loading Syntax

You can implement custom saving syntax by overriding the function `to_text() -> String` and `from_text(timeline_event: String)`.
The `is_valid_event(event_name: String) -> bool` needs to be override too, if you want to quickly check if the event name is correct.

When is custom saving and loading useful? If your shortcode has a special text syntax or is converting between values, map a word to an integer.
This is what the text-, character-, choice-, condition-, and variable events do, so take a look at them if this is something you are interested in.

#### 5. Editor fields:

Your event is now fully functional, but in the visual editor, it is still only blank. You will need to override the `build_event_editor()` method to define the fields/texts that will show on the event.
Your event is now fully functional, but in the visual editor, it is still blank. You will need to override the `build_event_editor()` method to define the fields/texts that will appear on the event.

```gdscript
func build_event_editor() -> void:
Expand All @@ -136,22 +148,22 @@ If you would like to learn more about events, I strongly suggest looking at the

## What is a subsystem?

A subsystem is a script that contains useful methods for game execution. Subsystems can be accessed as `Dialogic.SubsystemName.method()` when running the game. They should contain all of your extensions game code.
A subsystem is a script that contains useful methods for game execution. Subsystems can be accessed as `Dialogic.SubsystemName.method()` when running the game. They should contain all of your extension's code.
For example, built-in subsystems include `Text, Portraits, Choices, Audio, etc.`. Their methods are used by the built-in events and can be used by your events as well.

Additionally, it's good if a subsystem manages dialogic nodes. This could be done like this:

```gdscript
func update_my_dialogic_nodes(some_setting):
    for node in get_tree().get_nodes_in_group("dialogic_custom_nodes"):
        node.update_something(some_setting)
for node in get_tree().get_nodes_in_group("dialogic_custom_nodes"):
node.update_something(some_setting)
```

## Your custom subsystem

A subsystem is a script inheriting `DialogicSubsystem`. It can override that class's methods.
The most important methods you might want to override are `clear_game_state()` and `load_game_state()` for saving and loading, and `pause()` and `resume()` for pausing.
If you want save-persistent data, store it in the `Dialogic.current_state_info` dictionary.
If you want to save persistent data, store it in the `Dialogic.current_state_info` dictionary.

---

Expand Down Expand Up @@ -180,16 +192,16 @@ Your animation script should look something like this (`bounce_in`, for example)
extends DialogicAnimation
func animate():
    var tween := (node.create_tween() as Tween)
    node.scale = Vector2()
    node.modulate.a = 0
    tween.set_ease(Tween.EASE_IN_OUT)
    tween.set_trans(Tween.TRANS_SINE)
    tween.set_parallel()
    tween.tween_property(node, 'scale', Vector2(1,1), time).set_trans(Tween.TRANS_SPRING).set_ease(Tween.EASE_OUT)
    tween.tween_property(node, 'modulate:a', 1.0, time)
    tween.finished.connect(emit_signal.bind('finished_once'))
var tween := (node.create_tween() as Tween)
node.scale = Vector2()
node.modulate.a = 0
tween.set_ease(Tween.EASE_IN_OUT)
tween.set_trans(Tween.TRANS_SINE)
tween.set_parallel()
tween.tween_property(node, 'scale', Vector2(1,1), time).set_trans(Tween.TRANS_SPRING).set_ease(Tween.EASE_OUT)
tween.tween_property(node, 'modulate:a', 1.0, time)
tween.finished.connect(emit_signal.bind('finished_once'))
```

```admonish note
Expand All @@ -216,9 +228,9 @@ Importantly the name of your animation file will determine if it is a Join, Leav
## What are dialogic nodes?

[Dialogic nodes](dialogic-nodes.md) are nodes that, in some way, execute something visibly, logically or audibly.
They are generally managed by a subsystem and are found because they are automatically added to a group. This makes sure it doesn't matter where in the scene tree or how many of them exist.
They are generally managed by a subsystem and are found because they are automatically added to a group. This makes sure it doesn't matter where they are in the scene tree or how many of them exist.

`DialogicNodes` do not need to be added by the `index.gd` file!
`DialogicNodes` does not need to be added to the `index.gd` file!

---

Expand All @@ -227,14 +239,14 @@ They are generally managed by a subsystem and are found because they are automat
An extension might want to add a dialogic settings editor. This is just a UI scene that has a script inheriting `DialogicSettingsPage`.

- Overwrite some methods (just the ones that you need)
  - `_get_title()`
  - _get_priority() -> return an int that will influence the order of settings pages
  - _refresh() -> whenever the settings are opened
  - _about_to_close() -> whenever the settings editor closes
  - _get_info_section() -> return a node in your scene that will be used as an info section
- `_get_title()`
- _get_priority() -> return an integer that will influence the order of settings pages
- _refresh() -> whenever the settings are opened
- _about_to_close() -> whenever the settings editor closes
- _get_info_section() -> return a node in your scene that will be used as an info section
Settings are usually saved either
  - in the `project settings` in a subcategory of dialogic (e.g. `dialogic/myextension/setting`):
    - `ProjectSettings.set_setting('dialogic/myextension/setting', some_value)`
  - You can also save/load editor settings with `DialogicUtil.set_editor_setting('setting', value)` and `DialogicUtil.get_editor_setting('setting')`.
    - These depend on the project
- in the `project settings` in a subcategory of dialogic (e.g. `dialogic/myextension/setting`):
- `ProjectSettings.set_setting('dialogic/myextension/setting', some_value)`
- You can also save/load editor settings with `DialogicUtil.set_editor_setting('setting', value)` and `DialogicUtil.get_editor_setting('setting')`.
- These depend on the project
- Remember that all scripts in this scene must be in @tool mode.

0 comments on commit e50e796

Please sign in to comment.