Author | SHA1 | Message | Date |
---|---|---|---|
Non0w | 325e7aa0d4 | add draft crate push | 4 years ago |
Non0w | b59b2109ab | remove old yarn files | 4 years ago |
@@ -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/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/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/Crate.tscn" type="PackedScene" id=18] | |||
[sub_resource type="PlaneMesh" id=1] | |||
size = Vector2( 600, 600 ) | |||
@@ -418,4 +419,7 @@ shape = SubResource( 14 ) | |||
[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 ) | |||
[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"] |
@@ -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 ) | |||
shape = SubResource( 2 ) | |||
[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"] | |||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.35, 0 ) | |||
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 | |||
func on_interact(): | |||
func on_interact_pressed(interactor): | |||
EventDispatcher.emit_signal("trigger_script", yarn_script) |
@@ -10,9 +10,9 @@ func _process (delta): | |||
# rotate along the Y axis | |||
rotate_y(rotateSpeed * delta) | |||
func on_touch(body : KinematicBody): | |||
func on_touch(interactor : KinematicBody): | |||
# 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") | |||
queue_free() |
@@ -19,10 +19,19 @@ onready var camera = get_node("CameraOrbit") | |||
onready var interactCast = get_node("InteractRayCast") | |||
onready var anim = get_node("Casual2_Female/AnimationPlayer") | |||
# internal | |||
var interactables := [] | |||
var pushed_object | |||
func _process(delta): | |||
# 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(): | |||
try_touch(area) | |||
@@ -62,7 +71,7 @@ func _physics_process (delta): | |||
vel.z = dir.z * walkSpeed | |||
# jump input | |||
if Input.is_action_pressed("jump") and is_on_floor(): | |||
if can_jump(): | |||
vel.y = jumpForce | |||
else: | |||
vel.x = 0 | |||
@@ -80,8 +89,14 @@ func _physics_process (delta): | |||
else: | |||
anim.play("RecieveHit") | |||
# move along the current velocity | |||
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)) | |||
"debug for water" | |||
@@ -116,11 +131,33 @@ func try_touch(area): | |||
area.on_touch(self) | |||
# 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(): | |||
# 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() | |||
emit_signal("switch", activated) | |||
func on_interact(): | |||
func on_interact_pressed(interactor): | |||
activated = !activated | |||
update_view() | |||
emit_signal("switch", activated) | |||
@@ -1,6 +1,20 @@ | |||
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", | |||
"path": "res://jrpg/scripts/misc/test_level.gd" | |||
}, { | |||
"base": "Node", | |||
"class": "YarnImporter", | |||
"language": "GDScript", | |||
"path": "res://yarn/scripts/yarn-importer.gd" | |||
}, { | |||
"base": "Object", | |||
"class": "YarnRunner", | |||
"language": "GDScript", | |||
@@ -90,7 +85,6 @@ _global_script_class_icons={ | |||
"SpeechPanel": "", | |||
"SpeechText": "", | |||
"TestLevel": "", | |||
"YarnImporter": "", | |||
"YarnRunner": "", | |||
"YarnRunnerNode": "", | |||
"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() | |||