| @@ -0,0 +1,3 @@ | |||
| source_md5="76b99b929153960dd998ce494f45624c" | |||
| dest_md5="88cc37307aa3b05eef3a6b76f3580d82" | |||
| @@ -0,0 +1,3 @@ | |||
| source_md5="c61d0c6a7cdcb4cfe5bd424b476c9323" | |||
| dest_md5="7e8e7bd22121ab1b5a0809dd00e91900" | |||
| @@ -0,0 +1,3 @@ | |||
| source_md5="9da48ae0e2c8858122bdf1a8b8dd698e" | |||
| dest_md5="348cbedcb0148126d176d7cbcee8e36c" | |||
| @@ -0,0 +1,3 @@ | |||
| source_md5="c61d0c6a7cdcb4cfe5bd424b476c9323" | |||
| dest_md5="7e8e7bd22121ab1b5a0809dd00e91900" | |||
| @@ -1,12 +1,16 @@ | |||
| extends Node | |||
| extends Object | |||
| var YarnScript = preload("yarn_script.gd") | |||
| class_name YarnRunner | |||
| export (Resource) var yarnScript | |||
| var yarnScript : YarnScript | |||
| var say_func : FuncRef = null | |||
| var choices_func : FuncRef = null | |||
| var commands := {} | |||
| signal resume_workaround | |||
| func run_all(): | |||
| var next_node = yarnScript.nodes["Start"] | |||
| while next_node != null: | |||
| @@ -18,9 +22,12 @@ func run_all(): | |||
| next_node = null | |||
| func run_body(body): | |||
| yield(Controller.get_tree(), "idle_frame") # workaround before await | |||
| for element in body: | |||
| if element["type"] == "jump": | |||
| return element["node"] | |||
| elif element["type"] == "command": | |||
| yield(run_command(element["command"], element["args"]), "completed") | |||
| elif element["type"] == "choice_blocks": | |||
| var block = yield(decide_choice_block(element["blocks"]), "completed") | |||
| print(block) | |||
| @@ -32,14 +39,22 @@ func run_body(body): | |||
| return next_node_key | |||
| else: | |||
| if say_func == null or !say_func.is_valid(): | |||
| print(element) | |||
| printerr("no say_func provided") | |||
| else: | |||
| yield(say_func.call_func(element), "completed") | |||
| return "" | |||
| func add_command(command_key, function): | |||
| commands[command_key] = function | |||
| func run_command(command_key, args): | |||
| if (commands.has(command_key)): | |||
| var command : FuncRef = commands[command_key] | |||
| yield(command.call_func(args), "completed") | |||
| func decide_choice_block(blocks): | |||
| if choices_func == null or !choices_func.is_valid(): | |||
| return blocks[0] | |||
| printerr("no choices_func provided") | |||
| else: | |||
| return yield(choices_func.call_func(blocks), "completed") | |||
| @@ -0,0 +1,24 @@ | |||
| extends Node | |||
| class_name YarnRunnerNode | |||
| var yarnRunner := YarnRunner.new() | |||
| export var yarnScript : Resource | |||
| func start_script(): | |||
| yarnRunner.say_func = funcref(self, "on_new_line") | |||
| yarnRunner.choices_func = funcref(self, "on_choices") | |||
| yarnRunner.yarnScript = self.yarnScript | |||
| yield(yarnRunner.run_all(), "completed") | |||
| func on_new_line(line): | |||
| print(line) | |||
| yield(get_tree(),"idle_frame") | |||
| func on_choices(blocks): | |||
| print(blocks) | |||
| yield(get_tree(),"idle_frame") | |||
| print("Default choice taken : " + str(blocks[0])) | |||
| return blocks[0] | |||
| @@ -1,3 +1,5 @@ | |||
| extends Resource | |||
| class_name YarnScript | |||
| export var nodes = {} | |||
| @@ -91,6 +91,8 @@ func parse_condition_blocks(file, parsed_line): | |||
| var current_block = {"condition":parsed_line["expression"], "body":[]} | |||
| # print("[" + parsed_line["type"] + "]\n\t" + str(parsed_line)) | |||
| while not file.eof_reached(): | |||
| parsed_line = parse_line_body(file.get_line()) | |||
| var type = parsed_line["type"] | |||
| @@ -159,6 +161,10 @@ func parse_line_body(raw_line : String): | |||
| parsed_line["type"] = CONDITION_IF | |||
| var expr := "" | |||
| for token in Array(split).slice(1, split.size() -1): | |||
| if token == "False": | |||
| token = "false" | |||
| elif token == "True": | |||
| token = "true" | |||
| expr += token + " " | |||
| parsed_line["expression"] = expr | |||
| elif split[0] == "elseif": | |||
| @@ -6,11 +6,11 @@ var yarn_spinner_importer | |||
| func _enter_tree(): | |||
| yarn_spinner_importer = preload("yarn_spinner_importer.gd").new() | |||
| add_custom_type("YarnScript", "Resource", preload("yarn_script.gd"), preload("icon.png")) | |||
| add_custom_type("YarnRunner", "Node", preload("yarn_runner.gd"), preload("icon.png")) | |||
| add_custom_type("YarnRunnerNode", "Node", preload("yarn_runner_node.gd"), preload("icon.png")) | |||
| add_import_plugin(yarn_spinner_importer) | |||
| func _exit_tree(): | |||
| remove_custom_type("YarnScript") | |||
| remove_custom_type("YarnRunner") | |||
| remove_custom_type("YarnRunnerNode") | |||
| remove_import_plugin(yarn_spinner_importer) | |||
| yarn_spinner_importer = null | |||
| @@ -3,5 +3,5 @@ | |||
| [ext_resource path="res://jrpg/fonts/Puritan-Regular.otf" type="DynamicFontData" id=1] | |||
| [resource] | |||
| size = 30 | |||
| size = 20 | |||
| font_data = ExtResource( 1 ) | |||
| @@ -0,0 +1,18 @@ | |||
| [gd_scene load_steps=2 format=2] | |||
| [ext_resource path="res://jrpg/fonts/puritan.tres" type="DynamicFont" id=1] | |||
| [node name="TestGameOver" type="Control"] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| [node name="Label" type="Label" parent="."] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| custom_fonts/font = ExtResource( 1 ) | |||
| text = "Game Over" | |||
| align = 1 | |||
| valign = 1 | |||
| @@ -0,0 +1,20 @@ | |||
| [gd_scene load_steps=6 format=2] | |||
| [ext_resource path="res://addons/yarn_spinner/yarn_runner_node.gd" type="Script" id=1] | |||
| [ext_resource path="res://jrpg/scripts/misc/test_main.gd" type="Script" id=2] | |||
| [ext_resource path="res://jrpg/yarn_scripts/main_debug.yarn" type="Resource" id=3] | |||
| [ext_resource path="res://jrpg/scenes/TestLVL.tscn" type="PackedScene" id=4] | |||
| [ext_resource path="res://jrpg/scenes/TestGameOver.tscn" type="PackedScene" id=5] | |||
| [node name="TestMain" type="Node"] | |||
| script = ExtResource( 2 ) | |||
| scenes = { | |||
| "TestGameOver": ExtResource( 5 ), | |||
| "TestLVL": ExtResource( 4 ) | |||
| } | |||
| [node name="YarnRunnerNode" type="Node" parent="."] | |||
| script = ExtResource( 1 ) | |||
| yarnScript = ExtResource( 3 ) | |||
| [node name="SceneContainer" type="Node" parent="."] | |||
| @@ -1,7 +1,7 @@ | |||
| [gd_scene load_steps=4 format=2] | |||
| [ext_resource path="res://jrpg/models/chars/Zombie_Male.glb" type="PackedScene" id=1] | |||
| [ext_resource path="res://jrpg/scripts/enemy.gd" type="Script" id=2] | |||
| [ext_resource path="res://jrpg/scripts/entities/enemy.gd" type="Script" id=2] | |||
| [sub_resource type="CapsuleShape" id=1] | |||
| radius = 0.5 | |||
| @@ -1,7 +1,7 @@ | |||
| [gd_scene load_steps=6 format=2] | |||
| [ext_resource path="res://jrpg/models/coinGold.glb" type="PackedScene" id=1] | |||
| [ext_resource path="res://jrpg/scripts/pickup.gd" type="Script" id=2] | |||
| [ext_resource path="res://jrpg/scripts/entities/pickup.gd" type="Script" id=2] | |||
| [ext_resource path="res://jrpg/models/gold.material" type="Material" id=3] | |||
| [ext_resource path="res://jrpg/models/wood.material" type="Material" id=4] | |||
| @@ -1,8 +1,8 @@ | |||
| [gd_scene load_steps=5 format=2] | |||
| [ext_resource path="res://jrpg/models/chars/Casual2_Female.glb" type="PackedScene" id=1] | |||
| [ext_resource path="res://jrpg/scripts/camera/camera_orbit.gd" type="Script" id=3] | |||
| [ext_resource path="res://jrpg/scripts/player.gd" type="Script" id=4] | |||
| [ext_resource path="res://jrpg/scripts/entities/camera/camera_orbit.gd" type="Script" id=3] | |||
| [ext_resource path="res://jrpg/scripts/entities/player.gd" type="Script" id=4] | |||
| [sub_resource type="CapsuleShape" id=1] | |||
| radius = 0.5 | |||
| @@ -25,9 +25,9 @@ script = ExtResource( 3 ) | |||
| transform = Transform( -1, 0, -3.25841e-07, 0, 1, 0, 3.25841e-07, 0, -1, -1, 1, -5 ) | |||
| current = true | |||
| [node name="AttackRayCast" type="RayCast" parent="."] | |||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.3, 1, 0.6 ) | |||
| [node name="InteractRayCast" type="RayCast" parent="."] | |||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.3, 1, 0.2 ) | |||
| enabled = true | |||
| cast_to = Vector3( 0, 0, 1.5 ) | |||
| cast_to = Vector3( 0, 0, 1.7 ) | |||
| [editable path="Casual2_Female"] | |||
| @@ -1,10 +1,12 @@ | |||
| [gd_scene load_steps=2 format=2] | |||
| [gd_scene load_steps=3 format=2] | |||
| [ext_resource path="res://main/scripts/LogPanel.gd" type="Script" id=1] | |||
| [ext_resource path="res://jrpg/scripts/ui/speech_text.gd" type="Script" id=1] | |||
| [ext_resource path="res://jrpg/fonts/puritan.tres" type="DynamicFont" id=2] | |||
| [node name="LogPanel" type="Control"] | |||
| [node name="BubblePanel" type="Control"] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| margin_right = -232.0 | |||
| margin_bottom = 212.0 | |||
| script = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| @@ -19,6 +21,7 @@ anchor_left = 0.02 | |||
| anchor_top = 0.05 | |||
| anchor_right = 0.98 | |||
| anchor_bottom = 0.95 | |||
| custom_fonts/normal_font = ExtResource( 2 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| [gd_scene load_steps=2 format=2] | |||
| [ext_resource path="res://jrpg/fonts/puritan.tres" type="DynamicFont" id=1] | |||
| [node name="ChoiceButton" type="Button"] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| custom_fonts/font = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| [gd_scene load_steps=3 format=2] | |||
| [ext_resource path="res://jrpg/scripts/ui/choices_box.gd" type="Script" id=1] | |||
| [ext_resource path="res://jrpg/scenes/ui/ChoiceButton.tscn" type="PackedScene" id=2] | |||
| [node name="ChoicesBox" type="VBoxContainer"] | |||
| anchor_left = 0.3 | |||
| anchor_top = 0.1 | |||
| anchor_right = 0.7 | |||
| anchor_bottom = 0.45 | |||
| script = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| button_template = ExtResource( 2 ) | |||
| @@ -2,25 +2,26 @@ | |||
| [ext_resource path="res://jrpg/fonts/puritan.tres" type="DynamicFont" id=1] | |||
| [ext_resource path="res://jrpg/textures/white_square.png" type="Texture" id=2] | |||
| [ext_resource path="res://jrpg/scripts/test_ui.gd" type="Script" id=3] | |||
| [ext_resource path="res://jrpg/scripts/ui/test_hud.gd" type="Script" id=3] | |||
| [node name="UI" type="Control"] | |||
| [node name="HUD" type="Control"] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| script = ExtResource( 3 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| healthBar_path = NodePath("HealthBar") | |||
| goldText_path = NodePath("GoldText") | |||
| healthBar_path = NodePath("../HUD/HealthBar") | |||
| goldText_path = NodePath("../HUD/GoldText") | |||
| [node name="GoldText" type="Label" parent="."] | |||
| anchor_top = 1.0 | |||
| anchor_bottom = 1.0 | |||
| margin_left = 36.0 | |||
| margin_top = -133.0 | |||
| margin_right = 293.0 | |||
| margin_bottom = -94.0 | |||
| margin_left = 35.4703 | |||
| margin_top = -158.427 | |||
| margin_right = 292.47 | |||
| margin_bottom = -91.4271 | |||
| custom_fonts/font = ExtResource( 1 ) | |||
| text = "Gold : 500" | |||
| valign = 1 | |||
| @@ -0,0 +1,16 @@ | |||
| [gd_scene load_steps=3 format=2] | |||
| [ext_resource path="res://jrpg/scripts/ui/speech_text.gd" type="Script" id=1] | |||
| [ext_resource path="res://jrpg/fonts/puritan.tres" type="DynamicFont" id=2] | |||
| [node name="SpeechText" type="Label"] | |||
| anchor_right = 1.0 | |||
| margin_right = -232.0 | |||
| margin_bottom = 212.0 | |||
| custom_fonts/font = ExtResource( 2 ) | |||
| align = 1 | |||
| valign = 1 | |||
| script = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| @@ -1,41 +0,0 @@ | |||
| extends Spatial | |||
| # look stats | |||
| var lookSensitivity : float = 15.0 | |||
| var minLookAngle : float = -20.0 | |||
| var maxLookAngle : float = 75.0 | |||
| # vectors | |||
| var mouseDelta = Vector2() | |||
| # components | |||
| onready var player = get_parent() | |||
| # called when an input is detected | |||
| func _input (event): | |||
| # set "mouseDelta" when we move our mouse | |||
| if event is InputEventMouseMotion: | |||
| mouseDelta = event.relative | |||
| # called every frame | |||
| func _process (delta): | |||
| # get the rotation to apply to the camera and player | |||
| var rot = Vector3(mouseDelta.y, mouseDelta.x, 0) * lookSensitivity * delta | |||
| # camera vertical rotation | |||
| rotation_degrees.x += rot.x | |||
| rotation_degrees.x = clamp(rotation_degrees.x, minLookAngle, maxLookAngle) | |||
| # player horizontal rotation | |||
| player.rotation_degrees.y -= rot.y | |||
| # clear the mouse movement vector | |||
| mouseDelta = Vector2() | |||
| # called when the node is initialized | |||
| func _ready (): | |||
| # hide the mouse cursor | |||
| Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) | |||
| @@ -0,0 +1,47 @@ | |||
| extends Spatial | |||
| # look stats | |||
| var lookSensitivity : float = 15.0 | |||
| var minLookAngle : float = -20.0 | |||
| var maxLookAngle : float = 75.0 | |||
| # vectors | |||
| var mouseDelta = Vector2() | |||
| # components | |||
| onready var player = get_parent() | |||
| # called when the node is initialized | |||
| func _ready (): | |||
| on_player_input_change(Controller.player_input_enabled) | |||
| Controller.connect("player_input_change", self, "on_player_input_change") | |||
| # called when an input is detected | |||
| func _input (event): | |||
| # set "mouseDelta" when we move our mouse | |||
| if Controller.player_input_enabled and event is InputEventMouseMotion: | |||
| mouseDelta = event.relative | |||
| # called every frame | |||
| func _process (delta): | |||
| if Controller.player_input_enabled: | |||
| # get the rotation to apply to the camera and player | |||
| var rot = Vector3(mouseDelta.y, mouseDelta.x, 0) * lookSensitivity * delta | |||
| # camera vertical rotation | |||
| rotation_degrees.x += rot.x | |||
| rotation_degrees.x = clamp(rotation_degrees.x, minLookAngle, maxLookAngle) | |||
| # player horizontal rotation | |||
| player.rotation_degrees.y -= rot.y | |||
| # clear the mouse movement vector | |||
| mouseDelta = Vector2() | |||
| func on_player_input_change(value): | |||
| print(value) | |||
| if value: | |||
| Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) | |||
| else: | |||
| Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) | |||
| @@ -0,0 +1,16 @@ | |||
| extends Node | |||
| class_name BasisInteraction | |||
| export var auto_connect_on_ready := true | |||
| func _ready(): | |||
| init() | |||
| if auto_connect_on_ready: | |||
| get_parent().connect("on_interact", self, "on_interact") | |||
| func init(): | |||
| pass | |||
| func on_interact(): | |||
| print("interact") | |||
| @@ -0,0 +1,26 @@ | |||
| extends BasisInteraction | |||
| var is_talking = false | |||
| export var yarnScript : Resource | |||
| export var speechPanel_path : NodePath | |||
| onready var speechPanel := get_node(speechPanel_path) | |||
| var yarnRunner := YarnRunner.new() | |||
| func on_interact(): | |||
| if not is_talking: | |||
| yarnRunner.say_func = funcref(speechPanel.text, "on_new_line") | |||
| yarnRunner.choices_func = funcref(speechPanel.choices, "on_choices") | |||
| yarnRunner.yarnScript = self.yarnScript | |||
| is_talking = true | |||
| speechPanel.show() | |||
| Controller.player_input_enabled = false | |||
| yield(yarnRunner.run_all(), "completed") | |||
| Controller.player_input_enabled = true | |||
| speechPanel.hide() | |||
| is_talking = false | |||
| @@ -32,6 +32,7 @@ func _on_Timer_timeout (): | |||
| # if we're within the attack distance - attack the player | |||
| if translation.distance_to(player.translation) <= attackDist: | |||
| anim.play("Punch") | |||
| player.take_damage(damage) | |||
| # called 60 times a second | |||
| @@ -50,8 +51,24 @@ func _physics_process (delta): | |||
| # gravity | |||
| vel.y -= gravity * delta | |||
| # TODO better | |||
| look_at(player.translation, Vector3.UP) | |||
| rotation_degrees.x = 0 | |||
| rotation_degrees.y = rotation_degrees.y + 180 | |||
| rotation_degrees.z = 0 | |||
| # move towards the player | |||
| vel = move_and_slide(vel, Vector3.UP) | |||
| if is_on_floor(): | |||
| if anim.current_animation != "Punch" and anim.current_animation != "RecieveHit": | |||
| if vel.length_squared() > 0: | |||
| anim.play("Walk") | |||
| else: | |||
| anim.play("Idle") | |||
| else: | |||
| anim.play("RecieveHit") | |||
| # called when the player deals damage to us | |||
| func take_damage (damageToTake): | |||
| @@ -0,0 +1,4 @@ | |||
| extends Node | |||
| signal on_interact | |||
| signal on_attack | |||
| @@ -0,0 +1,152 @@ | |||
| extends KinematicBody | |||
| # stats | |||
| var curHp : int = 10 | |||
| var maxHp : int = 10 | |||
| var damage : int = 1 | |||
| var gold : int = 0 | |||
| var attackRate : float = 0.3 | |||
| var lastAttackTime : int = 0 | |||
| # physics | |||
| var airborneSpeed : float = 3.0 | |||
| var walkSpeed : float = 5.0 | |||
| var runSpeed : float = 10.0 | |||
| var jumpForce : float = 10.0 | |||
| var gravity : float = 15.0 | |||
| var vel := Vector3() | |||
| # components | |||
| onready var camera = get_node("CameraOrbit") | |||
| onready var interactCast = get_node("InteractRayCast") | |||
| onready var anim = get_node("Casual2_Female/AnimationPlayer") | |||
| export var ui_path : NodePath | |||
| onready var ui = get_node(ui_path) | |||
| # called when the node is initialized | |||
| func _ready (): | |||
| # initialize the UI | |||
| ui.update_health_bar(curHp, maxHp) | |||
| ui.update_gold_text(gold) | |||
| func _process(delta): | |||
| # attack input | |||
| if Controller.player_input_enabled and is_on_floor() and Input.is_action_just_pressed("interact"): | |||
| try_interact() | |||
| # called every physics step (60 times a second) | |||
| func _physics_process (delta): | |||
| var input := Vector3() | |||
| # gravity | |||
| vel.y -= gravity * delta | |||
| if Controller.player_input_enabled : | |||
| # movement inputs | |||
| if Input.is_action_pressed("move_forward"): | |||
| input.z += 1 | |||
| if Input.is_action_pressed("move_backward"): | |||
| input.z -= 1 | |||
| if Input.is_action_pressed("move_left"): | |||
| input.x += 1 | |||
| if Input.is_action_pressed("move_right"): | |||
| input.x -= 1 | |||
| input = input.normalized() | |||
| # get the relative direction | |||
| var dir := (transform.basis.z * input.z + transform.basis.x * input.x) | |||
| # apply the direction to our velocity | |||
| if not is_on_floor(): | |||
| vel.x = lerp(vel.x, dir.x * airborneSpeed, .5 * delta) | |||
| vel.z = lerp(vel.z, dir.z * airborneSpeed, .5 * delta) | |||
| elif Input.is_action_pressed("run"): | |||
| vel.x = dir.x * runSpeed | |||
| vel.z = dir.z * runSpeed | |||
| else: | |||
| vel.x = dir.x * walkSpeed | |||
| vel.z = dir.z * walkSpeed | |||
| # jump input | |||
| if Input.is_action_pressed("jump") and is_on_floor(): | |||
| vel.y = jumpForce | |||
| else: | |||
| vel.x = 0 | |||
| vel.z = 0 | |||
| if is_on_floor(): | |||
| if anim.current_animation != "Punch": | |||
| if input.x != 0 || input.z != 0: | |||
| if Controller.player_input_enabled and Input.is_action_pressed("run"): | |||
| anim.play("Run") | |||
| else: | |||
| anim.play("Walk") | |||
| else: | |||
| anim.play("Idle") | |||
| else: | |||
| anim.play("RecieveHit") | |||
| # move along the current velocity | |||
| var previous_vel = vel | |||
| vel = move_and_slide(vel, Vector3.UP, true, 4, deg2rad(30)) | |||
| if is_on_wall(): | |||
| vel.y = min(previous_vel.y, vel.y) | |||
| # called when we collect a coin | |||
| func give_gold (amount): | |||
| gold += amount | |||
| # update the UI | |||
| ui.update_gold_text(gold) | |||
| # called when an enemy deals damage to us | |||
| func take_damage (damageToTake): | |||
| curHp -= damageToTake | |||
| # update the UI | |||
| ui.update_health_bar(curHp, maxHp) | |||
| # if our health is 0, die | |||
| if curHp <= 0: | |||
| die() | |||
| # called when our health reaches 0 | |||
| func die (): | |||
| # reload the scene | |||
| get_tree().reload_current_scene() | |||
| ## called when we press the attack button | |||
| #func try_attack(): | |||
| # # if we're not ready to attack, return | |||
| # if OS.get_ticks_msec() - lastAttackTime < attackRate * 1000: | |||
| # return | |||
| # | |||
| # # set the last attack time to now | |||
| # lastAttackTime = OS.get_ticks_msec() | |||
| # | |||
| # # play the animation | |||
| # anim.stop() | |||
| # anim.play("Punch") | |||
| # | |||
| # # is the ray cast colliding with an enemy? | |||
| # if attackCast.is_colliding(): | |||
| # if attackCast.get_collider().has_method("take_damage"): | |||
| # attackCast.get_collider().take_damage(damage) | |||
| # if attackCast.get_collider().has_signal("on_interact"): | |||
| # attackCast.get_collider().emit_signal("on_interact") | |||
| # called when we press the interact button | |||
| func try_interact(): | |||
| # is the ray cast colliding with an enemy? | |||
| if interactCast.is_colliding(): | |||
| # play the animation | |||
| anim.stop() | |||
| anim.play("Idle") | |||
| if interactCast.get_collider().has_signal("on_interact"): | |||
| interactCast.get_collider().emit_signal("on_interact") | |||
| @@ -0,0 +1,8 @@ | |||
| extends Node | |||
| var player_input_enabled := true setget player_input_enabled_set | |||
| signal player_input_change | |||
| func player_input_enabled_set(value): | |||
| player_input_enabled = value | |||
| emit_signal("player_input_change", value) | |||
| @@ -0,0 +1,8 @@ | |||
| extends Node | |||
| func _enter_tree(): | |||
| Controller.player_input_enabled = true | |||
| func _exit_tree(): | |||
| Controller.player_input_enabled = false | |||
| Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) | |||
| @@ -0,0 +1,27 @@ | |||
| extends Node | |||
| export var scenes : Dictionary | |||
| signal end | |||
| func _ready(): | |||
| $YarnRunnerNode.yarnRunner.add_command("Scene", funcref(self, "load_scene")) | |||
| $YarnRunnerNode.yarnRunner.add_command("WaitSignal", funcref(self, "wait_signal")) | |||
| yield($YarnRunnerNode.start_script(), "completed") | |||
| func load_scene(args): | |||
| yield(get_tree(),"idle_frame") | |||
| if args.size() > 0: | |||
| var scene_key = args[0] | |||
| if scenes.has(scene_key): | |||
| for child in $SceneContainer.get_children(): | |||
| child.queue_free() | |||
| var scene = scenes[scene_key].instance() | |||
| $SceneContainer.add_child(scene) | |||
| func wait_signal(args): | |||
| yield(self, "end") | |||
| func _input(event): | |||
| if event.is_action_pressed("ui_cancel"): | |||
| emit_signal("end") | |||
| @@ -1,129 +0,0 @@ | |||
| extends KinematicBody | |||
| # stats | |||
| var curHp : int = 10 | |||
| var maxHp : int = 10 | |||
| var damage : int = 1 | |||
| var gold : int = 0 | |||
| var attackRate : float = 0.3 | |||
| var lastAttackTime : int = 0 | |||
| # physics | |||
| var walkSpeed : float = 5.0 | |||
| var runSpeed : float = 10.0 | |||
| var jumpForce : float = 10.0 | |||
| var gravity : float = 15.0 | |||
| var vel := Vector3() | |||
| # components | |||
| onready var camera = get_node("CameraOrbit") | |||
| onready var attackCast = get_node("AttackRayCast") | |||
| onready var anim = get_node("Casual2_Female/AnimationPlayer") | |||
| export var ui_path : NodePath | |||
| onready var ui = get_node(ui_path) | |||
| # called when the node is initialized | |||
| func _ready (): | |||
| # initialize the UI | |||
| ui.update_health_bar(curHp, maxHp) | |||
| ui.update_gold_text(gold) | |||
| func _process(delta): | |||
| # attack input | |||
| if is_on_floor() and Input.is_action_just_pressed("attack"): | |||
| try_attack() | |||
| # called every physics step (60 times a second) | |||
| func _physics_process (delta): | |||
| vel.x = 0 | |||
| vel.z = 0 | |||
| var input := Vector3() | |||
| # movement inputs | |||
| if Input.is_action_pressed("move_forward"): | |||
| input.z += 1 | |||
| if Input.is_action_pressed("move_backward"): | |||
| input.z -= 1 | |||
| if Input.is_action_pressed("move_left"): | |||
| input.x += 1 | |||
| if Input.is_action_pressed("move_right"): | |||
| input.x -= 1 | |||
| input = input.normalized() | |||
| # get the relative direction | |||
| var dir := (transform.basis.z * input.z + transform.basis.x * input.x) | |||
| # apply the direction to our velocity | |||
| if Input.is_action_pressed("run"): | |||
| vel.x = dir.x * runSpeed | |||
| vel.z = dir.z * runSpeed | |||
| else: | |||
| vel.x = dir.x * walkSpeed | |||
| vel.z = dir.z * walkSpeed | |||
| # gravity | |||
| vel.y -= gravity * delta | |||
| # jump input | |||
| if Input.is_action_pressed("jump") and is_on_floor(): | |||
| vel.y = jumpForce | |||
| if is_on_floor(): | |||
| if anim.current_animation != "Punch": | |||
| if input.x != 0 || input.z != 0: | |||
| if Input.is_action_pressed("run"): | |||
| anim.play("Run") | |||
| else: | |||
| anim.play("Walk") | |||
| else: | |||
| anim.play("Idle") | |||
| else: | |||
| anim.play("RecieveHit") | |||
| # move along the current velocity | |||
| vel = move_and_slide(vel, Vector3.UP, true, 4, deg2rad(89)) | |||
| # called when we collect a coin | |||
| func give_gold (amount): | |||
| gold += amount | |||
| # update the UI | |||
| ui.update_gold_text(gold) | |||
| # called when an enemy deals damage to us | |||
| func take_damage (damageToTake): | |||
| curHp -= damageToTake | |||
| # update the UI | |||
| ui.update_health_bar(curHp, maxHp) | |||
| # if our health is 0, die | |||
| if curHp <= 0: | |||
| die() | |||
| # called when our health reaches 0 | |||
| func die (): | |||
| # reload the scene | |||
| get_tree().reload_current_scene() | |||
| # called when we press the attack button | |||
| func try_attack(): | |||
| # if we're not ready to attack, return | |||
| if OS.get_ticks_msec() - lastAttackTime < attackRate * 1000: | |||
| return | |||
| # set the last attack time to now | |||
| lastAttackTime = OS.get_ticks_msec() | |||
| # play the animation | |||
| anim.stop() | |||
| anim.play("Punch") | |||
| # is the ray cast colliding with an enemy? | |||
| if attackCast.is_colliding(): | |||
| if attackCast.get_collider().has_method("take_damage"): | |||
| attackCast.get_collider().take_damage(damage) | |||
| @@ -3,13 +3,15 @@ class_name ChoicesBox | |||
| signal choice_made | |||
| export var button_template : PackedScene | |||
| func on_choice_made(marker): | |||
| emit_signal("choice_made", marker) | |||
| func on_choices(choices_list): | |||
| show() | |||
| for choice in choices_list: | |||
| var choiceButton := Button.new() | |||
| var choiceButton = button_template.instance() | |||
| choiceButton.text = choice["text"] | |||
| choiceButton.connect("pressed", self, "on_choice_made", [choice]) | |||
| add_child(choiceButton) | |||
| @@ -0,0 +1,10 @@ | |||
| extends Control | |||
| export var text_path : NodePath | |||
| onready var text := get_node(text_path) | |||
| export var choices_path : NodePath | |||
| onready var choices := get_node(choices_path) | |||
| func _ready(): | |||
| hide() | |||
| @@ -0,0 +1,29 @@ | |||
| extends Label | |||
| class_name SpeechText | |||
| signal click_down | |||
| signal click_up | |||
| var wait_input := false | |||
| func _ready(): | |||
| text = "" | |||
| func _input(event): | |||
| if wait_input and event is InputEventMouseButton: | |||
| if event.is_pressed(): # Mouse button down. | |||
| emit_signal("click_down") | |||
| else: | |||
| emit_signal("click_up") | |||
| func on_new_line(line): | |||
| show() | |||
| text = line.text | |||
| wait_input = true | |||
| yield(self, "click_down") | |||
| yield(self, "click_up") | |||
| wait_input = false | |||
| func clear(): | |||
| text = '' | |||
| @@ -0,0 +1,40 @@ | |||
| title: Start | |||
| tags: | |||
| colorID: 0 | |||
| position: 571,308 | |||
| --- | |||
| Starting | |||
| [[TestLVL]] | |||
| === | |||
| title: TestLVL | |||
| tags: | |||
| colorID: 0 | |||
| position: 571,668 | |||
| --- | |||
| <<Scene TestLVL>> | |||
| Scene loaded | |||
| [[TestLVLLoop]] | |||
| === | |||
| title: GameOver | |||
| tags: | |||
| colorID: 0 | |||
| position: 1096,808 | |||
| --- | |||
| <<Scene TestGameOver>> | |||
| Game Over | |||
| <<WaitSignal>> | |||
| Restarting | |||
| [[TestLVL]] | |||
| === | |||
| title: TestLVLLoop | |||
| tags: | |||
| colorID: 0 | |||
| position: 579,916 | |||
| --- | |||
| <<WaitSignal>> | |||
| <<if False>> | |||
| [[TestLVLLoop]] | |||
| <<else>> | |||
| [[GameOver]] | |||
| <<endif>> | |||
| === | |||
| @@ -0,0 +1,13 @@ | |||
| [remap] | |||
| importer="yarn.script" | |||
| type="Resource" | |||
| path="res://.import/main_debug.yarn-25c0e0fa3f4971fbbd75a2edb09403f4.res" | |||
| [deps] | |||
| source_file="res://jrpg/yarn_scripts/main_debug.yarn" | |||
| dest_files=[ "res://.import/main_debug.yarn-25c0e0fa3f4971fbbd75a2edb09403f4.res" ] | |||
| [params] | |||
| @@ -0,0 +1,26 @@ | |||
| title: Start | |||
| tags: | |||
| position: 701,320 | |||
| --- | |||
| Bonjour je suis un npc de debug ! | |||
| [[Bonjour|bonjour]] | |||
| [[Euh... Nique ta mère!|ntm]] | |||
| === | |||
| title: bonjour | |||
| tags: | |||
| position: 1032.2125854492188,730.3896484375 | |||
| --- | |||
| Est-ce que tu aimes la France ? | |||
| Est-ce que tu es prêt à donner ta vie pour la France ?? | |||
| A MOURIIIR POUR TA PATRIE ?? | |||
| === | |||
| title: ntm | |||
| tags: | |||
| position: 693.5343566489377,684.1047771502635 | |||
| --- | |||
| Vous n'avez pas honte ?? | |||
| === | |||
| @@ -0,0 +1,13 @@ | |||
| [remap] | |||
| importer="yarn.script" | |||
| type="Resource" | |||
| path="res://.import/npc_debug.yarn-0be9617748c4c825e4ae2abea83bc72f.res" | |||
| [deps] | |||
| source_file="res://jrpg/yarn_scripts/npc_debug.yarn" | |||
| dest_files=[ "res://.import/npc_debug.yarn-0be9617748c4c825e4ae2abea83bc72f.res" ] | |||
| [params] | |||
| @@ -1,34 +0,0 @@ | |||
| title: Start | |||
| tags: | |||
| position: 701,320 | |||
| --- | |||
| Empty Text | |||
| Haha | |||
| [[lul]] | |||
| je devrais pas apparaître | |||
| === | |||
| title: lul | |||
| tags: | |||
| position: 1032.2125854492188,730.3896484375 | |||
| --- | |||
| Huhuhu | |||
| <<if 1 > 2 >> | |||
| OK !! | |||
| [[zboub]] | |||
| <<else>> | |||
| Pas ok. | |||
| <<endif>> | |||
| [[zboub|zboub]] | |||
| [[start|Start]] | |||
| Moi non plus | |||
| === | |||
| title: zboub | |||
| tags: | |||
| position: 693.5343566489377,684.1047771502635 | |||
| --- | |||
| Prout poruoruoruo | |||
| === | |||
| @@ -1,14 +0,0 @@ | |||
| [remap] | |||
| importer="yarn.script" | |||
| type="Resource" | |||
| path="res://.import/test.yarn-642d0590cee80e9b0bd554c3bdc33727.res" | |||
| [deps] | |||
| source_file="res://main/dialogues/test.yarn" | |||
| dest_files=[ "res://.import/test.yarn-642d0590cee80e9b0bd554c3bdc33727.res" ] | |||
| [params] | |||
| use_red_anyway=false | |||
| @@ -1,13 +0,0 @@ | |||
| [gd_scene load_steps=2 format=2] | |||
| [ext_resource path="res://main/scripts/ChoicesBox.gd" type="Script" id=1] | |||
| [node name="ChoicesBox" type="VBoxContainer"] | |||
| anchor_left = 0.3 | |||
| anchor_top = 0.1 | |||
| anchor_right = 0.7 | |||
| anchor_bottom = 0.45 | |||
| script = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| @@ -1,27 +0,0 @@ | |||
| [gd_scene load_steps=3 format=2] | |||
| [ext_resource path="res://main/scripts/dialogue_test.gd" type="Script" id=1] | |||
| [ext_resource path="res://yarn/scenes/YarnSpinner.tscn" type="PackedScene" id=2] | |||
| [node name="DialogueTest" type="Control"] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| script = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| [node name="YarnSpinner" parent="." instance=ExtResource( 2 )] | |||
| yarn_file = "main/dialogues/test.yarn" | |||
| [node name="StartButton" type="Button" parent="."] | |||
| anchor_left = 0.45 | |||
| anchor_top = 0.45 | |||
| anchor_right = 0.55 | |||
| anchor_bottom = 0.55 | |||
| margin_left = -6.0 | |||
| margin_top = -10.0 | |||
| margin_right = 6.0 | |||
| margin_bottom = 10.0 | |||
| text = "Start !" | |||
| [connection signal="pressed" from="StartButton" to="." method="_on_start_pressed"] | |||
| @@ -1,34 +0,0 @@ | |||
| [gd_scene load_steps=3 format=2] | |||
| [sub_resource type="BoxShape" id=2] | |||
| extents = Vector3( 4.51412, 0.146837, 4.39716 ) | |||
| [sub_resource type="SphereShape" id=1] | |||
| [node name="Spatial" type="Spatial"] | |||
| [node name="DirectionalLight" type="DirectionalLight" parent="."] | |||
| [node name="StaticBody" type="StaticBody" parent="."] | |||
| transform = Transform( 0.997775, 0.0666744, 0, -0.0666744, 0.997775, 0, 0, 0, 1, 0, 0, 0 ) | |||
| [node name="CSGBox" type="CSGBox" parent="StaticBody"] | |||
| transform = Transform( 4.58515, 0, 0, 0, 1, 0, 0, 0, 4.58515, 0, 0, 0 ) | |||
| height = 0.3043 | |||
| [node name="CollisionShape" type="CollisionShape" parent="StaticBody"] | |||
| shape = SubResource( 2 ) | |||
| [node name="VehicleBody" type="RigidBody" parent="."] | |||
| [node name="CSGSphere" type="CSGSphere" parent="VehicleBody"] | |||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.01212, 0 ) | |||
| radial_segments = 36 | |||
| rings = 16 | |||
| [node name="CollisionShape" type="CollisionShape" parent="VehicleBody"] | |||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.01212, 0 ) | |||
| shape = SubResource( 1 ) | |||
| [node name="Camera" type="Camera" parent="VehicleBody"] | |||
| transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.59567, 6.78563 ) | |||
| @@ -1,27 +0,0 @@ | |||
| [gd_scene load_steps=6 format=2] | |||
| [ext_resource path="res://main/scripts/test_viteuf.gd" type="Script" id=1] | |||
| [ext_resource path="res://main/dialogues/test.yarn" type="Resource" id=2] | |||
| [ext_resource path="res://addons/yarn_spinner/yarn_runner.gd" type="Script" id=3] | |||
| [ext_resource path="res://main/scenes/LogPanel.tscn" type="PackedScene" id=4] | |||
| [ext_resource path="res://main/scenes/ChoicesBox.tscn" type="PackedScene" id=5] | |||
| [node name="Node" type="Control"] | |||
| anchor_right = 1.0 | |||
| anchor_bottom = 1.0 | |||
| script = ExtResource( 1 ) | |||
| __meta__ = { | |||
| "_edit_use_anchors_": false | |||
| } | |||
| [node name="YarnRunner" type="Node" parent="."] | |||
| script = ExtResource( 3 ) | |||
| yarnScript = ExtResource( 2 ) | |||
| [node name="LogPanel" parent="." instance=ExtResource( 4 )] | |||
| anchor_bottom = 0.6 | |||
| [node name="ChoicesBox" parent="." instance=ExtResource( 5 )] | |||
| anchor_top = 0.6 | |||
| anchor_bottom = 1.0 | |||
| alignment = 1 | |||
| @@ -1,13 +0,0 @@ | |||
| extends Control | |||
| class_name LogPanel | |||
| func _ready(): | |||
| $RichTextLabel.text = "" | |||
| func on_new_line(text): | |||
| show() | |||
| $RichTextLabel.text += text + '\n' | |||
| yield($TextButton, "pressed") | |||
| func clear(): | |||
| $RichTextLabel.text = '' | |||
| @@ -1,9 +0,0 @@ | |||
| extends Control | |||
| func start(): | |||
| $StartButton.hide() | |||
| yield($YarnSpinner.spin_yarn($YarnSpinner.yarn_file), "completed") | |||
| $StartButton.show() | |||
| func _on_start_pressed(): | |||
| start() | |||
| @@ -1,28 +0,0 @@ | |||
| extends Control | |||
| func _ready(): | |||
| # $ChoicesBox.hide() | |||
| # $LogPanel.hide() | |||
| on_dialogue_start() | |||
| $YarnRunner.say_func = funcref(self, "on_new_line") | |||
| $YarnRunner.choices_func = funcref(self, "on_choices") | |||
| yield($YarnRunner.run_all(), "completed") | |||
| on_dialogue_end() | |||
| func on_dialogue_start(): | |||
| $LogPanel.show() | |||
| $ChoicesBox.show() | |||
| $LogPanel.clear() | |||
| $ChoicesBox.clear() | |||
| func on_new_line(line): | |||
| yield($LogPanel.on_new_line(line["text"]), "completed") | |||
| func on_choices(choices_list): | |||
| print(choices_list) | |||
| return yield($ChoicesBox.on_choices(choices_list), "completed") | |||
| func on_dialogue_end(): | |||
| pass | |||
| # $ChoicesBox.hide() | |||
| # $LogPanel.hide() | |||
| @@ -9,25 +9,49 @@ | |||
| config_version=4 | |||
| _global_script_classes=[ { | |||
| "base": "Node", | |||
| "class": "BasisInteraction", | |||
| "language": "GDScript", | |||
| "path": "res://jrpg/scripts/entities/components/interactions/basis_interaction.gd" | |||
| }, { | |||
| "base": "VBoxContainer", | |||
| "class": "ChoicesBox", | |||
| "language": "GDScript", | |||
| "path": "res://main/scripts/ChoicesBox.gd" | |||
| "path": "res://jrpg/scripts/ui/choices_box.gd" | |||
| }, { | |||
| "base": "Control", | |||
| "class": "LogPanel", | |||
| "base": "Label", | |||
| "class": "SpeechText", | |||
| "language": "GDScript", | |||
| "path": "res://main/scripts/LogPanel.gd" | |||
| "path": "res://jrpg/scripts/ui/speech_text.gd" | |||
| }, { | |||
| "base": "Node", | |||
| "class": "YarnImporter", | |||
| "language": "GDScript", | |||
| "path": "res://yarn/scripts/yarn-importer.gd" | |||
| }, { | |||
| "base": "Object", | |||
| "class": "YarnRunner", | |||
| "language": "GDScript", | |||
| "path": "res://addons/yarn_spinner/yarn_runner.gd" | |||
| }, { | |||
| "base": "Node", | |||
| "class": "YarnRunnerNode", | |||
| "language": "GDScript", | |||
| "path": "res://addons/yarn_spinner/yarn_runner_node.gd" | |||
| }, { | |||
| "base": "Resource", | |||
| "class": "YarnScript", | |||
| "language": "GDScript", | |||
| "path": "res://addons/yarn_spinner/yarn_script.gd" | |||
| } ] | |||
| _global_script_class_icons={ | |||
| "BasisInteraction": "", | |||
| "ChoicesBox": "", | |||
| "LogPanel": "", | |||
| "YarnImporter": "" | |||
| "SpeechText": "", | |||
| "YarnImporter": "", | |||
| "YarnRunner": "", | |||
| "YarnRunnerNode": "", | |||
| "YarnScript": "" | |||
| } | |||
| [application] | |||
| @@ -35,6 +59,10 @@ _global_script_class_icons={ | |||
| config/name="Chepa" | |||
| config/icon="res://icon.png" | |||
| [autoload] | |||
| Controller="*res://jrpg/scripts/misc/controller.gd" | |||
| [editor_plugins] | |||
| enabled=PoolStringArray( "yarn_spinner" ) | |||
| @@ -72,7 +100,7 @@ jump={ | |||
| "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null) | |||
| ] | |||
| } | |||
| attack={ | |||
| interact={ | |||
| "deadzone": 0.5, | |||
| "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) | |||
| ] | |||
| @@ -1,9 +1,11 @@ | |||
| [gd_scene load_steps=4 format=2] | |||
| [ext_resource path="res://main/scenes/ChoicesBox.tscn" type="PackedScene" id=1] | |||
| [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 | |||