English | 简体中文
Create interactive fictions and visual novels in your Godot game.
Download from here and unzip it to the res://addons folder.
Enable Novelogic in Project Settings > Plugins.
func _ready():
# Novelogic.signal_name.connect(...)
var scenario := Novelogic.load_scenario("res://path/to/scenario.nvs")
Novelogic.start_scenario(scenario)
func _on_button_pressed():
if Novelogic.current_event is ScenarioText or Novelogic.current_event is ScenarioDialogue:
Novelogic.next_event()NovelogicScenario *.nvs files uses four spaces for indentation. DO NOT use tabs.
Export NovelogicScenario *.nvs files in Resources before you export your project.
signal text_started(text: String)This is a single line text.
This is a
multiline
text.
signal dialogue_started(dialogue: String, who: String, how: String, which: String)Alice: This is a single line dialogue.
Alice@smile: This is a
multiline
dialogue.
Alice:voice_01: Can you hear me?
Alice@smile:1godotresuid: It also works!
* Label
<> CallLabel
-> JumpToLabel
* CallLabel
# Return where label/scenario called, or end the scenario
<-
* JumpToLabel
-> JumpToScenario
* JumpIfCondition
-> JumpToScenario :: 1 + 1 == 2
* JumpToScenario
-> scenario@Label
* CallScenarioWithVariables
<> scenario@Label
* JumpToBeginning
-> START
* EndScenario
-> END
# Scenario variables
health = 42
health -= 3 * d(12) + 6
game_over = health <= 0
# Extension variables
GameState.good_ending = true
Support = += -= *= /= **= %= &= |= ^= <<= >>=.
roll = d(6)
if roll == 6:
...
elif roll == 1:
...
else:
...
when:
case roll == 6:
...
case roll == 1:
...
else:
...
when d(7):
case < 1 or case > 7:
Something went wrong...
case 1:
Monday...
case 2, 3, 4, 5:
Tuesday, Wednesday, Thursday, Friday.
else:
Saturday, Sunday!
When when has an argument, cases that start with == != < <= > >= are treated as expressions.
signal choice_started(choices: PackedStringArray)
func handle_choice(choice: String)- THE LEFT BRANCH
flag.left = true
...
- THE RIGHT BRANCH
flag.right = true
...
- THE MAIN ROAD :: flag.left and flag.right
...
- I have no choice
- I have no choice
- I have no choice
...
choices are the available choices. To get all choices, use (Novelogic.current_event as ScenarioChoice).all_choices().
signal input_started(prompt: String, default: String)
func handle_input(input: Variant)player ?> Input your name || Alice
Player: My name is {player}.
answer ?> The Answer to the Ultimate Question of Life, the Universe, and Everything
if answer == "42":
...
else:
...
func _on_dialogue_started(dialogue: String, who: String, how: String, which: String):
dialogue = dialogue.format(Novelogic.scenario_variables)
...input type is Variant, not limited to texts.
class_name CommandExtension
extends NovelogicExtension # (Optional) Access autoloads
func _init():
Novelogic.extension = self
func d(sides: int) -> int:
return randi_range(1, sides)
func wait(time: float) -> Signal:
return Novelogic.get_tree().create_timer(time).timeouti = d(6)
# await is not required
wait(0.5)
AudioManager.play_music("night")
# Support named and optional arguments
@bgm "night" fade_time=0.5 volume=0.6 loop=true
-
The command calls the
snake_casefunction. e.g.@shakeCamerameansshake_camera(). -
Use
!paramandparam!as shortcuts for boolean parameter values. e.g.@shake camera !loop wait!meansshake(camera, false, true). -
Only the first unnamed argument will be the first argument of the function. e.g.
@bgm "night" fade_time=0.5 "day"meansbgm("night", 0.5).