Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 49fa5d08de | |||
| 1ee9dea9f6 | |||
| d5fa2f88be | |||
| 8676bbb2f6 | |||
| 6e998810b6 | |||
| c96be7467e | |||
| 6aa7530502 | |||
| d7ac1c6c22 | |||
| 0170a53b5a | |||
| abc33fd06c | |||
| 2fbeb93018 | |||
| 9253a78a06 | |||
| 0008b16d48 | |||
| 8e0dced918 | |||
| 2e21fb7e98 | |||
| b69191e7f7 | |||
| 8f75b5b644 | |||
| 6275bea52c | |||
| 279cac22ee | |||
| e88ba2e1ef | |||
| f01143e887 | |||
| 18711776bb | |||
| 0f246825fc | |||
| 19e30dd0b8 | |||
| 730c4999d7 | |||
| cfe604d3b7 | |||
| ad16b86171 | |||
| 5ee295256b | |||
| ab23d41496 | |||
| ae0944fe00 | |||
| 486cfb5546 | |||
| b92eb909ad | |||
| d2c7302ab2 | |||
| 5affc48dc5 | |||
| cdb6b83124 | |||
| a4f9511892 | |||
| 7a3e96d679 | |||
| e38c391e1c | |||
| eaedf8c396 | |||
| ffa20bbdf8 | |||
| b77b6e3a52 | |||
| c7d56301fc |
@@ -1,6 +1,12 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArea3D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F8a54226fa2e1c9371a8091f24cfd744aef11fe6869527dc23b9b837623a29b9_003FArea3D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAudioStreamPlayer2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F848324b1c23114c3f5e8bbb5a42c4ade394c59a7a7a133a66b76581ca571_003FAudioStreamPlayer2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptProperties_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F4298b0f293f987511fc1b7956ee691fd778f8378_003FBabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptProperties_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EQuest_002EQuestListItemUi_005FScriptMethods_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F48fad7e7f3c9e292b3fdbddf9d363f0d1752aa_003FBabushka_002Escripts_002ECSharp_002ECommon_002EQuest_002EQuestListItemUi_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACastHelpers_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F3c92637ae2e83da0a63791071c41eae291d594156062866d8621b7ed7245c_003FCastHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACastHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd111abf504bf42b5968a609b168fd093b2e200_003Fbb_003F1c116fcd_003FCastHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACharacterBody2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fbba0bbd7a98ee58286e9484fbe86e01afff6232283f6efd3556eb7116453_003FCharacterBody2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Ff1d69ec2da76ccf9bc8a75c8e0fdca9a7ba1adf8c8c9d5047e2fa5991c02eca_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fjonathan_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe37dc1faf08a4d5ea030ad59bdf77522523400_003Fd4_003Fbd338aeb_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Ff1d69ec2da76ccf9bc8a75c8e0fdca9a7ba1adf8c8c9d5047e2fa5991c02eca_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceLoader_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F9f4e8eb124d11f8219cb513a19bed22b2120ed29f9d6785ba56e3367b48d581_003FResourceLoader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fc7102cd0ffb8973777e61b1942c3fffac7e14016a511d055c3adf73ff91748_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
@@ -0,0 +1,22 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if !ProjectSettings.has_setting("babushka/hacks/speed_hack"):
|
||||
ProjectSettings.set_setting("babushka/hacks/speed_hack",-1)
|
||||
|
||||
var property_info = {
|
||||
"name": "babushka/hacks/speed_hack",
|
||||
"type": TYPE_FLOAT,
|
||||
"hint": PROPERTY_HINT_RANGE,
|
||||
"hint_string": "-1,20,0.5"
|
||||
}
|
||||
|
||||
ProjectSettings.add_property_info(property_info)
|
||||
ProjectSettings.set_initial_value("babushka/hacks/speed_hack",-1)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
# Clean-up of the plugin goes here.
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://buwfplh0xji8q
|
||||
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="BabushkaHelpers"
|
||||
description=""
|
||||
author="Cozy Raven"
|
||||
version=""
|
||||
script="babushkahelpers.gd"
|
||||
@@ -95,6 +95,8 @@ func _make_visible(visible:bool) -> void:
|
||||
func _save_external_data() -> void:
|
||||
if _editor_view_and_manager_exist():
|
||||
editor_view.editors_manager.save_current_resource()
|
||||
|
||||
DialogicResourceUtil.update_directory('.tres')
|
||||
|
||||
|
||||
func _get_unsaved_status(for_scene:String) -> String:
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
@tool
|
||||
extends DialogicEvent
|
||||
class_name DialogicQuestActivateEvent
|
||||
|
||||
|
||||
# Define properties of the event here
|
||||
var quest_resource: String
|
||||
|
||||
func _execute() -> void:
|
||||
var resource = ResourceLoader.load(quest_resource)
|
||||
QuestManager.ChangeQuestStatus(resource,QuestEventUtils.QuestStatus.AVAILABLE)
|
||||
QuestManager.SetFollowQuest(resource)
|
||||
finish() # called to continue with the next event
|
||||
|
||||
|
||||
#region INITIALIZE
|
||||
################################################################################
|
||||
# Set fixed settings of this event
|
||||
func _init() -> void:
|
||||
event_name = "Activate Quest"
|
||||
event_category = "Quest"
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region SAVING/LOADING
|
||||
################################################################################
|
||||
func get_shortcode() -> String:
|
||||
return "quest_activate"
|
||||
|
||||
func get_shortcode_parameters() -> Dictionary:
|
||||
return {
|
||||
#param_name : property_info
|
||||
"quest_resource" : {"property": "quest_resource", "default": ""},
|
||||
}
|
||||
|
||||
# You can alternatively overwrite these 3 functions: to_text(), from_text(), is_valid_event()
|
||||
#endregion
|
||||
|
||||
|
||||
#region EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func build_event_editor() -> void:
|
||||
add_header_label("Activate Quest")
|
||||
add_header_edit(
|
||||
"quest_resource",
|
||||
ValueType.DYNAMIC_OPTIONS,
|
||||
{
|
||||
"mode":2,
|
||||
"suggestions_func":QuestEventUtils.quest_resource_suggestrions
|
||||
})
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://br3a7napsjmg3
|
||||
@@ -0,0 +1,55 @@
|
||||
@tool
|
||||
extends DialogicEvent
|
||||
class_name DialogicQuestCompleteEvent
|
||||
|
||||
|
||||
# Define properties of the event here
|
||||
var quest_resource: String
|
||||
|
||||
func _execute() -> void:
|
||||
var resource = ResourceLoader.load(quest_resource)
|
||||
QuestManager.ChangeQuestStatus(resource,QuestEventUtils.QuestStatus.DONE)
|
||||
QuestManager.SetFollowQuest(null)
|
||||
finish() # called to continue with the next event
|
||||
|
||||
|
||||
#region INITIALIZE
|
||||
################################################################################
|
||||
# Set fixed settings of this event
|
||||
func _init() -> void:
|
||||
event_name = "Complete Quest"
|
||||
event_category = "Quest"
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region SAVING/LOADING
|
||||
################################################################################
|
||||
func get_shortcode() -> String:
|
||||
return "quest_complete"
|
||||
|
||||
func get_shortcode_parameters() -> Dictionary:
|
||||
return {
|
||||
#param_name : property_info
|
||||
"quest_resource" : {"property": "quest_resource", "default": ""},
|
||||
}
|
||||
|
||||
# You can alternatively overwrite these 3 functions: to_text(), from_text(), is_valid_event()
|
||||
#endregion
|
||||
|
||||
|
||||
#region EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func build_event_editor() -> void:
|
||||
add_header_label("Complete Quest")
|
||||
add_header_edit(
|
||||
"quest_resource",
|
||||
ValueType.DYNAMIC_OPTIONS,
|
||||
{
|
||||
"mode":2,
|
||||
"suggestions_func":QuestEventUtils.quest_resource_suggestrions
|
||||
})
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://c8mtjwpe7c0h
|
||||
@@ -0,0 +1,163 @@
|
||||
@tool
|
||||
extends DialogicEvent
|
||||
class_name DialogicQuestConditionEvent
|
||||
|
||||
## Event that allows branching a timeline based on a condition.
|
||||
|
||||
#enum ConditionTypes {IF, ELIF, ELSE}
|
||||
|
||||
### Settings
|
||||
## condition type (see [ConditionTypes]). Defaults to if.
|
||||
#var condition_type := ConditionTypes.IF
|
||||
## The condition as a string. Will be executed as an Expression.
|
||||
#var condition := ""
|
||||
var quest_resource: String
|
||||
var compare_status: QuestEventUtils.QuestStatusOrActive
|
||||
|
||||
################################################################################
|
||||
## EXECUTE
|
||||
################################################################################
|
||||
|
||||
func _execute() -> void:
|
||||
var resource = ResourceLoader.load(quest_resource)
|
||||
|
||||
var result: bool
|
||||
if compare_status == QuestEventUtils.QuestStatusOrActive.ACTIVE:
|
||||
result = QuestManager.GetFollowQuest() == resource
|
||||
elif compare_status == QuestEventUtils.QuestStatusOrActive.NOT_ACTIVE:
|
||||
result = QuestManager.GetFollowQuest() != resource
|
||||
else:
|
||||
result = QuestManager.GetQuestStatus(resource).status == compare_status
|
||||
|
||||
if not result:
|
||||
var idx: int = dialogic.current_event_idx
|
||||
var ignore := 1
|
||||
while true:
|
||||
idx += 1
|
||||
if not dialogic.current_timeline.get_event(idx) or ignore == 0:
|
||||
break
|
||||
elif dialogic.current_timeline.get_event(idx).can_contain_events:
|
||||
ignore += 1
|
||||
elif dialogic.current_timeline.get_event(idx) is DialogicEndBranchEvent:
|
||||
ignore -= 1
|
||||
|
||||
dialogic.current_event_idx = idx-1
|
||||
finish()
|
||||
|
||||
|
||||
## only called if the previous event was an end-branch event
|
||||
## return true if this event should be executed if the previous event was an end-branch event
|
||||
func should_execute_this_branch() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
################################################################################
|
||||
## INITIALIZE
|
||||
################################################################################
|
||||
|
||||
func _init() -> void:
|
||||
event_name = "Quest Condition"
|
||||
set_default_color('Color3')
|
||||
event_category = "Quest"
|
||||
event_sorting_index = 1
|
||||
can_contain_events = true
|
||||
|
||||
|
||||
# return a control node that should show on the END BRANCH node
|
||||
func get_end_branch_control() -> Control:
|
||||
return load(get_script().resource_path.get_base_dir().path_join('ui_quest_condition_end.tscn')).instantiate()
|
||||
|
||||
################################################################################
|
||||
## SAVING/LOADING
|
||||
################################################################################
|
||||
|
||||
func to_text() -> String:
|
||||
return 'ifquest ' + quest_resource + ', ' + str(compare_status) + ':'
|
||||
|
||||
|
||||
func from_text(string:String) -> void:
|
||||
#if string.strip_edges().begins_with('if'):
|
||||
# condition = string.strip_edges().trim_prefix('if ').trim_suffix(':').strip_edges()
|
||||
# condition_type = ConditionTypes.IF
|
||||
var strings:Array[String]
|
||||
strings.assign(string.strip_edges().trim_prefix('ifquest ').trim_suffix(':').strip_edges().split(','))
|
||||
quest_resource = strings[0].strip_edges()
|
||||
var compare_string: String = strings[1].strip_edges()
|
||||
if compare_string.is_valid_int():
|
||||
compare_status = compare_string.to_int()
|
||||
else:
|
||||
compare_status = QuestEventUtils.QuestStatusOrActive.get(compare_string)
|
||||
|
||||
|
||||
func is_valid_event(string:String) -> bool:
|
||||
if string.strip_edges().begins_with('ifquest '):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
################################################################################
|
||||
## EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func build_event_editor() -> void:
|
||||
add_header_label("IF")
|
||||
add_header_edit(
|
||||
"quest_resource",
|
||||
ValueType.DYNAMIC_OPTIONS,
|
||||
{
|
||||
"mode":2,
|
||||
"suggestions_func":QuestEventUtils.quest_resource_suggestrions
|
||||
})
|
||||
add_header_label("IS")
|
||||
add_header_edit("compare_status",ValueType.FIXED_OPTIONS,{
|
||||
'options': [
|
||||
{
|
||||
'label': 'HIDDEN',
|
||||
'value': QuestEventUtils.QuestStatusOrActive.HIDDEN,
|
||||
},
|
||||
{
|
||||
'label': 'AVAILABLE',
|
||||
'value': QuestEventUtils.QuestStatusOrActive.AVAILABLE,
|
||||
},
|
||||
{
|
||||
'label': 'DONE',
|
||||
'value': QuestEventUtils.QuestStatusOrActive.DONE,
|
||||
},
|
||||
{
|
||||
'label': 'CANCLED',
|
||||
'value': QuestEventUtils.QuestStatusOrActive.CANCLED,
|
||||
},
|
||||
{
|
||||
'label': 'ACTIVE',
|
||||
'value': QuestEventUtils.QuestStatusOrActive.ACTIVE,
|
||||
},
|
||||
{
|
||||
'label': 'NOT_ACTIVE',
|
||||
'value': QuestEventUtils.QuestStatusOrActive.NOT_ACTIVE,
|
||||
}
|
||||
]})
|
||||
|
||||
func _get_icon() -> Resource:
|
||||
return load("res://addons/dialogic/Modules/Condition/icon.svg")
|
||||
|
||||
####################### CODE COMPLETION ########################################
|
||||
################################################################################
|
||||
|
||||
func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'ifquest', 'ifquest ', TextNode.syntax_highlighter.code_flow_color)
|
||||
|
||||
|
||||
#################### SYNTAX HIGHLIGHTING #######################################
|
||||
################################################################################
|
||||
|
||||
|
||||
func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
|
||||
var word := line.get_slice(' ', 0)
|
||||
dict[line.find(word)] = {"color":Highlighter.code_flow_color}
|
||||
dict[line.find(word)+len(word)] = {"color":Highlighter.normal_color}
|
||||
dict = Highlighter.color_condition(dict, line)
|
||||
return dict
|
||||
@@ -0,0 +1 @@
|
||||
uid://b2ggc2f5kh61j
|
||||
@@ -0,0 +1,43 @@
|
||||
@tool
|
||||
class_name QuestEventUtils
|
||||
|
||||
enum QuestStatus{
|
||||
HIDDEN = 0,
|
||||
AVAILABLE = 1,
|
||||
DONE = 2,
|
||||
CANCLED = 3
|
||||
}
|
||||
|
||||
enum QuestStatusOrActive{
|
||||
HIDDEN = 0,
|
||||
AVAILABLE = 1,
|
||||
DONE = 2,
|
||||
CANCLED = 3,
|
||||
ACTIVE = 4,
|
||||
NOT_ACTIVE = 5
|
||||
}
|
||||
|
||||
|
||||
static func quest_resource_suggestrions(search_text:String) -> Dictionary:
|
||||
var ret_val = {}
|
||||
var quest_paths = get_all_file_paths("res://resources/quests")
|
||||
|
||||
for path in quest_paths:
|
||||
var res = ResourceLoader.load(path)
|
||||
ret_val[res.id]= {"value":path, "tooltip":res.title + "\n\n" + res.description}
|
||||
|
||||
return ret_val
|
||||
|
||||
static func get_all_file_paths(path: String) -> Array[String]:
|
||||
var file_paths: Array[String] = []
|
||||
var dir = DirAccess.open(path)
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
while file_name != "":
|
||||
var file_path = path + "/" + file_name
|
||||
if dir.current_is_dir():
|
||||
file_paths += get_all_file_paths(file_path)
|
||||
else:
|
||||
file_paths.append(file_path)
|
||||
file_name = dir.get_next()
|
||||
return file_paths
|
||||
@@ -0,0 +1 @@
|
||||
uid://d1x2343wpkdku
|
||||
@@ -0,0 +1,9 @@
|
||||
@tool
|
||||
extends DialogicIndexer
|
||||
|
||||
func _get_events() -> Array:
|
||||
return [
|
||||
this_folder.path_join('event_quest_activate.gd'),
|
||||
this_folder.path_join('event_quest_complete.gd'),
|
||||
this_folder.path_join('event_quest_condition.gd')
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
uid://wup1fvm05rqv
|
||||
@@ -0,0 +1,51 @@
|
||||
@tool
|
||||
extends HBoxContainer
|
||||
|
||||
var parent_resource: DialogicEvent = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
$AddElif.button_up.connect(add_elif)
|
||||
$AddElse.button_up.connect(add_else)
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
if parent_resource is DialogicQuestConditionEvent:
|
||||
# hide add elif and add else button on ELSE event
|
||||
$AddElif.visible = false# parent_resource.condition_type != DialogicConditionEvent.ConditionTypes.ELSE
|
||||
$AddElse.visible = true# parent_resource.condition_type != DialogicConditionEvent.ConditionTypes.ELSE
|
||||
$Label.text = "End of If Quest" #"End of "+["IF", "ELIF", "ELSE"][parent_resource.condition_type]+" ("+parent_resource.condition+")"
|
||||
|
||||
# hide add add else button if followed by ELIF or ELSE event
|
||||
var timeline_editor := find_parent('VisualEditor')
|
||||
if timeline_editor:
|
||||
var next_event: DialogicEvent = null
|
||||
if timeline_editor.get_block_below(get_parent()):
|
||||
next_event = timeline_editor.get_block_below(get_parent()).resource
|
||||
if next_event is DialogicConditionEvent:
|
||||
if next_event.condition_type != DialogicConditionEvent.ConditionTypes.IF:
|
||||
$AddElse.hide()
|
||||
#if parent_resource.condition_type == DialogicConditionEvent.ConditionTypes.ELSE:
|
||||
# $Label.text = "End of ELSE"
|
||||
else:
|
||||
hide()
|
||||
|
||||
|
||||
func add_elif() -> void:
|
||||
var timeline := find_parent('VisualEditor')
|
||||
if timeline:
|
||||
var resource := DialogicConditionEvent.new()
|
||||
resource.condition_type = DialogicConditionEvent.ConditionTypes.ELIF
|
||||
timeline.add_event_undoable(resource, get_parent().get_index()+1)
|
||||
timeline.indent_events()
|
||||
timeline.something_changed()
|
||||
|
||||
|
||||
func add_else() -> void:
|
||||
var timeline := find_parent('VisualEditor')
|
||||
if timeline:
|
||||
var resource := DialogicConditionEvent.new()
|
||||
resource.condition_type = DialogicConditionEvent.ConditionTypes.ELSE
|
||||
timeline.add_event_undoable(resource, get_parent().get_index()+1)
|
||||
timeline.indent_events()
|
||||
timeline.something_changed()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dlrnhnnonum4o
|
||||
@@ -0,0 +1,20 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dnrpcgjkyoiau"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dlrnhnnonum4o" path="res://addons/dialogic_additions/Quest/ui_condition_end.gd" id="1_f3miq"]
|
||||
|
||||
[node name="Condition_End" type="HBoxContainer"]
|
||||
offset_right = 90.0
|
||||
offset_bottom = 23.0
|
||||
script = ExtResource("1_f3miq")
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
layout_mode = 2
|
||||
text = "End of condition X"
|
||||
|
||||
[node name="AddElif" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
text = "Add Elif"
|
||||
|
||||
[node name="AddElse" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
text = "Add Else"
|
||||
@@ -0,0 +1,510 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "LanguageTool API",
|
||||
"description": "Check texts for style and grammar issues with <a href='https://languagetool.org'>LanguageTool</a>. Please consider the following default limitations:<ul><li>your daily request limit depending on <a href='https://languagetool.org/editor/settings/access-tokens'>your plan</a> <li>maximum number of requests per minute: 20 (free) / 80 (Premium) <li>maximum number of characters per minute: 75,000 (free) / 300,000 (Premium) <li>maximum number of characters per request: 20,000 (free) / 60,000 (Premium) <li>for the free version, also consider the <a href='https://dev.languagetool.org/public-http-api'>limitations documented here</a> <li><b>Note:</b> any parameters or outputs not part of this documentation are internal and must not be relied on</ul> Need more generous limits? Just <a href='https://languagetool.org/proofreading-api'>contact us</a>.",
|
||||
"version": "1.1.2"
|
||||
},
|
||||
"host": "api.languagetoolplus.com",
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"basePath": "/v2",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"paths": {
|
||||
"/check": {
|
||||
"post": {
|
||||
"summary": "Check a text",
|
||||
"description": "The main feature - check a text with LanguageTool for possible style and grammar issues.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "The text to be checked. This or 'data' is required.",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "data",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "The text to be checked, given as a JSON document that specifies what's text and what's markup. This or 'text' is required. Markup will be ignored when looking for errors. Example text: <pre>A <b>test</b></pre>JSON for the example text: <pre>{\"annotation\":[\n {\"text\": \"A \"},\n {\"markup\": \"<b>\"},\n {\"text\": \"test\"},\n {\"markup\": \"</b>\"}\n]}</pre> <p>If you have markup that should be interpreted as whitespace, like <tt><p></tt> in HTML, you can have it interpreted like this: <pre>{\"markup\": \"<p>\", \"interpretAs\": \"\\n\\n\"}</pre><p>The 'data' feature is not limited to HTML or XML, it can be used for any kind of markup. Entities will need to be expanded in this input.",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "language",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "A language code like `en-US`, `de-DE`, `fr`, or `auto` to guess the language automatically (see `preferredVariants` below). For languages with variants (English, German, Portuguese) spell checking will only be activated when you specify the variant, e.g. `en-GB` instead of just `en`.",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Set to get Premium API access: Your username/email as used to log in at languagetool.org."
|
||||
},
|
||||
{
|
||||
"name": "apiKey",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"description": "Set to get Premium API access: <a target='_blank' href='https://languagetool.org/editor/settings/access-tokens'>your API key</a>"
|
||||
},
|
||||
{
|
||||
"name": "dicts",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Comma-separated list of dictionaries to include words from; uses special default dictionary if this is unset"
|
||||
},
|
||||
{
|
||||
"name": "motherTongue",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "A language code of the user's native language, enabling false friends checks for some language pairs."
|
||||
},
|
||||
{
|
||||
"name": "preferredVariants",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Comma-separated list of preferred language variants. The language detector used with `language=auto` can detect e.g. English, but it cannot decide whether British English or American English is used. Thus this parameter can be used to specify the preferred variants like `en-GB` and `de-AT`. Only available with `language=auto`. You should set variants for at least German and English, as otherwise the spell checking will not work for those, as no spelling dictionary can be selected for just `en` or `de`."
|
||||
},
|
||||
{
|
||||
"name": "enabledRules",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "IDs of rules to be enabled, comma-separated. Note that 'level' still applies, so the rule won't run unless 'level' is set to a level that activates the rule."
|
||||
},
|
||||
{
|
||||
"name": "disabledRules",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "IDs of rules to be disabled, comma-separated"
|
||||
},
|
||||
{
|
||||
"name": "enabledCategories",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "IDs of categories to be enabled, comma-separated"
|
||||
},
|
||||
{
|
||||
"name": "disabledCategories",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "IDs of categories to be disabled, comma-separated"
|
||||
},
|
||||
{
|
||||
"name": "enabledOnly",
|
||||
"in": "formData",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If true, only the rules and categories whose IDs are specified with `enabledRules` or `enabledCategories` are enabled."
|
||||
},
|
||||
{
|
||||
"name": "level",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"enum": ["default", "picky"],
|
||||
"description": "If set to `picky`, additional rules will be activated, i.e. rules that you might only find useful when checking formal text."
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "the result of checking the text",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"software": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"version",
|
||||
"buildDate",
|
||||
"apiVersion"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Usually 'LanguageTool'."
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "A version string like '3.3' or '3.4-SNAPSHOT'."
|
||||
},
|
||||
"buildDate": {
|
||||
"type": "string",
|
||||
"description": "Date when the software was built, e.g. '2016-05-25'."
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "integer",
|
||||
"description": "Version of this API response. We don't expect to make incompatible changes, so this can also be increased for newly added fields."
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "An optional warning, e.g. when the API format is not stable."
|
||||
},
|
||||
"premium": {
|
||||
"type": "boolean",
|
||||
"description": "true if you're using a Premium account with all the premium text checks (since LanguageTool 4.2)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"type": "object",
|
||||
"description": "The language used for checking the text.",
|
||||
"required": [
|
||||
"name",
|
||||
"code",
|
||||
"detectedLanguage"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Language name like 'French' or 'English (US)'."
|
||||
},
|
||||
"code": {
|
||||
"type": "string",
|
||||
"description": "ISO 639-1 code like 'en', 'en-US', or 'ca-ES-valencia'"
|
||||
},
|
||||
"detectedLanguage": {
|
||||
"type": "object",
|
||||
"description": "The automatically detected text language (might be different from the language actually used for checking).",
|
||||
"required": [
|
||||
"name",
|
||||
"code"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Language name like 'French' or 'English (US)'."
|
||||
},
|
||||
"code": {
|
||||
"type": "string",
|
||||
"description": "ISO 639-1 code like 'en', 'en-US', or 'ca-ES-valencia'."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"matches": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message",
|
||||
"offset",
|
||||
"length",
|
||||
"replacements",
|
||||
"context",
|
||||
"sentence"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Message about the error displayed to the user."
|
||||
},
|
||||
"shortMessage": {
|
||||
"type": "string",
|
||||
"description": "An optional shorter version of 'message'."
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"description": "The 0-based character offset of the error in the text."
|
||||
},
|
||||
"length": {
|
||||
"type": "integer",
|
||||
"description": "The length of the error in characters."
|
||||
},
|
||||
"replacements": {
|
||||
"type": "array",
|
||||
"description": "Replacements that might correct the error. The array can be empty, in this case there is no suggested replacement.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "the replacement string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"context": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"text",
|
||||
"offset",
|
||||
"length"
|
||||
],
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "Context of the error, i.e. the error and some text to the left and to the left."
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"description": "The 0-based character offset of the error in the context text."
|
||||
},
|
||||
"length": {
|
||||
"type": "integer",
|
||||
"description": "The length of the error in characters in the context."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sentence": {
|
||||
"type": "string",
|
||||
"description": "The sentence the error occurred in (since LanguageTool 4.0 or later)"
|
||||
},
|
||||
"rule": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"description",
|
||||
"category"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "An rule's identifier that's unique for this language."
|
||||
},
|
||||
"subId": {
|
||||
"type": "string",
|
||||
"description": "An optional sub identifier of the rule, used when several rules are grouped."
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"urls": {
|
||||
"type": "array",
|
||||
"description": "An optional array of URLs with a more detailed description of the error.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "the URL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"issueType": {
|
||||
"type": "string",
|
||||
"description": "The <a href=\"http://www.w3.org/International/multilingualweb/lt/drafts/its20/its20.html#lqissue-typevalues\">Localization Quality Issue Type</a>. This is not defined for all languages, in which case it will always be 'Uncategorized'."
|
||||
},
|
||||
"category": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "A category's identifier that's unique for this language."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A short description of the category."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/languages": {
|
||||
"get": {
|
||||
"summary": "Get a list of supported languages.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "An array of language objects.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"code",
|
||||
"longCode"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "a language name like 'French' or 'English (Australia)'"
|
||||
},
|
||||
"code": {
|
||||
"type": "string",
|
||||
"description": "a language code like 'en'"
|
||||
},
|
||||
"longCode": {
|
||||
"type": "string",
|
||||
"description": "a language code like 'en-US' or 'ca-ES-valencia'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/words": {
|
||||
"get": {
|
||||
"summary": "List words in dictionaries",
|
||||
"description": "List words in the user's personal dictionaries.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "offset",
|
||||
"in": "query",
|
||||
"type": "integer",
|
||||
"description": "Offset of where to start in the list of words. Defaults to 0."
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"type": "integer",
|
||||
"description": "Maximum number of words to return. Defaults to 10."
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"in": "query",
|
||||
"type": "string",
|
||||
"description": "Your username as used to log in at languagetool.org.",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "apiKey",
|
||||
"in": "query",
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"description": "<a target='_blank' href='https://languagetool.org/editor/settings/access-tokens'>Your API key</a>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "dicts",
|
||||
"in": "query",
|
||||
"type": "string",
|
||||
"description": "Comma-separated list of dictionaries to include words from; uses special default dictionary if this is unset"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "the user's words from the given user dictionaries",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"words": {
|
||||
"type": "array",
|
||||
"description": "array of words",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/words/add": {
|
||||
"post": {
|
||||
"summary": "Add word to a dictionary",
|
||||
"description": "Add a word to one of the user's personal dictionaries. Please note that this feature is considered to be used for personal dictionaries which must not contain more than 500 words. If this is an issue for you, please contact us.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "word",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "The word to be added. Must not be a phrase, i.e. cannot contain white space. The word is added to a global dictionary that applies to all languages.",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Your username as used to log in at languagetool.org.",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "apiKey",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"description": "<a target='_blank' href='https://languagetool.org/editor/settings/access-tokens'>Your API key</a>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "dict",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Name of the dictionary to add the word to; non-existent dictionaries are created after calling this; if unset, adds to special default dictionary"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "the result of adding the word",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"added": {
|
||||
"type": "boolean",
|
||||
"description": "true if the word has been added. false means the word hasn't been added because it had been added before."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/words/delete": {
|
||||
"post": {
|
||||
"summary": "Remove word from a dictionary",
|
||||
"description": "Remove a word from one of the user's personal dictionaries.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "word",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "The word to be removed.",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Your username as used to log in at languagetool.org.",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "apiKey",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"description": "<a target='_blank' href='https://languagetool.org/editor/settings/access-tokens'>Your API key</a>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "dict",
|
||||
"in": "formData",
|
||||
"type": "string",
|
||||
"description": "Name of the dictionary to remove the word from; if the dictionary is empty upon calling this, it is deleted; if unset, removes from special default dictionary"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "the result of removing the word",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"deleted": {
|
||||
"type": "boolean",
|
||||
"description": "true if the word has been removed. false means the word hasn't been removed because it was not in the dictionary."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
var plugin: LanguagetToolPlugin
|
||||
|
||||
func _enter_tree() -> void:
|
||||
plugin = LanguagetToolPlugin.new()
|
||||
add_child(plugin)
|
||||
|
||||
EditorInterface.get_inspector().edited_object_changed.connect(_inspector_edited_object_changed)
|
||||
|
||||
func _inspector_edited_object_changed():
|
||||
plugin.check_new_inspector();
|
||||
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://fm32qkudo8sp
|
||||
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="LanguageTool"
|
||||
description="Check texts for style and grammar issues with LanguageTool. "
|
||||
author="Jonathan @ Cozy Raven Interactive"
|
||||
version=""
|
||||
script="languagetool.gd"
|
||||
@@ -0,0 +1,110 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://dxalawvo2ji7p"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dkyiuvuc2w2xc" path="res://addons/languagetool/scripts/language_tool_correction_overlay_references.gd" id="1_rh5c2"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hdqxg"]
|
||||
bg_color = Color(0.145098, 0.145098, 0.145098, 1)
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color(0.0784314, 0.0784314, 0.0784314, 1)
|
||||
corner_radius_top_left = 5
|
||||
corner_radius_top_right = 5
|
||||
corner_radius_bottom_right = 5
|
||||
corner_radius_bottom_left = 5
|
||||
|
||||
[node name="CorrectionOverlay" type="VBoxContainer"]
|
||||
offset_right = 408.0
|
||||
offset_bottom = 181.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
script = ExtResource("1_rh5c2")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 15
|
||||
theme_override_constants/margin_top = 15
|
||||
theme_override_constants/margin_right = 15
|
||||
theme_override_constants/margin_bottom = 15
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_hdqxg")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CategoryLabel" type="Label" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 11
|
||||
text = "Rechtschreibung"
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="CloseButton" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 11
|
||||
text = "X"
|
||||
|
||||
[node name="Spacer" type="Control" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 4)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DescriptionLabel" type="Label" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/paragraph_spacing = 0
|
||||
text = "Ensure spelling is correct"
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="Spacer2" type="Control" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 2)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Replacements" type="HFlowContainer" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Test 1"
|
||||
|
||||
[node name="Button2" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Test 1"
|
||||
|
||||
[node name="Button3" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Test 1"
|
||||
|
||||
[node name="Button4" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Hello world!!!"
|
||||
|
||||
[node name="Button5" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Test 1"
|
||||
|
||||
[node name="Button6" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Test 1"
|
||||
|
||||
[node name="Button7" type="Button" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "Test 1"
|
||||
@@ -0,0 +1,41 @@
|
||||
@tool
|
||||
extends Node
|
||||
|
||||
class_name LanguageToolCorrectionOverlay
|
||||
|
||||
const CORRECTION_OVERLAY = preload("res://addons/languagetool/scenes/correction_overlay.tscn")
|
||||
var instantiatedOverlay: LanguageToolCorrectionOverlayReferences
|
||||
|
||||
func _enter_tree() -> void:
|
||||
instantiatedOverlay = CORRECTION_OVERLAY.instantiate()
|
||||
add_child(instantiatedOverlay)
|
||||
hideOverlay()
|
||||
|
||||
func _ready():
|
||||
instantiatedOverlay.close_button.pressed.connect(hideOverlay)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
pass
|
||||
|
||||
func hideOverlay():
|
||||
instantiatedOverlay.hide()
|
||||
|
||||
func showOverlay(position:Vector2, width: float, _match:LanguageToolApiWrapper.LanguageToolCheckResponse.Match, replacement_clicked : Callable):
|
||||
#print(instantiatedOverlay.test)
|
||||
instantiatedOverlay.show()
|
||||
instantiatedOverlay.global_position = position
|
||||
instantiatedOverlay.size = Vector2(0,0)
|
||||
instantiatedOverlay.custom_minimum_size = Vector2(width, 0)
|
||||
instantiatedOverlay.category_label.text = _match.rule.category.name
|
||||
instantiatedOverlay.description_label.text = _match.message
|
||||
|
||||
for c in instantiatedOverlay.replacements.get_children():
|
||||
c.free()
|
||||
|
||||
for r in _match.replacements:
|
||||
var replacementButton = Button.new()
|
||||
replacementButton.text = r
|
||||
replacementButton.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
replacementButton.pressed.connect(func():replacement_clicked.call(r))
|
||||
instantiatedOverlay.replacements.add_child(replacementButton)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://ct2t8rr000prq
|
||||
@@ -0,0 +1,9 @@
|
||||
@tool
|
||||
extends VBoxContainer
|
||||
|
||||
class_name LanguageToolCorrectionOverlayReferences
|
||||
|
||||
@onready var category_label: Label = $MarginContainer/PanelContainer/MarginContainer/VBoxContainer/HBoxContainer/CategoryLabel
|
||||
@onready var description_label: Label = $MarginContainer/PanelContainer/MarginContainer/VBoxContainer/DescriptionLabel
|
||||
@onready var replacements: HFlowContainer = $MarginContainer/PanelContainer/MarginContainer/VBoxContainer/Replacements
|
||||
@onready var close_button: Button = $MarginContainer/PanelContainer/MarginContainer/VBoxContainer/HBoxContainer/CloseButton
|
||||
@@ -0,0 +1 @@
|
||||
uid://dkyiuvuc2w2xc
|
||||
@@ -0,0 +1,32 @@
|
||||
extends SyntaxHighlighter
|
||||
|
||||
class_name LanguageToolErrorSyntaxHighlighter
|
||||
|
||||
var check:LanguageToolApiWrapper.LanguageToolCheckResponse
|
||||
|
||||
func _init(check:LanguageToolApiWrapper.LanguageToolCheckResponse):
|
||||
self.check = check
|
||||
|
||||
func _get_line_syntax_highlighting(line: int) -> Dictionary:
|
||||
var normalColor = EditorInterface.get_base_control().get_theme_color("font_color", "Editor")
|
||||
var errorColor = EditorInterface.get_base_control().get_theme_color("error_color", "Editor")
|
||||
var warningColor = EditorInterface.get_base_control().get_theme_color("warning_color", "Editor")
|
||||
var successColor = EditorInterface.get_base_control().get_theme_color("success_color", "Editor")
|
||||
|
||||
var retval = {}
|
||||
|
||||
for m:LanguageToolApiWrapper.LanguageToolCheckResponse.Match in check.matches:
|
||||
var row_column = LanguageToolUtils.offset_to_row_column(m.offset,get_text_edit().text)
|
||||
if row_column[0] != line:
|
||||
continue
|
||||
match m.rule.category.id:
|
||||
"GRAMMAR":
|
||||
retval[row_column[1]] = {"color":warningColor}
|
||||
"TYPOS":
|
||||
retval[row_column[1]] = {"color":errorColor}
|
||||
_:
|
||||
retval[row_column[1]] = {"color":successColor}
|
||||
|
||||
retval[row_column[1]+m.length] = {"color":normalColor}
|
||||
|
||||
return retval
|
||||
@@ -0,0 +1 @@
|
||||
uid://csxcr0bsetagc
|
||||
@@ -0,0 +1,112 @@
|
||||
extends Node
|
||||
|
||||
class_name LanguagetToolPlugin
|
||||
|
||||
var api: LanguageToolApiWrapper
|
||||
var overlay: LanguageToolCorrectionOverlay
|
||||
|
||||
var checkDict: Dictionary[String,LanguageToolApiWrapper.LanguageToolCheckResponse] = {}
|
||||
|
||||
func _enter_tree() -> void:
|
||||
api = LanguageToolApiWrapper.new()
|
||||
add_child(api)
|
||||
overlay = LanguageToolCorrectionOverlay.new()
|
||||
add_child(overlay)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
pass
|
||||
|
||||
func check_new_inspector():
|
||||
overlay.hideOverlay()
|
||||
|
||||
var textEdits: Array[TextEdit] = _find_multiline_text_edits()
|
||||
for te: TextEdit in textEdits:
|
||||
te.text_changed.connect(func():_on_text_changed(te))
|
||||
te.focus_exited.connect(func():_on_focus_lost(te))
|
||||
te.caret_changed.connect(func():_on_caret_changed(te))
|
||||
|
||||
_check_text(te)
|
||||
_mark_errors_in_text(te)
|
||||
|
||||
|
||||
func _on_text_changed(textEdit: TextEdit):
|
||||
_mark_errors_in_text(textEdit)
|
||||
overlay.hideOverlay()
|
||||
|
||||
func _on_focus_lost(textEdit: TextEdit):
|
||||
_check_text(textEdit)
|
||||
_mark_errors_in_text(textEdit)
|
||||
|
||||
func _on_caret_changed(textEdit: TextEdit):
|
||||
if(!checkDict.has(textEdit.text)):
|
||||
return
|
||||
var check: LanguageToolApiWrapper.LanguageToolCheckResponse = checkDict[textEdit.text]
|
||||
|
||||
# find match at caret
|
||||
var caret_offset:int = LanguageToolUtils.row_column_to_offset(textEdit.get_caret_line(), textEdit.get_caret_column(),textEdit.text)
|
||||
var _match:LanguageToolApiWrapper.LanguageToolCheckResponse.Match = null
|
||||
for m in check.matches:
|
||||
if m.offset <= caret_offset and m.offset + m.length >= caret_offset:
|
||||
_match = m
|
||||
break
|
||||
|
||||
if _match != null:
|
||||
var edit_global_rect = textEdit.get_global_rect()
|
||||
overlay.showOverlay(
|
||||
edit_global_rect.position + Vector2(0,edit_global_rect.size.y),
|
||||
edit_global_rect.size.x,
|
||||
_match,
|
||||
func(newText):_apply_text_change(textEdit,newText,_match))
|
||||
else:
|
||||
overlay.hideOverlay()
|
||||
pass
|
||||
|
||||
func _check_text(textEdit: TextEdit):
|
||||
if textEdit.text == "":
|
||||
return
|
||||
|
||||
if checkDict.has(textEdit.text):
|
||||
return
|
||||
|
||||
var response = api.check(textEdit.text)
|
||||
checkDict[textEdit.text] = response
|
||||
|
||||
|
||||
func _mark_errors_in_text(textEdit: TextEdit):
|
||||
if(!checkDict.has(textEdit.text)):
|
||||
textEdit.syntax_highlighter=null
|
||||
return
|
||||
var check: LanguageToolApiWrapper.LanguageToolCheckResponse = checkDict[textEdit.text]
|
||||
textEdit.syntax_highlighter = LanguageToolErrorSyntaxHighlighter.new(check)
|
||||
|
||||
func _apply_text_change(textEdit:TextEdit, newText: String, _match:LanguageToolApiWrapper.LanguageToolCheckResponse.Match):
|
||||
var oldText = textEdit.text
|
||||
var removedOldWord = oldText.erase(_match.offset,_match.length)
|
||||
var newWordInserted = removedOldWord.insert(_match.offset,newText)
|
||||
textEdit.text = newWordInserted
|
||||
textEdit.text_changed.emit()
|
||||
overlay.hideOverlay()
|
||||
_check_text(textEdit)
|
||||
_mark_errors_in_text(textEdit)
|
||||
|
||||
func _find_multiline_text_edits()->Array[TextEdit]:
|
||||
var multilinteTexts:Array[Node] = _find_recursive(
|
||||
EditorInterface.get_inspector().get_child(0).get_child(2),
|
||||
"EditorPropertyMultilineText");
|
||||
|
||||
var textEditors:Array[TextEdit]
|
||||
textEditors.assign( multilinteTexts.map(func(c):return c.get_child(0).get_child(0) as TextEdit))
|
||||
|
||||
return textEditors
|
||||
|
||||
func _find_recursive(node: Node, type: Variant) -> Array[Node]:
|
||||
if type is String:
|
||||
if node.get_class() == type:
|
||||
return [node]
|
||||
elif is_instance_of(node, type):
|
||||
return [node]
|
||||
|
||||
var retval: Array[Node] = []
|
||||
for child in node.get_children():
|
||||
retval.append_array(_find_recursive(child, type))
|
||||
return retval
|
||||
@@ -0,0 +1 @@
|
||||
uid://bi8yv26eglkso
|
||||
@@ -0,0 +1,32 @@
|
||||
@tool
|
||||
extends Object
|
||||
|
||||
class_name LanguageToolUtils
|
||||
|
||||
static func offset_to_row_column(offset:int, text:String)->Vector2i:
|
||||
var row:int = 0
|
||||
var column:int = 0
|
||||
|
||||
if offset > text.length():
|
||||
return Vector2i(-1,-1)
|
||||
|
||||
for i in offset:
|
||||
if text[i] == "\n":
|
||||
row+=1
|
||||
column = 0
|
||||
else:
|
||||
column+=1
|
||||
return Vector2i(row, column)
|
||||
|
||||
static func row_column_to_offset(row:int, column:int, text:String) -> int:
|
||||
var current_row:int = 0
|
||||
var current_column:int = 0
|
||||
for i in text.length():
|
||||
if current_row == row and current_column == column:
|
||||
return i
|
||||
if text[i] == "\n":
|
||||
current_row += 1
|
||||
current_column = 0
|
||||
else:
|
||||
current_column += 1
|
||||
return -1
|
||||
@@ -0,0 +1 @@
|
||||
uid://q01v4f8pfgfe
|
||||
@@ -0,0 +1,211 @@
|
||||
@tool
|
||||
class_name LanguageToolApiWrapper
|
||||
extends Node
|
||||
|
||||
const BASE_URL := "https://api.languagetoolplus.com/v2"
|
||||
|
||||
func _make_request(endpoint: String, method: HTTPClient.Method = HTTPClient.METHOD_GET, data: Dictionary = {}, headers: Dictionary = {}):
|
||||
var url = BASE_URL + endpoint
|
||||
var scheme_split = url.split("://")
|
||||
var scheme = scheme_split[0]
|
||||
var rest = scheme_split[1]
|
||||
var host_and_path = rest.split("/", false, 1)
|
||||
var host = host_and_path[0]
|
||||
var path = "/" + host_and_path[1] if host_and_path.size() > 1 else "/"
|
||||
var port = 443 if scheme == "https" else 80
|
||||
|
||||
var client = HTTPClient.new()
|
||||
var tlsOptions: TLSOptions = (TLSOptions.client() if scheme == "https" else null)
|
||||
var err = client.connect_to_host(host, port, tlsOptions)
|
||||
if err != OK:
|
||||
push_error("Failed to connect to host: " + str(err))
|
||||
return null
|
||||
|
||||
while client.get_status() in [HTTPClient.STATUS_CONNECTING, HTTPClient.STATUS_RESOLVING]:
|
||||
client.poll()
|
||||
OS.delay_msec(10)
|
||||
|
||||
var header_array = []
|
||||
for k in headers.keys():
|
||||
header_array.append(str(k) + ": " + str(headers[k]))
|
||||
|
||||
var body = ""
|
||||
if method == HTTPClient.METHOD_POST:
|
||||
body = ""
|
||||
if data.size() > 0:
|
||||
body = client.query_string_from_dict(data)
|
||||
header_array.append("Content-Type: application/x-www-form-urlencoded")
|
||||
header_array.append("Content-Length: " + str(body.length()))
|
||||
client.request(HTTPClient.METHOD_POST, path, header_array, body)
|
||||
else:
|
||||
if data.size() > 0:
|
||||
path += "?" + client.query_string_from_dict(data)
|
||||
client.request(HTTPClient.METHOD_GET, path, header_array)
|
||||
|
||||
while client.get_status() == HTTPClient.STATUS_REQUESTING:
|
||||
client.poll()
|
||||
OS.delay_msec(10)
|
||||
|
||||
var response = ""
|
||||
while client.get_status() == HTTPClient.STATUS_BODY or client.has_response():
|
||||
client.poll()
|
||||
var chunk = client.read_response_body_chunk()
|
||||
if chunk.size() == 0:
|
||||
break
|
||||
response += chunk.get_string_from_utf8()
|
||||
OS.delay_msec(10)
|
||||
|
||||
var resp_code = client.get_response_code()
|
||||
if resp_code != 200:
|
||||
push_error("HTTP error: " + str(resp_code) + "\\n" + response)
|
||||
return null
|
||||
|
||||
var json = JSON.new()
|
||||
var json_err = json.parse(response)
|
||||
if json_err != OK:
|
||||
push_error("JSON parse error: " + str(json_err) + "\\n" + response)
|
||||
return null
|
||||
return json.get_data()
|
||||
|
||||
func check(text: String, language: String = "auto", opts: Dictionary = {}) -> LanguageToolCheckResponse:
|
||||
var data = {
|
||||
"text": text,
|
||||
"language": language
|
||||
}
|
||||
for k in opts.keys():
|
||||
data[k] = opts[k]
|
||||
print("Checking text: "+text)
|
||||
return LanguageToolCheckResponse.new(_make_request("/check", HTTPClient.METHOD_POST, data))
|
||||
|
||||
func get_languages():
|
||||
return _make_request("/languages", HTTPClient.METHOD_GET)
|
||||
|
||||
func list_words(username: String, apiKey: String, offset: int = 0, limit: int = 10, dicts: String = ""):
|
||||
var data = {
|
||||
"username": username,
|
||||
"apiKey": apiKey,
|
||||
"offset": offset,
|
||||
"limit": limit
|
||||
}
|
||||
if dicts != "":
|
||||
data["dicts"] = dicts
|
||||
return _make_request("/words", HTTPClient.METHOD_GET, data)
|
||||
|
||||
func add_word(word: String, username: String, apiKey: String, dict: String = ""):
|
||||
var data = {
|
||||
"word": word,
|
||||
"username": username,
|
||||
"apiKey": apiKey
|
||||
}
|
||||
if dict != "":
|
||||
data["dict"] = dict
|
||||
return _make_request("/words/add", HTTPClient.METHOD_POST, data)
|
||||
|
||||
func delete_word(word: String, username: String, apiKey: String, dict: String = ""):
|
||||
var data = {
|
||||
"word": word,
|
||||
"username": username,
|
||||
"apiKey": apiKey
|
||||
}
|
||||
if dict != "":
|
||||
data["dict"] = dict
|
||||
return _make_request("/words/delete", HTTPClient.METHOD_POST, data)
|
||||
|
||||
static func percent_encode(text: String) -> String:
|
||||
return text.uri_encode()
|
||||
|
||||
class LanguageToolCheckResponse:
|
||||
|
||||
# Software info
|
||||
var software_name: String
|
||||
var software_version: String
|
||||
var software_build_date: String
|
||||
var software_api_version: int
|
||||
var software_status: String = ""
|
||||
var software_premium: bool = false
|
||||
|
||||
# Language info
|
||||
var language_name: String
|
||||
var language_code: String
|
||||
var detected_language_name: String
|
||||
var detected_language_code: String
|
||||
|
||||
# Match structure
|
||||
class Match:
|
||||
var message: String
|
||||
var short_message: String = ""
|
||||
var offset: int
|
||||
var length: int
|
||||
var replacements: Array[String] = []
|
||||
var context_text: String
|
||||
var context_offset: int
|
||||
var context_length: int
|
||||
var sentence: String
|
||||
class Rule:
|
||||
var id: String
|
||||
var sub_id: String = ""
|
||||
var description: String
|
||||
var urls: Array[String] = []
|
||||
var issue_type: String = ""
|
||||
class Category:
|
||||
var id: String
|
||||
var name: String
|
||||
var category: Category
|
||||
var rule: Rule
|
||||
|
||||
var matches: Array[Match] = []
|
||||
|
||||
func _init(response: Variant) -> void:
|
||||
# Parse software
|
||||
var sw = response.software if response.has("software") else {}
|
||||
software_name = sw.name if sw.has("name") else ""
|
||||
software_version = sw.version if sw.has("version") else ""
|
||||
software_build_date = sw.buildDate if sw.has("buildDate") else ""
|
||||
software_api_version = sw.apiVersion if sw.has("apiVersion") else 0
|
||||
software_status = sw.status if sw.has("status") else ""
|
||||
software_premium = sw.premium if sw.has("premium") else false
|
||||
|
||||
# Parse language
|
||||
var lang = response.language if response.has("language") else {}
|
||||
language_name = lang.name if lang.has("name") else ""
|
||||
language_code = lang.code if lang.has("code") else ""
|
||||
var det_lang = lang.detectedLanguage if lang.has("detectedLanguage") else {}
|
||||
detected_language_name = det_lang.name if det_lang.has("name") else ""
|
||||
detected_language_code = det_lang.code if det_lang.has("code") else ""
|
||||
|
||||
# Parse matches
|
||||
matches = []
|
||||
var matches_arr = response.matches if response.has("matches") else []
|
||||
for m in matches_arr:
|
||||
var _match = Match.new()
|
||||
_match.message = m.message if m.has("message") else ""
|
||||
_match.short_message = m.shortMessage if m.has("shortMessage") else ""
|
||||
_match.offset = m.offset if m.has("offset") else 0
|
||||
_match.length = m.length if m.has("length") else 0
|
||||
#_match.replacements = []
|
||||
var replacements_arr = m.replacements if m.has("replacements") else []
|
||||
for r in replacements_arr:
|
||||
_match.replacements.append(r.value if r.has("value") else "")
|
||||
var ctx = m.context if m.has("context") else {}
|
||||
_match.context_text = ctx.text if ctx.has("text") else ""
|
||||
_match.context_offset = ctx.offset if ctx.has("offset") else 0
|
||||
_match.context_length = ctx.length if ctx.has("length") else 0
|
||||
_match.sentence = m.sentence if m.has("sentence") else ""
|
||||
var rule_dict = m.rule if m.has("rule") else {}
|
||||
var rule = Match.Rule.new()
|
||||
rule.id = rule_dict.id if rule_dict.has("id") else ""
|
||||
rule.sub_id = rule_dict.subId if rule_dict.has("subId") else ""
|
||||
rule.description = rule_dict.description if rule_dict.has("description") else ""
|
||||
#rule.urls = []
|
||||
var urls_arr = rule_dict.urls if rule_dict.has("urls") else []
|
||||
for u in urls_arr:
|
||||
rule.urls.append(u.value if u.has("value") else "")
|
||||
rule.issue_type = rule_dict.issueType if rule_dict.has("issueType") else ""
|
||||
var cat = rule_dict.category if rule_dict.has("category") else {}
|
||||
var category = Match.Rule.Category.new()
|
||||
category.id = cat.id if cat.has("id") else ""
|
||||
category.name = cat.name if cat.has("name") else ""
|
||||
rule.category = category
|
||||
_match.rule = rule
|
||||
matches.append(_match)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bkyd022t8ugkw
|
||||
@@ -0,0 +1,8 @@
|
||||
@tool
|
||||
extends EditorScript
|
||||
|
||||
func _run():
|
||||
var api = LanguageToolApiWrapper.new()
|
||||
EditorInterface.get_base_control().add_child(api)
|
||||
var result = api.check("Hello this is a santence how are you")
|
||||
print(result.matches[0])
|
||||
@@ -0,0 +1 @@
|
||||
uid://77jt5suj0wdj
|
||||
@@ -0,0 +1,47 @@
|
||||
@tool
|
||||
extends EditorScript
|
||||
|
||||
var testButton: Button
|
||||
|
||||
func _run():
|
||||
#var selected: Node = EditorInterface.get_inspector().get_child(0).get_child(2)
|
||||
#_print_info(selected)
|
||||
#print((EditorInterface.get_inspector().get_child(0).get_child(2).get_child(-1) as Button).text)
|
||||
#print((selected as LineEdit).text)
|
||||
#(selected as LineEdit).insert_text_at_caret("hello")
|
||||
#(selected as LineEdit).text_changed.emit((selected as LineEdit).text)
|
||||
#print(selected.get_class())
|
||||
#print(is_instance_of(selected, EditorPropertyText))
|
||||
#print(_find_recursive(selected,"EditorPropertyMultilineText")[0].get_child(0).get_child(0).get_class())
|
||||
#print(_find_recursive(selected,"EditorPropertyText")[0].get_child(0).get_child(0).get_class())
|
||||
testButton = Button.new()
|
||||
testButton.text = "Remove this button"
|
||||
#testButton.global_position = Vector2(1904.0, 305.0)
|
||||
testButton.pressed.connect(
|
||||
func():
|
||||
testButton.get_parent().remove_child(testButton)
|
||||
testButton.queue_free()
|
||||
)
|
||||
EditorInterface.get_base_control().add_child(testButton)
|
||||
|
||||
pass
|
||||
|
||||
|
||||
func _print_info(node: Control):
|
||||
print("Name: "+node.name)
|
||||
print("Children:")
|
||||
for child in node.get_children():
|
||||
print(" - "+child.name)
|
||||
|
||||
func _find_recursive(node: Node, type: Variant) -> Array[Node]:
|
||||
if type is String:
|
||||
if node.get_class() == type:
|
||||
return [node]
|
||||
elif is_instance_of(node, type):
|
||||
return [node]
|
||||
|
||||
var retval: Array[Node] = []
|
||||
for child in node.get_children():
|
||||
retval.append_array(_find_recursive(child, type))
|
||||
return retval
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://t6f7snttaggn
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ccy6bwunhfvrf"
|
||||
path="res://.godot/imported/Babushka_house_frontDoor.png-345830acb7ae8cbbb97011f89455fd91.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/farm/Babushka_house_frontDoor.png"
|
||||
dest_files=["res://.godot/imported/Babushka_house_frontDoor.png-345830acb7ae8cbbb97011f89455fd91.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b5ade1s2ijunu"
|
||||
path="res://.godot/imported/beetroot_icon.png-aef760d681bd7ef4c12802c6da8d93f5.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/farm/farming/farmobjekte/beetroot/beetroot_icon.png"
|
||||
dest_files=["res://.godot/imported/beetroot_icon.png-aef760d681bd7ef4c12802c6da8d93f5.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://xtci0n8tquc0"
|
||||
path="res://.godot/imported/beetroot_00.png-0c2234fc9109ef4b2bb1c7f568ee2fc7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/farm/farming/farmobjekte/beetroot_00.png"
|
||||
dest_files=["res://.godot/imported/beetroot_00.png-0c2234fc9109ef4b2bb1c7f568ee2fc7.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,9 @@
|
||||
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://bv3m12duf0dj6"]
|
||||
|
||||
[ext_resource type="Shader" uid="uid://dsa3lv2as7q3b" path="res://shader/outline.gdshader" id="1_fxlom"]
|
||||
|
||||
[resource]
|
||||
shader = ExtResource("1_fxlom")
|
||||
shader_parameter/allow_out_of_bounds = true
|
||||
shader_parameter/outline_thickness = 8.0
|
||||
shader_parameter/outline_color = Color(0.88, 0.54208, 0.4576, 1)
|
||||
@@ -0,0 +1,9 @@
|
||||
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://blch5kdhkbj75"]
|
||||
|
||||
[ext_resource type="Shader" uid="uid://dsa3lv2as7q3b" path="res://shader/outline.gdshader" id="1_ovtva"]
|
||||
|
||||
[resource]
|
||||
shader = ExtResource("1_ovtva")
|
||||
shader_parameter/allow_out_of_bounds = true
|
||||
shader_parameter/outline_thickness = 8.0
|
||||
shader_parameter/outline_color = Color(0.88, 0.79684, 0.3256, 1)
|
||||
@@ -4,12 +4,11 @@ importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://b3kyrsoobmkhp"
|
||||
path="res://.godot/imported/best_house_blender.blend-ac89c74aef2f275bdf4b4baadee17c0c.scn"
|
||||
valid=false
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/mockups/3d/best_house_blender.blend"
|
||||
dest_files=["res://.godot/imported/best_house_blender.blend-ac89c74aef2f275bdf4b4baadee17c0c.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
script = ExtResource("1_0jwhi")
|
||||
overrides = {
|
||||
"global_bg_color": "Color(0.898375, 0.917922, 0.835355, 1)",
|
||||
"global_font_color": "Color(0.242786, 0.16463, 0.180255, 1)",
|
||||
"global_font_size": "20.0"
|
||||
"global_font_color": "Color(0.257812, 0.125248, 0.0533752, 1)",
|
||||
"global_font_size": "30.0"
|
||||
}
|
||||
|
||||
[sub_resource type="Resource" id="Resource_uxnk3"]
|
||||
@@ -44,10 +44,10 @@ overrides = {
|
||||
"name_label_alignment": "2",
|
||||
"name_label_box_modulate": "Color(1, 1, 1, 1)",
|
||||
"name_label_box_panel": "\"res://dialog/Babushka_NPC_Namebox_background.tres\"",
|
||||
"name_label_custom_font_size": "30.0",
|
||||
"name_label_use_global_color": "false",
|
||||
"next_indicator_enabled": "false",
|
||||
"text_alignment": "1",
|
||||
"text_size": "20.0",
|
||||
"text_size": "40.0",
|
||||
"typing_sounds_end_sound": "\"res://audio/sfx/UI/Dialog/SFX_Dialog_Open_01.wav\""
|
||||
}
|
||||
|
||||
@@ -59,7 +59,14 @@ overrides = {}
|
||||
[sub_resource type="Resource" id="Resource_umvdi"]
|
||||
script = ExtResource("1_0jwhi")
|
||||
scene = ExtResource("7_rg32j")
|
||||
overrides = {}
|
||||
overrides = {
|
||||
"font_size_custom": "30.0",
|
||||
"text_color_disabled": "Color(0.605469, 0.605469, 0.605469, 1)",
|
||||
"text_color_focused": "Color(1, 0.628906, 0.628906, 1)",
|
||||
"text_color_hovered": "Color(0.882353, 0.572549, 0.572549, 1)",
|
||||
"text_color_pressed": "Color(1, 0.882812, 0.53125, 1)",
|
||||
"text_color_use_global": "false"
|
||||
}
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ci2ul"]
|
||||
script = ExtResource("1_0jwhi")
|
||||
@@ -94,4 +101,4 @@ layer_info = {
|
||||
}
|
||||
base_overrides = {}
|
||||
layers = Array[ExtResource("1_0jwhi")]([])
|
||||
metadata/_latest_layer = "14"
|
||||
metadata/_latest_layer = "15"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[quest_complete quest_resource="res://resources/quests/demo/7_talk_yeli_inside_1.tres"]
|
||||
join Yeli center
|
||||
Yeli: Thank you for your help out there.
|
||||
Yeli: You must be tired. Please rest. I prepared a bed for you. It's in the room to the left.
|
||||
Yeli: There is nothing interesting to see here.
|
||||
leave Yeli
|
||||
[quest_activate quest_resource="res://resources/quests/demo/8_goto_bed.tres"]
|
||||
[end_timeline]
|
||||
@@ -1,18 +1,18 @@
|
||||
join Yeli center
|
||||
join Vesna2 center
|
||||
join vesna center
|
||||
Everyone: Smachnoho!
|
||||
Vesna2: Lovely soup, Yeli!
|
||||
vesna: Lovely soup, Yeli!
|
||||
Yeli (_part_side): God bless you, my child! That’s also thanks to you.
|
||||
Vesna2: So, how do you like it in Lasnoye so far?
|
||||
vesna: So, how do you like it in Lasnoye so far?
|
||||
- It feels different from when Vasily and I used to live here.
|
||||
- It’s just as I remembered it.
|
||||
Yeli (_part_side): Indeed, it is.
|
||||
Yeli (_part_side): Since the evacuation, Lasnoye and its people had to adapt to…new circumstances.
|
||||
Yeli (_part_side): But at its core, it’s still our motherland from back then.
|
||||
Vesna2: …And the forest? Has anyone tried to go back and--
|
||||
vesna: …And the forest? Has anyone tried to go back and--
|
||||
Yeli (_part_side): The forest is strictly off-limits!
|
||||
Yeli (_part_side): Dragana forbids it.
|
||||
Yeli (_part_side): The grime turned the forest into a dangerous place.
|
||||
Yeli (_part_side): But here you’re safe. After all, you can always count on your Yeli!
|
||||
Vesna2: In that case, pass me some more soup!
|
||||
vesna: In that case, pass me some more soup!
|
||||
[end_timeline]
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"@path": "res://addons/dialogic/Resources/character.gd",
|
||||
"@subpath": NodePath(""),
|
||||
&"_translation_id": "",
|
||||
&"color": Color(1, 1, 1, 1),
|
||||
&"custom_info": {
|
||||
"sound_mood_default": "",
|
||||
"sound_moods": {},
|
||||
"style": "NPC_narrative"
|
||||
},
|
||||
&"default_portrait": "",
|
||||
&"description": "Main character",
|
||||
&"display_name": "Vesna2",
|
||||
&"mirror": false,
|
||||
&"nicknames": [""],
|
||||
&"offset": Vector2(0, 0),
|
||||
&"portraits": {},
|
||||
&"scale": 1.0
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://c0vfdx7xal0py
|
||||
@@ -1,3 +0,0 @@
|
||||
join vesna left
|
||||
That’s the last one. I should get back to Yeli.
|
||||
[end_timeline]
|
||||
@@ -1,4 +0,0 @@
|
||||
join Vesna2 center
|
||||
Vesna2: I just wish I liked tomatoes more.
|
||||
Vesna2: Well…Yeli probably started with the cooking. I should go inside.
|
||||
[end_timeline]
|
||||
@@ -1,10 +0,0 @@
|
||||
join Yeli center
|
||||
join Vesna2 center
|
||||
Yeli (_part_side): Thank you, my child! Your Yeli is not so agile anymore.
|
||||
Vesna2: But you’re diligent! You’ve started with the preparation for dinner.
|
||||
Yeli (_part_side): Indeed, I have.
|
||||
Yeli (_part_side): But, oh my, those ducks messed up the tomatos.
|
||||
Yeli (_part_side): Oh, would you like to assist me?
|
||||
Vesna2: What do I have to do?
|
||||
Yeli (_part_side): First, take the hoe and watering can over there! Then come back to me!
|
||||
[end_timeline]
|
||||
@@ -1,15 +0,0 @@
|
||||
join Vesna2 center
|
||||
join Domovoi center
|
||||
Vesna2: Oh no, most of the beets aren’t ripe yet.
|
||||
Domovoi: Pssss!
|
||||
Domovoi: Yeah, you!
|
||||
Domovoi: The code word is “Rosty Rosty”
|
||||
Vesna2: What?
|
||||
Domovoi: Just say it!
|
||||
Vesna2: Rosty…rosty?
|
||||
# Hier wächst die rote Beete magisch. Mit einem Signal/Ereignis?
|
||||
[signal]
|
||||
Vesna2: It worked! How did it work?
|
||||
Vesna2: Thank y…and he’s gone.
|
||||
What a truly quirky individual.
|
||||
[end_timeline]
|
||||
@@ -1,5 +0,0 @@
|
||||
join Chuga center
|
||||
Chuga: I believe you’ve seen enough for today.
|
||||
Chuga: And yes, you too.
|
||||
Thank you for playing!
|
||||
[end_timeline]
|
||||
@@ -1,5 +1,5 @@
|
||||
join Yeli center
|
||||
join Vesna2 center
|
||||
join vesna center
|
||||
Yeli (_part_side): Wow! So many?
|
||||
Yeli (_part_side): Good job! Put it in the kettle!
|
||||
[wait_input]
|
||||
@@ -0,0 +1,15 @@
|
||||
join vesna center
|
||||
join Domovoi center
|
||||
vesna: Oh no, most of the beets aren’t ripe yet.
|
||||
Domovoi: Pssss!
|
||||
Domovoi: Yeah, you!
|
||||
Domovoi: The code word is “Rosty Rosty”
|
||||
vesna: What?
|
||||
Domovoi: Just say it!
|
||||
vesna: Rosty…rosty?
|
||||
# Hier wächst die rote Beete magisch. Mit einem Signal/Ereignis?
|
||||
[signal arg="MagicWord"]
|
||||
vesna: It worked! How did it work?
|
||||
vesna: Thank y…and he’s gone.
|
||||
vesna: What a truly quirky individual.
|
||||
[end_timeline]
|
||||
@@ -0,0 +1,5 @@
|
||||
join vesna center
|
||||
[quest_complete quest_resource="res://resources/quests/demo/2_collect_ducks.tres"]
|
||||
That’s the last one. I should get back to Yeli.
|
||||
[quest_activate quest_resource="res://resources/quests/demo/3_talk_yeli_2.tres"]
|
||||
[end_timeline]
|
||||
@@ -1,8 +1,10 @@
|
||||
join Yeli center
|
||||
join Yeli right
|
||||
join vesna left
|
||||
[quest_complete quest_resource="res://resources/quests/demo/1_talk_yeli_1.tres"]
|
||||
Yeli (_part_side): Come here, you little quacking beast!
|
||||
- What a mess!
|
||||
- You haven’t called me that way yet.
|
||||
- How did you call me?
|
||||
Yeli (_part_side): Vesna, oh, thank goodness!
|
||||
Yeli (_part_side): Please could you get the runner ducks back into their coop?
|
||||
[quest_activate quest_resource="res://resources/quests/demo/2_collect_ducks.tres"]
|
||||
[end_timeline]
|
||||
@@ -0,0 +1,6 @@
|
||||
join Chuga center
|
||||
Chuga: I believe you’ve seen enough for today.
|
||||
Chuga: And yes, you too.
|
||||
vesna: Thank you for playing!
|
||||
do SceneTransition.ChangeSceneToFileThreaded("res://scenes/Babushka_scene_credits.tscn")
|
||||
[end_timeline]
|
||||
@@ -1,22 +1,24 @@
|
||||
join Vesna2 center
|
||||
[quest_complete quest_resource="res://resources/quests/demo/9_talk_to_chuga.tres"]
|
||||
join vesna center
|
||||
join Chuga center
|
||||
Chuga: Look who it is!
|
||||
Vesna2: Your name was Chuga, right? I want to go to the forest!
|
||||
vesna: Your name was Chuga, right? I want to go to the forest!
|
||||
Chuga: To the forest? After everything the others told you?
|
||||
Vesna2: Will you let me through?
|
||||
vesna: Will you let me through?
|
||||
Chuga: Will I?
|
||||
Chuga: Let us have a riddle!
|
||||
Chuga: If you answer correctly, I let you through.
|
||||
Chuga: If not, I let you through anyway.
|
||||
Vesna2: So, what’s the point of answering?
|
||||
vesna: So, what’s the point of answering?
|
||||
Chuga: You give me an answer, and I give you something to see in the dark.
|
||||
Chuga: Or are you planning to return with bumps and bruises?
|
||||
Chuga: So, listen\: “I wear a crown, but I’m no king.” Vesna, what am I?
|
||||
- Queen
|
||||
Chuga: What a boring answer.
|
||||
- Tree
|
||||
That’s it!
|
||||
Chuga: That’s it!
|
||||
- Soup
|
||||
Chuga: Hate the player, not the game.
|
||||
Chuga: Here you go!
|
||||
[quest_activate quest_resource="res://resources/quests/demo/10_fight_the_monsters.tres"]
|
||||
[end_timeline]
|
||||
@@ -0,0 +1,4 @@
|
||||
join vesna center
|
||||
vesna: I just wish I liked tomatoes more.
|
||||
vesna: Well…Yeli probably started with the cooking. I should go inside.
|
||||
[end_timeline]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user