| 作者 | SHA1 | 備註 | 提交日期 |
|---|---|---|---|
|
|
325e7aa0d4 | add draft crate push | 5 年之前 |
|
|
b59b2109ab | remove old yarn files | 5 年之前 |
| @@ -1,4 +1,4 @@ | |||||
| [gd_scene load_steps=32 format=2] | |||||
| [gd_scene load_steps=33 format=2] | |||||
| [ext_resource path="res://jrpg/scripts/levels/spawner.gd" type="Script" id=1] | [ext_resource path="res://jrpg/scripts/levels/spawner.gd" type="Script" id=1] | ||||
| [ext_resource path="res://jrpg/yarn_scripts/test_start.yarn" type="Resource" id=2] | [ext_resource path="res://jrpg/yarn_scripts/test_start.yarn" type="Resource" id=2] | ||||
| @@ -17,6 +17,7 @@ | |||||
| [ext_resource path="res://jrpg/scripts/misc/test_level.gd" type="Script" id=15] | [ext_resource path="res://jrpg/scripts/misc/test_level.gd" type="Script" id=15] | ||||
| [ext_resource path="res://jrpg/models/nature/river/water.tres" type="Material" id=16] | [ext_resource path="res://jrpg/models/nature/river/water.tres" type="Material" id=16] | ||||
| [ext_resource path="res://jrpg/scenes/entities/Switch.tscn" type="PackedScene" id=17] | [ext_resource path="res://jrpg/scenes/entities/Switch.tscn" type="PackedScene" id=17] | ||||
| [ext_resource path="res://jrpg/scenes/entities/Crate.tscn" type="PackedScene" id=18] | |||||
| [sub_resource type="PlaneMesh" id=1] | [sub_resource type="PlaneMesh" id=1] | ||||
| size = Vector2( 600, 600 ) | size = Vector2( 600, 600 ) | ||||
| @@ -418,4 +419,7 @@ shape = SubResource( 14 ) | |||||
| [node name="Switch" parent="." instance=ExtResource( 17 )] | [node name="Switch" parent="." instance=ExtResource( 17 )] | ||||
| transform = Transform( 1, 0, 0, 0, 0.0600904, 0.998193, 0, -0.998193, 0.0600904, 7.74067, -0.485543, -28.5048 ) | transform = Transform( 1, 0, 0, 0, 0.0600904, 0.998193, 0, -0.998193, 0.0600904, 7.74067, -0.485543, -28.5048 ) | ||||
| [node name="Crate" parent="." instance=ExtResource( 18 )] | |||||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 8.32558, -1.44783, 0 ) | |||||
| [connection signal="switch" from="Switch" to="." method="_on_Switch_switch"] | [connection signal="switch" from="Switch" to="." method="_on_Switch_switch"] | ||||
| @@ -0,0 +1,32 @@ | |||||
| [gd_scene load_steps=6 format=2] | |||||
| [ext_resource path="res://jrpg/scripts/entities/crate.gd" type="Script" id=1] | |||||
| [ext_resource path="res://jrpg/scripts/entities/utils/trigger_relay.gd" type="Script" id=2] | |||||
| [sub_resource type="CubeMesh" id=1] | |||||
| size = Vector3( 1.5, 1.5, 1.5 ) | |||||
| [sub_resource type="BoxShape" id=2] | |||||
| extents = Vector3( 0.75, 0.75, 0.75 ) | |||||
| [sub_resource type="BoxShape" id=3] | |||||
| extents = Vector3( 0.75, 0.75, 0.75 ) | |||||
| [node name="Crate" type="KinematicBody"] | |||||
| script = ExtResource( 1 ) | |||||
| [node name="MeshInstance" type="MeshInstance" parent="."] | |||||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0 ) | |||||
| mesh = SubResource( 1 ) | |||||
| material/0 = null | |||||
| [node name="CollisionShape" type="CollisionShape" parent="."] | |||||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0 ) | |||||
| shape = SubResource( 2 ) | |||||
| [node name="InteractableArea" type="Area" parent="."] | |||||
| script = ExtResource( 2 ) | |||||
| [node name="CollisionShape" type="CollisionShape" parent="InteractableArea"] | |||||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0 ) | |||||
| shape = SubResource( 3 ) | |||||
| @@ -30,4 +30,3 @@ script = ExtResource( 3 ) | |||||
| transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1, 0 ) | transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1, 0 ) | ||||
| shape = SubResource( 2 ) | shape = SubResource( 2 ) | ||||
| [connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"] | [connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"] | ||||
| [connection signal="on_interact" from="InteractableArea" to="." method="on_interact"] | |||||
| @@ -98,4 +98,3 @@ script = ExtResource( 2 ) | |||||
| [node name="CollisionShape" type="CollisionShape" parent="InteractableArea"] | [node name="CollisionShape" type="CollisionShape" parent="InteractableArea"] | ||||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.35, 0 ) | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.35, 0 ) | ||||
| shape = SubResource( 7 ) | shape = SubResource( 7 ) | ||||
| [connection signal="on_interact" from="InteractableArea" to="." method="on_interact"] | |||||
| @@ -0,0 +1,8 @@ | |||||
| extends KinematicBody | |||||
| func on_interact_pressed(interactor): | |||||
| interactor.start_pushing(self) | |||||
| func on_interact_released(interactor): | |||||
| interactor.stop_pushing(self) | |||||
| @@ -4,5 +4,5 @@ class_name NPC | |||||
| var yarn_script : Resource | var yarn_script : Resource | ||||
| func on_interact(): | |||||
| func on_interact_pressed(interactor): | |||||
| EventDispatcher.emit_signal("trigger_script", yarn_script) | EventDispatcher.emit_signal("trigger_script", yarn_script) | ||||
| @@ -10,9 +10,9 @@ func _process (delta): | |||||
| # rotate along the Y axis | # rotate along the Y axis | ||||
| rotate_y(rotateSpeed * delta) | rotate_y(rotateSpeed * delta) | ||||
| func on_touch(body : KinematicBody): | |||||
| func on_touch(interactor : KinematicBody): | |||||
| # is this the player? If so give them gold | # is this the player? If so give them gold | ||||
| if body.is_in_group("Player"): | |||||
| body.give_gold(goldToGive) | |||||
| if interactor.is_in_group("Player"): | |||||
| interactor.give_gold(goldToGive) | |||||
| emit_signal("picked_up") | emit_signal("picked_up") | ||||
| queue_free() | queue_free() | ||||
| @@ -19,10 +19,19 @@ onready var camera = get_node("CameraOrbit") | |||||
| onready var interactCast = get_node("InteractRayCast") | onready var interactCast = get_node("InteractRayCast") | ||||
| onready var anim = get_node("Casual2_Female/AnimationPlayer") | onready var anim = get_node("Casual2_Female/AnimationPlayer") | ||||
| # internal | |||||
| var interactables := [] | |||||
| var pushed_object | |||||
| func _process(delta): | func _process(delta): | ||||
| # attack input | # attack input | ||||
| if Controller.player_input_enabled and is_on_floor() and Input.is_action_just_pressed("interact"): | |||||
| try_interact() | |||||
| if Controller.player_input_enabled and is_on_floor(): | |||||
| if Input.is_action_just_pressed("interact"): | |||||
| try_interact_pressed() | |||||
| if Input.is_action_just_released("interact"): | |||||
| try_interact_released() | |||||
| for area in $TouchableArea.get_overlapping_areas(): | for area in $TouchableArea.get_overlapping_areas(): | ||||
| try_touch(area) | try_touch(area) | ||||
| @@ -62,7 +71,7 @@ func _physics_process (delta): | |||||
| vel.z = dir.z * walkSpeed | vel.z = dir.z * walkSpeed | ||||
| # jump input | # jump input | ||||
| if Input.is_action_pressed("jump") and is_on_floor(): | |||||
| if can_jump(): | |||||
| vel.y = jumpForce | vel.y = jumpForce | ||||
| else: | else: | ||||
| vel.x = 0 | vel.x = 0 | ||||
| @@ -80,8 +89,14 @@ func _physics_process (delta): | |||||
| else: | else: | ||||
| anim.play("RecieveHit") | anim.play("RecieveHit") | ||||
| # move along the current velocity | |||||
| var previous_vel = vel | var previous_vel = vel | ||||
| # move pushed object first if there is one | |||||
| if pushed_object: | |||||
| var object_vel = pushed_object.move_and_slide(vel, Vector3.UP, true, 1, deg2rad(30)) | |||||
| vel.x = object_vel.x | |||||
| vel.z = object_vel.z | |||||
| # move along the current velocity | |||||
| vel = move_and_slide(vel, Vector3.UP, true, 4, deg2rad(30)) | vel = move_and_slide(vel, Vector3.UP, true, 4, deg2rad(30)) | ||||
| "debug for water" | "debug for water" | ||||
| @@ -116,11 +131,33 @@ func try_touch(area): | |||||
| area.on_touch(self) | area.on_touch(self) | ||||
| # called when we press the interact button | # called when we press the interact button | ||||
| func try_interact(): | |||||
| # is the ray cast colliding with an enemy? | |||||
| func try_interact_pressed(): | |||||
| # play the animation | |||||
| anim.stop() | |||||
| anim.play("Idle") | |||||
| for area in $InteractorArea.get_overlapping_areas(): | for area in $InteractorArea.get_overlapping_areas(): | ||||
| # play the animation | |||||
| anim.stop() | |||||
| anim.play("Idle") | |||||
| if area.has_method("on_interact"): | |||||
| area.on_interact() | |||||
| if area.has_method("on_interact_pressed"): | |||||
| interactables.push_back(area) | |||||
| area.on_interact_pressed(self) | |||||
| # called when we release the interact button | |||||
| func try_interact_released(): | |||||
| # play the animation | |||||
| anim.stop() | |||||
| anim.play("Idle") | |||||
| for interactable in interactables: | |||||
| if interactable.has_method("on_interact_released"): | |||||
| interactable.on_interact_released(self) | |||||
| interactables.clear() | |||||
| func start_pushing(body): | |||||
| pushed_object = body | |||||
| func stop_pushing(body): | |||||
| pushed_object = null | |||||
| func can_jump(): | |||||
| return pushed_object == null and Input.is_action_pressed("jump") and is_on_floor() | |||||
| @@ -11,7 +11,7 @@ func _ready(): | |||||
| update_view() | update_view() | ||||
| emit_signal("switch", activated) | emit_signal("switch", activated) | ||||
| func on_interact(): | |||||
| func on_interact_pressed(interactor): | |||||
| activated = !activated | activated = !activated | ||||
| update_view() | update_view() | ||||
| emit_signal("switch", activated) | emit_signal("switch", activated) | ||||
| @@ -1,6 +1,20 @@ | |||||
| extends Node | extends Node | ||||
| signal on_interact() | |||||
| export var target_path : NodePath = ".." | |||||
| func on_interact(): | |||||
| emit_signal("on_interact") | |||||
| signal on_interact_pressed | |||||
| signal on_interact_released | |||||
| func _ready(): | |||||
| if target_path: | |||||
| var target_node = get_node(target_path) | |||||
| if target_node != null and target_node.has_method("on_interact_pressed"): | |||||
| self.connect("on_interact_pressed", target_node, "on_interact_pressed") | |||||
| if target_node != null and target_node.has_method("on_interact_released"): | |||||
| self.connect("on_interact_released", target_node, "on_interact_released") | |||||
| func on_interact_pressed(interactor): | |||||
| emit_signal("on_interact_pressed", interactor) | |||||
| func on_interact_released(interactor): | |||||
| emit_signal("on_interact_released", interactor) | |||||
| @@ -59,11 +59,6 @@ _global_script_classes=[ { | |||||
| "language": "GDScript", | "language": "GDScript", | ||||
| "path": "res://jrpg/scripts/misc/test_level.gd" | "path": "res://jrpg/scripts/misc/test_level.gd" | ||||
| }, { | }, { | ||||
| "base": "Node", | |||||
| "class": "YarnImporter", | |||||
| "language": "GDScript", | |||||
| "path": "res://yarn/scripts/yarn-importer.gd" | |||||
| }, { | |||||
| "base": "Object", | "base": "Object", | ||||
| "class": "YarnRunner", | "class": "YarnRunner", | ||||
| "language": "GDScript", | "language": "GDScript", | ||||
| @@ -90,7 +85,6 @@ _global_script_class_icons={ | |||||
| "SpeechPanel": "", | "SpeechPanel": "", | ||||
| "SpeechText": "", | "SpeechText": "", | ||||
| "TestLevel": "", | "TestLevel": "", | ||||
| "YarnImporter": "", | |||||
| "YarnRunner": "", | "YarnRunner": "", | ||||
| "YarnRunnerNode": "", | "YarnRunnerNode": "", | ||||
| "YarnScript": "" | "YarnScript": "" | ||||
| @@ -1 +0,0 @@ | |||||
| Yojson.Json_error("Line 100, bytes 20-53:\nInvalid escape sequence 'Users\\Arnaud\\scoop\\apps\\godot\\cur'"): | |||||
| @@ -1,19 +0,0 @@ | |||||
| [gd_scene load_steps=4 format=2] | |||||
| [ext_resource path="res://jrpg/scenes/ui/ChoicesBox.tscn" type="PackedScene" id=1] | |||||
| [ext_resource path="res://main/scenes/LogPanel.tscn" type="PackedScene" id=2] | |||||
| [ext_resource path="res://yarn/scripts/YarnSpinner.gd" type="Script" id=3] | |||||
| [node name="YarnSpinner" type="Control"] | |||||
| anchor_right = 1.0 | |||||
| anchor_bottom = 1.0 | |||||
| script = ExtResource( 3 ) | |||||
| __meta__ = { | |||||
| "_edit_use_anchors_": false | |||||
| } | |||||
| [node name="ChoicesBox" parent="." instance=ExtResource( 1 )] | |||||
| [node name="LogPanel" parent="." instance=ExtResource( 2 )] | |||||
| @@ -1,25 +0,0 @@ | |||||
| extends YarnImporter | |||||
| export var yarn_file = "" | |||||
| func _ready(): | |||||
| $ChoicesBox.hide() | |||||
| $LogPanel.hide() | |||||
| func on_dialogue_start(): | |||||
| yield(.on_dialogue_start(), "completed") | |||||
| $LogPanel.show() | |||||
| $ChoicesBox.show() | |||||
| $LogPanel.clear() | |||||
| $ChoicesBox.clear() | |||||
| func on_new_line(line): | |||||
| yield($LogPanel.on_new_line(line), "completed") | |||||
| func on_choices(choices_list): | |||||
| return yield($ChoicesBox.on_choices(choices_list), "completed") | |||||
| func on_dialogue_end(): | |||||
| yield(.on_dialogue_end(), "completed") | |||||
| $ChoicesBox.hide() | |||||
| $LogPanel.hide() | |||||
| @@ -1,355 +0,0 @@ | |||||
| extends Node | |||||
| class_name YarnImporter | |||||
| # | |||||
| # A YARN Importer for Godot | |||||
| # | |||||
| # Credits: | |||||
| # - Dave Kerr (http://www.naturallyintelligent.com) | |||||
| # | |||||
| # Latest: https://github.com/naturally-intelligent/godot-yarn-importer | |||||
| # | |||||
| # Yarn: https://github.com/InfiniteAmmoInc/Yarn | |||||
| # Twine: http://twinery.org | |||||
| # | |||||
| # Yarn: a ball of threads (Yarn file) | |||||
| # Thread: a series of fibres (Yarn node) | |||||
| # Fibre: a text or choice or logic (Yarn line) | |||||
| var yarn = {} | |||||
| # OVERRIDE METHODS | |||||
| # | |||||
| # called to request new dialog | |||||
| func on_new_line(text): | |||||
| pass | |||||
| # called to request new choice button | |||||
| func on_choices(choices_list): | |||||
| pass | |||||
| # called to request internal logic handling | |||||
| func logic(instruction, command): | |||||
| pass | |||||
| # called for each line of text | |||||
| func yarn_text_variables(text): | |||||
| return text | |||||
| # called when "settings" node parsed | |||||
| func story_setting(setting, value): | |||||
| pass | |||||
| # called for each node name | |||||
| func on_node_start(to): | |||||
| pass | |||||
| yield(get_tree(), "idle_frame") | |||||
| # called for each node name (after) | |||||
| func on_node_end(to): | |||||
| pass | |||||
| yield(get_tree(), "idle_frame") | |||||
| # START SPINNING YOUR YARN | |||||
| # | |||||
| func spin_yarn(file, start_thread = false): | |||||
| yarn = load_yarn(file) | |||||
| # Find the starting thread... | |||||
| if not start_thread: | |||||
| start_thread = yarn['start'] | |||||
| # Load any scene-specific settings | |||||
| # (Not part of official Yarn standard) | |||||
| if 'settings' in yarn['threads']: | |||||
| var settings = yarn['threads']['settings'] | |||||
| for fibre in settings['fibres']: | |||||
| var line = fibre['text'] | |||||
| var split = line.split('=') | |||||
| var setting = split[0].strip_edges(true, true) | |||||
| var value = split[1].strip_edges(true, true) | |||||
| story_setting(setting, value) | |||||
| # First thread unravel... | |||||
| yield(on_dialogue_start(), "completed") | |||||
| yield(yarn_unravel(start_thread), "completed") | |||||
| # Internally create a new thread (during loading) | |||||
| func new_yarn_thread(): | |||||
| var thread = {} | |||||
| thread['title'] = '' | |||||
| thread['kind'] = 'branch' # 'branch' for standard dialog, 'code' for gdscript | |||||
| thread['tags'] = [] # unused | |||||
| thread['fibres'] = [] | |||||
| return thread | |||||
| func exec(stri): | |||||
| var expr := Expression.new() | |||||
| print("input : " + stri) | |||||
| var err := expr.parse(stri) | |||||
| if err == OK: | |||||
| var res = expr.execute() | |||||
| print("res : " + str(res)) | |||||
| else: | |||||
| print("err : " + str(err)) | |||||
| func jajoujaj(): | |||||
| print("jaaaja") | |||||
| # Internally create a new fibre (during loading) | |||||
| func new_yarn_fibre(line:String): | |||||
| # choice fibre | |||||
| if line.substr(0,2) == '[[': | |||||
| if line.find('|') != -1: | |||||
| var fibre = {} | |||||
| fibre['kind'] = 'choice' | |||||
| line = line.replace('[[', '') | |||||
| line = line.replace(']]', '') | |||||
| var split = line.split('|') | |||||
| fibre['text'] = split[0] | |||||
| fibre['marker'] = split[1] | |||||
| return fibre | |||||
| else: | |||||
| var fibre = {} | |||||
| fibre['kind'] = 'jump' | |||||
| line = line.replace('[[', '') | |||||
| line = line.replace(']]', '') | |||||
| fibre['marker'] = line | |||||
| return fibre | |||||
| # logic instruction (not part of official Yarn standard) | |||||
| elif line.substr(0,2) == '<<': | |||||
| line = line.replace('<<', '') | |||||
| line = line.replace('>>', '') | |||||
| var line_split = line.split(' ') | |||||
| print (line_split) | |||||
| var command = line.substr(line.find(' ')) | |||||
| exec(command) | |||||
| # if line.find(':') != -1: | |||||
| # fibre['kind'] = 'logic' | |||||
| # line = line.replace('<<', '') | |||||
| # line = line.replace('>>', '') | |||||
| # var split = line.split(':') | |||||
| # fibre['instruction'] = split[0] | |||||
| # fibre['command'] = split[1] | |||||
| # #print(line, split[0], split[1]) | |||||
| # return fibre | |||||
| # text fibre | |||||
| var fibre = {} | |||||
| fibre['kind'] = 'text' | |||||
| fibre['text'] = line | |||||
| return fibre | |||||
| # Create Yarn data structure from file (must be *.yarn.txt Yarn format) | |||||
| func load_yarn(path): | |||||
| var yarn = {} | |||||
| yarn['threads'] = {} | |||||
| yarn['start'] = false | |||||
| yarn['file'] = path | |||||
| var file = File.new() | |||||
| file.open(path, file.READ) | |||||
| if file.is_open(): | |||||
| # yarn reading flags | |||||
| var start = false | |||||
| var header = true | |||||
| var thread = new_yarn_thread() | |||||
| # loop | |||||
| while !file.eof_reached(): | |||||
| # read a line | |||||
| var line = file.get_line() | |||||
| # header read mode | |||||
| if header: | |||||
| if line == '---': | |||||
| header = false | |||||
| else: | |||||
| var split = line.split(': ') | |||||
| if split[0] == 'title': | |||||
| var title_split = split[1].split(':') | |||||
| var thread_title = '' | |||||
| var thread_kind = 'branch' | |||||
| if len(title_split) == 1: | |||||
| thread_title = split[1] | |||||
| else: | |||||
| thread_title = title_split[1] | |||||
| thread_kind = title_split[0] | |||||
| thread['title'] = thread_title | |||||
| thread['kind'] = thread_kind | |||||
| if not yarn['start']: | |||||
| yarn['start'] = thread_title | |||||
| # end of thread | |||||
| elif line == '===': | |||||
| header = true | |||||
| yarn['threads'][thread['title']] = thread | |||||
| thread = new_yarn_thread() | |||||
| # fibre read mode | |||||
| else: | |||||
| var fibre = new_yarn_fibre(line) | |||||
| if fibre: | |||||
| thread['fibres'].append(fibre) | |||||
| else: | |||||
| print('ERROR: Yarn file missing: ', filename) | |||||
| return yarn | |||||
| # Main logic for node handling | |||||
| # | |||||
| func yarn_unravel(to, from=false): | |||||
| if not to in yarn['threads']: | |||||
| print('WARNING: Missing Yarn thread: ', to, ' in file ',yarn['file']) | |||||
| return | |||||
| while to != null and to in yarn['threads']: | |||||
| yield (on_node_start(to), "completed") | |||||
| if to in yarn['threads']: | |||||
| var thread = yarn['threads'][to] | |||||
| to = null | |||||
| match thread['kind']: | |||||
| 'branch': | |||||
| var i = 0 | |||||
| while i < thread['fibres'].size(): | |||||
| match thread['fibres'][i]['kind']: | |||||
| 'text': | |||||
| var fibre = thread['fibres'][i] | |||||
| var text = yarn_text_variables(fibre['text']) | |||||
| yield(on_new_line(text), "completed") | |||||
| 'choice': | |||||
| var choices = [] | |||||
| while i < thread['fibres'].size() and thread['fibres'][i]['kind'] == 'choice' : | |||||
| var fibre = thread['fibres'][i] | |||||
| var text = yarn_text_variables(fibre['text']) | |||||
| choices.push_back({"text": text, "marker": fibre['marker']}) | |||||
| i += 1 | |||||
| to = yield(on_choices(choices), "completed") | |||||
| break | |||||
| 'logic': | |||||
| var fibre = thread['fibres'][i] | |||||
| var instruction = fibre['instruction'] | |||||
| var command = fibre['command'] | |||||
| yield(logic(instruction, command), "completed") | |||||
| 'jump': | |||||
| var fibre = thread['fibres'][i] | |||||
| to = fibre['marker'] | |||||
| break | |||||
| i += 1 | |||||
| 'code': | |||||
| yarn_code(to) | |||||
| yield(on_node_end(to), "completed") | |||||
| yield (on_dialogue_end(), "completed") | |||||
| func on_dialogue_start(): | |||||
| pass | |||||
| yield(get_tree(), "idle_frame") | |||||
| func on_dialogue_end(): | |||||
| pass | |||||
| yield(get_tree(), "idle_frame") | |||||
| # | |||||
| # RUN GDSCRIPT CODE FROM YARN NODE - Special node = code:title | |||||
| # - Not part of official Yarn standard | |||||
| # | |||||
| func yarn_code(title, run=true, parent='parent.', tabs="\t", next_func="yarn_unravel"): | |||||
| if title in yarn['threads']: | |||||
| var thread = yarn['threads'][title] | |||||
| var code = '' | |||||
| for fibre in thread['fibres']: | |||||
| match fibre['kind']: | |||||
| 'text': | |||||
| var line = yarn_text_variables(fibre['text']) | |||||
| line = yarn_code_replace(line, parent, next_func) | |||||
| code += tabs + line + "\n" | |||||
| 'choice': | |||||
| var line = parent+next_func+"('"+fibre['marker']+"')" | |||||
| print(line) | |||||
| code += tabs + line + "\n" | |||||
| if run: | |||||
| run_yarn_code(code) | |||||
| else: | |||||
| return code | |||||
| else: | |||||
| print('WARNING: Title missing in yarn ball: ', title) | |||||
| # override to replace convenience variables | |||||
| func yarn_code_replace(code, parent='parent.', next_func="yarn_unravel"): | |||||
| if code.find("[[") != -1: | |||||
| code = code.replace("[[", parent+next_func+"('") | |||||
| code = code.replace("]]", "')") | |||||
| code = code.replace("say(", parent+"say(") | |||||
| code = code.replace("choice(", parent+"choice(") | |||||
| return code | |||||
| func run_yarn_code(code): | |||||
| var front = "extends Node\n" | |||||
| front += "func dynamic_code():\n" | |||||
| front += "\tvar parent = get_parent()\n\n" | |||||
| code = front + code | |||||
| #print("CODE BLOCK: \n", code) | |||||
| var script = GDScript.new() | |||||
| script.set_source_code(code) | |||||
| script.reload() | |||||
| #print("Executing code...") | |||||
| var node = Node.new() | |||||
| node.set_script(script) | |||||
| add_child(node) | |||||
| var result = node.dynamic_code() | |||||
| remove_child(node) | |||||
| return result | |||||
| # EXPORTING TO GDSCRIPT | |||||
| # | |||||
| # This code may not be directly usable | |||||
| # Use if you need an exit from Yarn | |||||
| func export_to_gdscript(): | |||||
| var script = '' | |||||
| script += "func start_story():\n\n" | |||||
| if 'settings' in yarn['threads']: | |||||
| var settings = yarn['threads']['settings'] | |||||
| for fibre in settings['fibres']: | |||||
| var line = fibre['text'] | |||||
| var split = line.split('=') | |||||
| var setting = split[0].strip_edges(true, true) | |||||
| var value = split[1].strip_edges(true, true) | |||||
| script += "\t" + 'story_setting("' + setting + '", "' + value + '")' + "\n" | |||||
| script += "\tstory_logic('" + yarn['start'] + "')\n\n" | |||||
| # story logic choice/press event | |||||
| script += "func story_logic(marker):\n\n" | |||||
| script += "\tmatch marker:\n" | |||||
| for title in yarn['threads']: | |||||
| var thread = yarn['threads'][title] | |||||
| match thread['kind']: | |||||
| 'branch': | |||||
| var code = "\n\t\t'" + thread['title'] + "':" | |||||
| var tabs = "\n\t\t\t" | |||||
| for fibre in thread['fibres']: | |||||
| match fibre['kind']: | |||||
| 'text': | |||||
| code += tabs + 'say("' + fibre['text'] + '")' | |||||
| 'choice': | |||||
| code += tabs + 'choice("' + fibre['text'] + '", "' + fibre['marker'] + '")' | |||||
| 'logic': | |||||
| code += tabs + 'logic("' + fibre['instruction'] + '", "' + fibre['command'] + '")' | |||||
| script += code + "\n" | |||||
| 'code': | |||||
| var code = "\n\t\t'" + thread['title'] + "':" | |||||
| var tabs = "\n\t\t\t" | |||||
| code += "\n" | |||||
| code += yarn_code(thread['title'], false, '', "\t\t\t", "story_logic") | |||||
| script += code + "\n" | |||||
| # done | |||||
| return script | |||||
| func print_gdscript_to_console(): | |||||
| print(export_to_gdscript()) | |||||
| func save_to_gdscript(filename): | |||||
| var script = export_to_gdscript() | |||||
| # write to file | |||||
| var file = File.new() | |||||
| file.open(filename, file.WRITE) | |||||
| if not file.is_open(): | |||||
| print('ERROR: Cant open file ', filename) | |||||
| return false | |||||
| file.store_string(script) | |||||
| file.close() | |||||