Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/coppolaemilio/dialogic into…
Browse files Browse the repository at this point in the history
… add-tween-event
  • Loading branch information
CakeVR committed Sep 30, 2024
2 parents 4abdf71 + ee34954 commit 0bcac3e
Show file tree
Hide file tree
Showing 290 changed files with 7,717 additions and 3,802 deletions.
6 changes: 3 additions & 3 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# These are supported funding model platforms

github: coppolaemilio
patreon: coppolaemilio
github: jowan-spooner
patreon: jowanspooner
open_collective: # Replace with a single Open Collective username
ko_fi: coppolaemilio
ko_fi: jowan_spooner
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
Expand Down
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ If applicable, add screenshots to help explain your problem.

**System (please complete the following information):**
- OS: [e.g. Windows, Linux]
- Godot Version: [e.g. 3.2.3]
- Dialogic Version: [e.g. 1.0]
- Godot Version: [e.g. 4.2.2]
- Dialogic Version: [e.g. 2.0 Alpha 14, please be specific!]

## Solutions

Expand Down
6 changes: 6 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
blank_issues_enabled: true
contact_links:
- name: Dialogic 1 Repository
url: https://github.com/dialogic-godot/dialogic-1/issues
about: Please post anything related to Dialogc 1.x (Godot 3.x) on the Dialogic 1 Repository!

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 - 2023 Emilio Coppola
Copyright (c) 2020 - present Emilio Coppola

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img width="1280" alt="cover" src="https://user-images.githubusercontent.com/2206700/189457799-6327bab0-b085-4421-8640-6a18e395d17d.png">
</p>

<h1 align="center">Dialogic</h1>
<h1 align="center">Dialogic 2</h1>

<p align="center">
Create <b>Dialogs</b>, <b>Visual Novels</b>, <b>RPGs</b>, and <b>manage Characters</b> with Godot to create your Game!
Expand All @@ -28,9 +28,7 @@

Dialogic 2 **requires at least Godot 4.2**.

It's a major rewrite compared to the previous Dialogic 1.

[If you are looking for the Godot 3.5 version you can find it here.](https://github.com/dialogic-godot/dialogic/tree/dialogic-1)
[If you are looking for the Godot 3.x version (Dialogic 1.x) you can find it here.](https://github.com/dialogic-godot/dialogic-1)

## Installation
Follow the installation instructions on our [Getting Started](https://docs.dialogic.pro/getting-started.html#1-installation--activation) documentation.
Expand Down Expand Up @@ -68,9 +66,9 @@ Changelogs will accommodate for these changes and inform you on how to update yo


## Credits
Made by [Emilio Coppola](https://github.com/coppolaemilio) and [Jowan-Spooner](https://github.com/Jowan-Spooner).
Made by [Jowan-Spooner](https://github.com/Jowan-Spooner) and [Emilio Coppola](https://github.com/coppolaemilio).

Contributors: [zaknafean](https://github.com/zaknafean), [thebardsrc](https://github.com/thebardsrc), [and more!](https://github.com/dialogic-godot/dialogic/graphs/contributors).
Contributors: [CakeVR](https://github.com/CakeVR), [Exelia](https://github.com/exelia-antonov), [zaknafean](https://github.com/zaknafean), [and more!](https://github.com/dialogic-godot/dialogic/graphs/contributors).

Special thanks: [Arnaud](https://github.com/arnaudvergnet), [AnidemDex](https://github.com/AnidemDex), [ellogwen](https://github.com/ellogwen), [Tim Krief](https://github.com/timkrief), [Toen](https://twitter.com/ToenAndreMC), Òscar, [Francisco Presencia](https://francisco.io/), [M7mdKady14](https://github.com/M7mdKady14).

Expand Down
40 changes: 40 additions & 0 deletions Tests/Unit/guess_special_resource_test.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
extends GdUnitTestSuite

## Check if transition animations can be accessed with "in", "out, "in out"
## as space-delimited prefix.
func test_fade_in_animation_paths() -> void:
const TYPE := "PortraitAnimation"
var fade_in_1: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade in").get('path', "")
var fade_in_2: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade cross").get('path', "")
var fade_in_3: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade out").get('path', "")

var is_any_fade_in_empty := fade_in_1.is_empty() or fade_in_2.is_empty() or fade_in_3.is_empty()
assert(is_any_fade_in_empty == false, "Fade In/Out animations are empty.")

var are_all_fade_in_equal := fade_in_1 == fade_in_2 and fade_in_2 == fade_in_3
assert(are_all_fade_in_equal == true, "Fade In/Out animations returned different paths.")


## Test if invalid animation paths will return empty strings.
func test_invalid_animation_path() -> void:
const TYPE := "PortraitAnimation"
var invalid_animation_1: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade i").get('path', "")
assert(invalid_animation_1.is_empty() == true, "Invalid animation 1's path is not empty.")


var invalid_animation_2: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade").get('path', "")
assert(invalid_animation_2.is_empty() == true, "Invalid animation 2's path is not empty.")


## Test if invalid types will return empty strings.
func test_invalid_type_path() -> void:
const INVALID_TYPE := "Portait Animation"
var invalid_animation: String = DialogicResourceUtil.guess_special_resource(INVALID_TYPE, "fade in").get('path', "")
assert(invalid_animation.is_empty() == true, "Invalid animation 1's path is not empty.")

const VALID_TYPE := "PortraitAnimation"
var valid_animation_path: String = DialogicResourceUtil.guess_special_resource(VALID_TYPE, "fade in").get('path', "")
assert(valid_animation_path.is_empty() == false, "Valids animation's path is empty.")

assert(not invalid_animation == valid_animation_path, "Valid and invalid animation paths are equal.")

56 changes: 40 additions & 16 deletions addons/dialogic/Core/DialogicGameHandler.gd
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ var Backgrounds := preload("res://addons/dialogic/Modules/Background/subsystem_b
var Portraits := preload("res://addons/dialogic/Modules/Character/subsystem_portraits.gd").new():
get: return get_subsystem("Portraits")

var PortraitContainers := preload("res://addons/dialogic/Modules/Character/subsystem_containers.gd").new():
get: return get_subsystem("PortraitContainers")

var Choices := preload("res://addons/dialogic/Modules/Choice/subsystem_choices.gd").new():
get: return get_subsystem("Choices")

Expand Down Expand Up @@ -151,8 +154,6 @@ var Voice := preload("res://addons/dialogic/Modules/Voice/subsystem_voice.gd").n

## Autoloads are added first, so this happens REALLY early on game startup.
func _ready() -> void:
DialogicResourceUtil.update()

_collect_subsystems()

clear()
Expand All @@ -166,7 +167,7 @@ func _ready() -> void:
## -> returns the layout node
func start(timeline:Variant, label:Variant="") -> Node:
# If we don't have a style subsystem, default to just start_timeline()
if !has_subsystem('Styles'):
if not has_subsystem('Styles'):
printerr("[Dialogic] You called Dialogic.start() but the Styles subsystem is missing!")
clear(ClearFlags.KEEP_VARIABLES)
start_timeline(timeline, label)
Expand All @@ -178,12 +179,12 @@ func start(timeline:Variant, label:Variant="") -> Node:
scene = self.Styles.load_style()
else:
scene = self.Styles.get_layout_node()
scene.show()

if not scene.is_node_ready():
scene.ready.connect(clear.bind(ClearFlags.KEEP_VARIABLES))
scene.ready.connect(start_timeline.bind(timeline, label))
else:
clear(ClearFlags.KEEP_VARIABLES)
start_timeline(timeline, label)

return scene
Expand All @@ -205,10 +206,12 @@ func start_timeline(timeline:Variant, label_or_idx:Variant = "") -> void:
printerr("[Dialogic] There was an error loading this timeline. Check the filename, and the timeline for errors")
return

await (timeline as DialogicTimeline).process()
(timeline as DialogicTimeline).process()

current_timeline = timeline
current_timeline_events = current_timeline.events
for event in current_timeline_events:
event.dialogic = self
current_event_idx = -1

if typeof(label_or_idx) == TYPE_STRING:
Expand All @@ -232,15 +235,15 @@ func preload_timeline(timeline_resource:Variant) -> Variant:
if timeline_resource == null:
printerr("[Dialogic] There was an error preloading this timeline. Check the filename, and the timeline for errors")
return null
else:
await (timeline_resource as DialogicTimeline).process()
return timeline_resource

(timeline_resource as DialogicTimeline).process()

return timeline_resource


## Clears and stops the current timeline.
func end_timeline() -> void:
clear(ClearFlags.TIMELINE_INFO_ONLY)
await clear(ClearFlags.TIMELINE_INFO_ONLY)
_on_timeline_ended()
timeline_ended.emit()

Expand All @@ -256,8 +259,7 @@ func handle_event(event_index:int) -> void:
if not current_timeline:
return

if has_meta('previous_event') and get_meta('previous_event') is DialogicEvent and (get_meta('previous_event') as DialogicEvent).event_finished.is_connected(handle_next_event):
(get_meta('previous_event') as DialogicEvent).event_finished.disconnect(handle_next_event)
_cleanup_previous_event()

if paused:
await dialogic_resumed
Expand Down Expand Up @@ -286,22 +288,34 @@ func handle_event(event_index:int) -> void:
## By using the clear flags from the [member ClearFlags] enum you can specify
## what info should be kept.
## For example, at timeline end usually it doesn't clear node or subsystem info.
func clear(clear_flags := ClearFlags.FULL_CLEAR) -> bool:
func clear(clear_flags := ClearFlags.FULL_CLEAR) -> void:
_cleanup_previous_event()

if !clear_flags & ClearFlags.TIMELINE_INFO_ONLY:
for subsystem in get_children():
if subsystem is DialogicSubsystem:
(subsystem as DialogicSubsystem).clear_game_state(clear_flags)

# Resetting variables
if current_timeline:
current_timeline.clean()
var timeline := current_timeline

current_timeline = null
current_event_idx = -1
current_timeline_events = []
current_state = States.IDLE
return true

# Resetting variables
if timeline:
await timeline.clean()


## Cleanup after previous event (if any).
func _cleanup_previous_event():
if has_meta('previous_event') and get_meta('previous_event') is DialogicEvent:
var event := get_meta('previous_event') as DialogicEvent
if event.event_finished.is_connected(handle_next_event):
event.event_finished.disconnect(handle_next_event)
event._clear_state()
remove_meta("previous_event")

#endregion

Expand All @@ -320,6 +334,9 @@ func get_full_state() -> Dictionary:
current_state_info['current_event_idx'] = -1
current_state_info['current_timeline'] = null

for subsystem in get_children():
(subsystem as DialogicSubsystem).save_game_state()

return current_state_info.duplicate(true)


Expand Down Expand Up @@ -406,4 +423,11 @@ func _on_timeline_ended() -> void:
@warning_ignore("unsafe_method_access")
self.Styles.get_layout_node().hide()


func print_debug_moment() -> void:
if not current_timeline:
return

printerr("\tAt event ", current_event_idx+1, " (",current_timeline_events[current_event_idx].event_name, ' Event) in timeline "', DialogicResourceUtil.get_unique_identifier(current_timeline.resource_path), '" (',current_timeline.resource_path,').')
print("\n")
#endregion
79 changes: 66 additions & 13 deletions addons/dialogic/Core/DialogicResourceUtil.gd
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class_name DialogicResourceUtil
static var label_cache := {}
static var event_cache: Array[DialogicEvent] = []

static var special_resources : Array[Dictionary] = []
static var special_resources := {}


static func update() -> void:
Expand Down Expand Up @@ -156,7 +156,7 @@ static func update_event_cache() -> Array:
for indexer in DialogicUtil.get_indexers():
# build event cache
for event in indexer._get_events():
if not FileAccess.file_exists(event):
if not ResourceLoader.exists(event):
continue
if not 'event_end_branch.gd' in event and not 'event_text.gd' in event:
event_cache.append(load(event).new())
Expand All @@ -173,25 +173,78 @@ static func update_event_cache() -> Array:
################################################################################

static func update_special_resources() -> void:
special_resources = []
special_resources.clear()
for indexer in DialogicUtil.get_indexers():
special_resources.append_array(indexer._get_special_resources())
var additions := indexer._get_special_resources()
for resource_type in additions:
if not resource_type in special_resources:
special_resources[resource_type] = {}
special_resources[resource_type].merge(additions[resource_type])


static func list_special_resources_of_type(type:String) -> Array:
static func list_special_resources(type:String, filter := {}) -> Dictionary:
if special_resources.is_empty():
update_special_resources()
return special_resources.filter(func(x:Dictionary): return type == x.get('type','')).map(func(x:Dictionary): return x.get('path', ''))
if type in special_resources:
if filter.is_empty():
return special_resources[type]
else:
var results := {}
for i in special_resources[type]:
if match_resource_filter(special_resources[type][i], filter):
results[i] = special_resources[type][i]
return results
return {}


static func match_resource_filter(dict:Dictionary, filter:Dictionary) -> bool:
for i in filter:
if not i in dict:
return false
if typeof(filter[i]) == TYPE_ARRAY:
if not dict[i] in filter[i]:
return false
else:
if not dict[i] == filter[i]:
return false
return true


static func guess_special_resource(type: String, string: String, default := {}, filter := {}, ignores:PackedStringArray=[]) -> Dictionary:
if string.is_empty():
return default


static func guess_special_resource(type:String, name:String, default:="") -> String:
if special_resources.is_empty():
update_special_resources()
if name.begins_with('res://'):
return name
for path in list_special_resources_of_type(type):
if DialogicUtil.pretty_name(path).to_lower() == name.to_lower():
return path
var resources := list_special_resources(type, filter)
if resources.is_empty():
printerr("[Dialogic] No ", type, "s found, but attempted to use one.")
return default

if string.begins_with('res://'):
for i in resources.values():
if i.path == string:
return i
printerr("[Dialogic] Unable to find ", type, " at path '", string, "'.")
return default

string = string.to_lower()

if string in resources:
return resources[string]

if not ignores.is_empty():
var regex := RegEx.create_from_string(r" ?\b(" + "|".join(ignores) + r")\b")
for name in resources:
if regex.sub(name, "") == regex.sub(string, ""):
return resources[name]

## As a last effort check against the unfiltered list
if string in special_resources[type]:
push_warning("[Dialogic] Using ", type, " '", string,"' when not supposed to.")
return special_resources[type][string]

printerr("[Dialogic] Unable to identify ", type, " based on string '", string, "'.")
return default

#endregion
Expand Down
Loading

0 comments on commit 0bcac3e

Please sign in to comment.