diff --git a/scenes/EnchantedSphere.tscn b/scenes/EnchantedSphere.tscn new file mode 100644 index 0000000..082f970 --- /dev/null +++ b/scenes/EnchantedSphere.tscn @@ -0,0 +1,29 @@ +[gd_scene format=3 uid="uid://cayybawvw26cm"] + +[ext_resource type="Script" path="res://scripts/EnchantedSphere.gd" id="1_sphere"] + +[sub_resource type="SphereMesh" id="SphereMesh_1"] +radius = 0.28 +height = 0.56 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"] +albedo_color = Color(0.8, 0.3, 1.0, 1) +emission_enabled = true +emission = Color(0.6, 0.1, 1.0, 1) +emission_energy_multiplier = 3.0 + +[node name="EnchantedSphere" type="Node3D"] +script = ExtResource("1_sphere") + +[node name="SphereMesh" type="MeshInstance3D" parent="."] +mesh = SubResource("SphereMesh_1") +material_override = SubResource("StandardMaterial3D_1") + +[node name="Tooltip" type="Label3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1, 0) +billboard = 1 +double_sided = true +text = "[E] Enchanted Sphere ++1 Tier" +font_size = 32 +outline_size = 6 diff --git a/scenes/Essence.tscn b/scenes/Essence.tscn new file mode 100644 index 0000000..8f851d4 --- /dev/null +++ b/scenes/Essence.tscn @@ -0,0 +1,28 @@ +[gd_scene format=3 uid="uid://bjk2mastaopd8"] + +[ext_resource type="Script" path="res://scripts/Essence.gd" id="1_essence"] + +[sub_resource type="SphereMesh" id="SphereMesh_1"] +radius = 0.18 +height = 0.36 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"] +albedo_color = Color(0.7, 0.2, 1.0, 1) +emission_enabled = true +emission = Color(0.5, 0.0, 1.0, 1) +emission_energy_multiplier = 2.0 + +[sub_resource type="SphereShape3D" id="SphereShape3D_1"] +radius = 0.18 + +[node name="Essence" type="CharacterBody3D"] +script = ExtResource("1_essence") + +[node name="EssenceMesh" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.22, 0) +mesh = SubResource("SphereMesh_1") +material_override = SubResource("StandardMaterial3D_1") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.22, 0) +shape = SubResource("SphereShape3D_1") diff --git a/scenes/Level.tscn b/scenes/Level.tscn index 39a8ff3..3ecccb6 100644 --- a/scenes/Level.tscn +++ b/scenes/Level.tscn @@ -78,6 +78,24 @@ size = Vector3(0.6, 1, 0.6) [sub_resource type="BoxShape3D" id="BoxShape3D_forge"] size = Vector3(2, 1.8, 2) +[sub_resource type="BoxMesh" id="BoxMesh_etable"] +size = Vector3(1.4, 0.9, 1.4) + +[sub_resource type="BoxMesh" id="BoxMesh_ebook"] +size = Vector3(0.7, 0.12, 0.5) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_etable"] +albedo_color = Color(0.12, 0.08, 0.22, 1) +roughness = 0.6 +metallic = 0.2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ebook"] +albedo_color = Color(0.55, 0.08, 0.08, 1) +roughness = 0.9 + +[sub_resource type="BoxShape3D" id="BoxShape3D_etable"] +size = Vector3(1.4, 0.9, 1.4) + [node name="Level" type="Node3D" unique_id=696519] script = ExtResource("1_ppgk2") show_grid = false @@ -242,3 +260,19 @@ mesh = SubResource("BoxMesh_chimney") [node name="CollisionShape3D" type="CollisionShape3D" parent="Forge" unique_id=726531191] shape = SubResource("BoxShape3D_forge") + +[node name="EnchantingTable" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8, 0.45, -8) +metadata/is_enchanting_table = true + +[node name="TableMesh" type="MeshInstance3D" parent="EnchantingTable"] +mesh = SubResource("BoxMesh_etable") +material_override = SubResource("StandardMaterial3D_etable") + +[node name="BookMesh" type="MeshInstance3D" parent="EnchantingTable"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.51, 0) +mesh = SubResource("BoxMesh_ebook") +material_override = SubResource("StandardMaterial3D_ebook") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="EnchantingTable"] +shape = SubResource("BoxShape3D_etable") diff --git a/scripts/EnchantedSphere.gd b/scripts/EnchantedSphere.gd new file mode 100644 index 0000000..6211126 --- /dev/null +++ b/scripts/EnchantedSphere.gd @@ -0,0 +1,25 @@ +extends Node3D + +@onready var tooltip: Label3D = $Tooltip +@onready var mesh_node: MeshInstance3D = $SphereMesh + +func _ready() -> void: + add_to_group("interactable") + tooltip.visible = false + var tw := create_tween().set_loops() + tw.tween_property(self, "position:y", 0.7, 0.9) + tw.tween_property(self, "position:y", 0.3, 0.9) + +func _process(delta: float) -> void: + rotation.y += delta * 1.8 + mesh_node.rotation.x += delta * 0.9 + var players := get_tree().get_nodes_in_group("player") + if players.is_empty(): + tooltip.visible = false + return + var p := players[0] as Node3D + tooltip.visible = p != null and global_position.distance_to(p.global_position) < 2.5 + +func interact(player: Node) -> void: + player.call("apply_upgrade_enchant") + queue_free() diff --git a/scripts/EnchantedSphere.gd.uid b/scripts/EnchantedSphere.gd.uid new file mode 100644 index 0000000..c516b90 --- /dev/null +++ b/scripts/EnchantedSphere.gd.uid @@ -0,0 +1 @@ +uid://c4d11cs4fcqib diff --git a/scripts/Enemy.gd b/scripts/Enemy.gd index 067324a..bbf575b 100644 --- a/scripts/Enemy.gd +++ b/scripts/Enemy.gd @@ -1,9 +1,10 @@ class_name Enemy extends CharacterBody3D -const PICKUP_SCENE := preload("res://scenes/Pickup.tscn") -const LEATHER_SCENE := preload("res://scenes/Leather.tscn") -const IRON_SCENE := preload("res://scenes/Iron.tscn") +const PICKUP_SCENE := preload("res://scenes/Pickup.tscn") +const LEATHER_SCENE := preload("res://scenes/Leather.tscn") +const IRON_SCENE := preload("res://scenes/Iron.tscn") +const ESSENCE_SCENE := preload("res://scenes/Essence.tscn") signal died(points: int) signal merged(upgrade: bool) @@ -12,6 +13,7 @@ enum State { CHASING, FLYING, STUNNED, DEAD, MERGING } static var first_leather_spawned: bool = false static var first_iron_spawned: bool = false +static var first_essence_spawned: bool = false var kickable_type: String = "" var tier: int = 1 @@ -277,6 +279,14 @@ func _try_drop_pickup() -> void: get_parent().add_child(iron) iron.global_position = global_position + if enemy_level == 3: + var drop_essence := not first_essence_spawned or randf() < 0.20 + if drop_essence: + first_essence_spawned = true + var essence := ESSENCE_SCENE.instantiate() as Node3D + get_parent().add_child(essence) + essence.global_position = global_position + var roll := randf() var p_type := "" var p_heal := 0 diff --git a/scripts/Essence.gd b/scripts/Essence.gd new file mode 100644 index 0000000..993b19f --- /dev/null +++ b/scripts/Essence.gd @@ -0,0 +1,105 @@ +extends CharacterBody3D + +const ENCHANTED_SPHERE_SCENE := preload("res://scenes/EnchantedSphere.tscn") + +signal destroyed + +enum State { IDLE, FLYING } + +const AIR_FRICTION := 0.88 +const MIN_SPEED := 0.3 +const WALL_BOUNCE := 0.6 +const WALL_SELF_DMG := 0.0 + +var kickable_type: String = "essence" +var tier: int = 3 +var state: State = State.IDLE +var fly_vel: Vector3 = Vector3.ZERO +var health: float = 999.0 +var dead: bool = false +var damage_modifier: float = 0.0 + +@onready var mesh_node: MeshInstance3D = $EssenceMesh +var essence_mat: StandardMaterial3D + +func _ready() -> void: + add_to_group("kickable") + essence_mat = mesh_node.material_override.duplicate() as StandardMaterial3D + mesh_node.material_override = essence_mat + var tw := create_tween().set_loops() + tw.tween_property(self, "position:y", 0.35, 0.6) + tw.tween_property(self, "position:y", 0.15, 0.6) + +func apply_collision_damage(_dmg: float) -> void: + pass + +func receive_kick(direction: Vector3, force: float) -> void: + fly_vel = direction * force + fly_vel.y = 0.0 + state = State.FLYING + +func _physics_process(delta: float) -> void: + if state == State.IDLE: + mesh_node.rotation.y += delta * 1.5 + return + _fly(delta) + +func _fly(delta: float) -> void: + var speed_now := Vector2(fly_vel.x, fly_vel.z).length() + velocity = fly_vel + velocity.y = 0.0 + move_and_slide() + + var handled := false + for i in get_slide_collision_count(): + var col := get_slide_collision(i) + var col3d := col.get_collider() as Node3D + if col3d == null: + continue + if col3d.has_meta("is_enchanting_table"): + _hit_table(col3d) + return + if col3d.has_meta("is_wall"): + var normal := col.get_normal() + normal.y = 0.0 + if normal.length() > 0.01: + fly_vel = fly_vel.bounce(normal.normalized()) * WALL_BOUNCE + else: + fly_vel = Vector3.ZERO + handled = true + break + elif col3d.is_in_group("enemies") or col3d.is_in_group("kickable"): + if col3d == self: + continue + KickSystem.resolve(self, col3d, fly_vel) + fly_vel *= 0.4 + handled = true + break + + if not handled: + fly_vel = velocity + fly_vel.y = 0.0 + + fly_vel *= pow(AIR_FRICTION, delta * 60.0) + + if Vector2(fly_vel.x, fly_vel.z).length() < MIN_SPEED: + fly_vel = Vector3.ZERO + velocity = Vector3.ZERO + state = State.IDLE + + mesh_node.rotation.y += delta * speed_now * 0.4 + +func _hit_table(table: Node3D) -> void: + if dead: + return + dead = true + state = State.IDLE + set_physics_process(false) + var parent := get_parent() + var spawn_pos := table.global_position + Vector3(0, 0.5, 0) + queue_free() + if parent == null: + return + var sphere := ENCHANTED_SPHERE_SCENE.instantiate() as Node3D + parent.add_child(sphere) + sphere.global_position = spawn_pos diff --git a/scripts/Essence.gd.uid b/scripts/Essence.gd.uid new file mode 100644 index 0000000..0c386f2 --- /dev/null +++ b/scripts/Essence.gd.uid @@ -0,0 +1 @@ +uid://bk2vad35jr81c diff --git a/scripts/Main.gd b/scripts/Main.gd index acb912c..c9edcac 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -172,6 +172,7 @@ func _start_game() -> void: kills_for_next = 10 Enemy.first_leather_spawned = false Enemy.first_iron_spawned = false + Enemy.first_essence_spawned = false _update_labels() spawn_timer.wait_time = 1.4 spawn_timer.connect("timeout", _on_spawn_timer) diff --git a/scripts/Player.gd b/scripts/Player.gd index e82133d..272d5bd 100644 --- a/scripts/Player.gd +++ b/scripts/Player.gd @@ -241,3 +241,9 @@ func apply_upgrade_armor() -> void: var tw := create_tween() tw.tween_property(player_mat, "albedo_color", Color(0.7, 0.8, 1.0), 0.1) tw.tween_property(player_mat, "albedo_color", BASE_COLOR, 0.5) + +func apply_upgrade_enchant() -> void: + tier += 1 + var tw := create_tween() + tw.tween_property(player_mat, "albedo_color", Color(0.8, 0.2, 1.0), 0.1) + tw.tween_property(player_mat, "albedo_color", BASE_COLOR, 0.6)