Dev pour la beta 1.4

* Changements de la texture des cristaux de Talion dans tous les assets 3D pour correspondre aux assets 2D
* Ajout d'un évenement en fin de région, une résurgence de Talion qui décontamine et fait looter les plantes mature aux alentours
* Ajout d'un path finding sur le mouvement du robot
* Modification du flow des actions à la souris : ajout d'un nouveau son, d'un icône à l'emplacement de l'action
* Modification du nombre et de l'ordre de mutation débloquées
* Augmentation de la valeur maximale de zoom
* Modification des scores à atteindre dans les premières régions
* Modification de l'interface du vaisseau, laissant apparaitre une roadmap plus claire, et laissant inspecter l'inventaire actuel
* Modification de l'icône d'action dans les scènes 3D
* Augmentation de la zone d'écart entre les plantes, et augmentation du taux de zone fertile en conséquence
* La station de recharge devient inutilisable après la fin de la région
* Ajout d'une transparence lors de la sélection d'objets derrières d'autres objets
* Les plantes juvéniles donneront toujours une graine si coupées
* Ajout d'un bouclage sur les couleurs des mutations
* Fix des hitbox des plantes pour l'inspection à la souris
* Fix de plusieurs bugs sur la manipulation de l'inventaire
* Ajout de nombreux screenshots d'utilisation des outils lors du tutoriel
* Amélioration mineure de la traduction/wording
This commit is contained in:
2026-05-17 02:29:55 +02:00
parent 73b0bf2d33
commit 8efe8bce36
126 changed files with 1955 additions and 463 deletions
+38 -15
View File
@@ -1,29 +1,52 @@
extends Camera2D
class_name Camera
class_name RegionCamera
const MOVE_LERP_WEIGHT = 0.9
const ZOOM_LERP_WEIGHT = 0.05
const SHAKE_INTENSITY = 10.0
const SHAKE_SPEED = 500.0
const ZOOM_STEP = 0.1
@export var following : Node2D
@export var should_follow : bool = true
@onready var settings = GameInfo.settings_data
@export var shake_active_time = -1
var shake_noise := FastNoiseLite.new()
func _input(_e):
if Input.is_action_just_pressed("zoom_in"):
settings.zoom = settings.zoom + ZOOM_STEP
GameInfo.save_settings()
if Input.is_action_just_pressed("zoom_out"):
settings.zoom = settings.zoom - ZOOM_STEP
GameInfo.save_settings()
if Input.is_action_just_pressed("zoom_in"):
settings.zoom = settings.zoom + ZOOM_STEP
GameInfo.save_settings()
if Input.is_action_just_pressed("zoom_out"):
settings.zoom = settings.zoom - ZOOM_STEP
GameInfo.save_settings()
func _ready():
if following:
zoom = Vector2.ONE * settings.zoom
global_position = following.global_position
if following and should_follow:
zoom = Vector2.ONE * settings.zoom
global_position = following.global_position
func _process(_delta):
if following:
global_position = following.global_position.lerp(global_position, MOVE_LERP_WEIGHT)
zoom = zoom.lerp(Vector2.ONE * settings.zoom, MOVE_LERP_WEIGHT)
func _process(delta):
if following and should_follow:
global_position = following.global_position.lerp(global_position, MOVE_LERP_WEIGHT)
zoom = zoom.lerp(Vector2.ONE * settings.zoom, MOVE_LERP_WEIGHT)
if shake_active_time > 0.:
print(shake_noise.get_noise_2d(shake_active_time * SHAKE_SPEED, 0) * SHAKE_INTENSITY)
shake_active_time -= delta
offset = Vector2(
shake_noise.get_noise_2d(shake_active_time * SHAKE_SPEED, 0) * SHAKE_INTENSITY,
shake_noise.get_noise_2d(0, shake_active_time * SHAKE_SPEED) * SHAKE_INTENSITY,
)
else :
offset = lerp(offset, Vector2.ZERO, 10.5 * delta)
func shake(time := 5):
shake_noise.seed = randi()
shake_active_time = time
@@ -39,10 +39,10 @@ materials/extract_format=0
materials/extract_path=""
_subresources={
"materials": {
"Default3D": {
"Cristal": {
"use_external/enabled": true,
"use_external/fallback_path": "res://common/assets/materials/default_3d.tres",
"use_external/path": "uid://dvvi1k5c5iowc"
"use_external/fallback_path": "res://common/assets/materials/cristal.tres",
"use_external/path": "uid://di0m3uqgi3l08"
}
}
}
@@ -4,12 +4,12 @@ importer="scene"
importer_version=1
type="PackedScene"
uid="uid://c7p114rvk26xw"
path="res://.godot/imported/cristal_crack_3.blend-513c4ee47a074edd5c96e86c23a0716a.scn"
path="res://.godot/imported/cristal_crack.blend-127c21c2b9bb4a6237729dd3a817aaf1.scn"
[deps]
source_file="res://entities/interactable_3d/cristal/assets/cristal_crack_3.blend"
dest_files=["res://.godot/imported/cristal_crack_3.blend-513c4ee47a074edd5c96e86c23a0716a.scn"]
source_file="res://entities/interactable_3d/cristal/assets/cristal_crack.blend"
dest_files=["res://.godot/imported/cristal_crack.blend-127c21c2b9bb4a6237729dd3a817aaf1.scn"]
[params]
@@ -39,10 +39,10 @@ materials/extract_format=0
materials/extract_path=""
_subresources={
"materials": {
"Default3D": {
"Cristal": {
"use_external/enabled": true,
"use_external/fallback_path": "res://common/assets/materials/default_3d.tres",
"use_external/path": "uid://dvvi1k5c5iowc"
"use_external/fallback_path": "res://common/assets/materials/cristal.tres",
"use_external/path": "uid://di0m3uqgi3l08"
}
}
}
@@ -1,68 +0,0 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://d0sdfjneo8rjj"
path="res://.godot/imported/cristal_crack_1.blend-01f6238e5ee6ec34d1d8a421f878430c.scn"
[deps]
source_file="res://entities/interactable_3d/cristal/assets/cristal_crack_1.blend"
dest_files=["res://.godot/imported/cristal_crack_1.blend-01f6238e5ee6ec34d1d8a421f878430c.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={
"materials": {
"Default3D": {
"use_external/enabled": true,
"use_external/fallback_path": "res://common/assets/materials/default_3d.tres",
"use_external/path": "uid://dvvi1k5c5iowc"
}
}
}
blender/nodes/visible=0
blender/nodes/active_collection_only=false
blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/colors=false
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/export_geometry_nodes_instances=false
blender/meshes/gpu_instances=false
blender/meshes/tangents=true
blender/meshes/skins=2
blender/meshes/export_bones_deforming_mesh_only=false
blender/materials/unpack_enabled=true
blender/materials/export_materials=1
blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true
gltf/naming_version=2
@@ -1,68 +0,0 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://b8cqw348lx15s"
path="res://.godot/imported/cristal_crack_2.blend-e5cf949346bc85a9c664c66dde3ab25a.scn"
[deps]
source_file="res://entities/interactable_3d/cristal/assets/cristal_crack_2.blend"
dest_files=["res://.godot/imported/cristal_crack_2.blend-e5cf949346bc85a9c664c66dde3ab25a.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={
"materials": {
"Default3D": {
"use_external/enabled": true,
"use_external/fallback_path": "res://common/assets/materials/default_3d.tres",
"use_external/path": "uid://dvvi1k5c5iowc"
}
}
}
blender/nodes/visible=0
blender/nodes/active_collection_only=false
blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/colors=false
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/export_geometry_nodes_instances=false
blender/meshes/gpu_instances=false
blender/meshes/tangents=true
blender/meshes/skins=2
blender/meshes/export_bones_deforming_mesh_only=false
blender/materials/unpack_enabled=true
blender/materials/export_materials=1
blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true
gltf/naming_version=2
@@ -3,9 +3,8 @@
[ext_resource type="Script" uid="uid://dwn3g8c5sa0a2" path="res://entities/interactable_3d/cristal/scripts/cristal.gd" id="1_ci2hw"]
[ext_resource type="AudioStream" uid="uid://3c4nxjasebyk" path="res://common/audio_manager/assets/sfx/pickaxe/pickaxe_1_reverb.wav" id="2_3rrt0"]
[ext_resource type="PackedScene" uid="uid://mwk845fx5ye2" path="res://entities/interactable_3d/cristal/assets/cristal.blend" id="2_ci2hw"]
[ext_resource type="PackedScene" uid="uid://c7p114rvk26xw" path="res://entities/interactable_3d/cristal/assets/cristal_crack_3.blend" id="2_vejte"]
[ext_resource type="PackedScene" uid="uid://c7p114rvk26xw" path="res://entities/interactable_3d/cristal/assets/cristal_crack.blend" id="2_vejte"]
[ext_resource type="AudioStream" uid="uid://bs5ldhabymm5p" path="res://common/audio_manager/assets/sfx/pickaxe/pickaxe_2_reverb.wav" id="3_247i2"]
[ext_resource type="PackedScene" uid="uid://d0sdfjneo8rjj" path="res://entities/interactable_3d/cristal/assets/cristal_crack_1.blend" id="3_nvfy2"]
[ext_resource type="AudioStream" uid="uid://bu278eqn8krnb" path="res://common/audio_manager/assets/sfx/pickaxe/pickaxe_3_reverb.wav" id="4_k7wsc"]
[ext_resource type="PackedScene" uid="uid://brp1fpvasaims" path="res://entities/interactable_3d/cristal/mutation_announce.tscn" id="9_247i2"]
@@ -63,14 +62,10 @@ scale_amount_min = 0.5
color = Color(1, 0.6509804, 0.09019608, 1)
color_ramp = SubResource("Gradient_ci2hw")
[node name="CristalModel" parent="." unique_id=1362490576 instance=ExtResource("2_ci2hw")]
[node name="CristalModel" parent="." unique_id=886555966 instance=ExtResource("2_ci2hw")]
unique_name_in_owner = true
[node name="CristalModelCrack1" parent="." unique_id=2936580 instance=ExtResource("3_nvfy2")]
unique_name_in_owner = true
visible = false
[node name="CristalModelCrack2" parent="." unique_id=1202531828 instance=ExtResource("2_vejte")]
[node name="CristalModelCrack" parent="." unique_id=26298259 instance=ExtResource("2_vejte")]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0051152706, 0.006559938, -0.011411905)
visible = false
@@ -82,4 +77,4 @@ shape = SubResource("BoxShape3D_nvfy2")
[node name="MutationAnnounce" parent="." unique_id=1447182082 instance=ExtResource("9_247i2")]
unique_name_in_owner = true
[editable path="CristalModelCrack2"]
[editable path="CristalModelCrack"]
@@ -27,11 +27,10 @@ func click():
func update_model():
if is_node_ready():
%CristalModel.visible = break_level == 0
%CristalModelCrack1.visible = break_level == 1
%CristalModelCrack2.visible = break_level > 1
%CristalModelCrack.visible = break_level > 0
if break_level > 1:
%CristalModelCrack2.find_children("AnimationPlayer")[0].play("Break")
%CristalModelCrack.find_children("AnimationPlayer")[0].play("Break")
func unlock_mutation():
var progression = GameInfo.game_data.progression_data
@@ -14,6 +14,7 @@ func can_interact(_p : Player) -> bool:
region != null
and region.data
and region.data.charges > 0
and region.data.state == RegionData.State.IN_PROGRESS
)
func interact(_p: Player) -> bool:
@@ -7,14 +7,18 @@
[ext_resource type="Texture2D" uid="uid://bhi3mwl23flwp" path="res://entities/interactables/truck/recharge/STW_Props_Batterie_Glass_V2.png" id="5_2okh4"]
[ext_resource type="Texture2D" uid="uid://c01f6ja6btsep" path="res://entities/interactables/truck/recharge/STW_Props_Batterie_TERRE.png" id="6_2okh4"]
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_bjhct"]
radius = 38.45475
height = 76.9095
[sub_resource type="LabelSettings" id="LabelSettings_1vpbi"]
font = ExtResource("4_ot7vv")
font_size = 30
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_ot7vv"]
radius = 43.0
height = 116.0
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_bjhct"]
radius = 38.45475
height = 76.9095
[node name="TruckRecharge" type="Area2D" unique_id=1099196706]
script = ExtResource("1_ipgcv")
default_interact_text = "RECHARGE"
@@ -22,10 +26,6 @@ default_info_title = "RECHARGE_STATION"
default_info_desc = "RECHARGE_STATION_DESC_TEXT"
metadata/_custom_type_script = "uid://dyprcd68fjstf"
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=2014886648]
position = Vector2(9, -53)
shape = SubResource("CapsuleShape2D_bjhct")
[node name="RechargeStation" type="Sprite2D" parent="." unique_id=1801951226]
scale = Vector2(0.5, 0.5)
texture = ExtResource("2_ot7vv")
@@ -67,6 +67,10 @@ scale = Vector2(0.5, 0.5)
texture = ExtResource("6_2okh4")
offset = Vector2(0, -120)
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=2014886648]
position = Vector2(12, -54)
shape = SubResource("CapsuleShape2D_ot7vv")
[node name="StaticBody2D" type="StaticBody2D" parent="." unique_id=1324035615]
[node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D" unique_id=842130596]
Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dslagvhodlepi"
path="res://.godot/imported/asset_cristals.png-fbcde6581d88986094aa97c2145c31c2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://entities/interactables/win_cristal/assets/sprites/asset_cristals.png"
dest_files=["res://.godot/imported/asset_cristals.png-fbcde6581d88986094aa97c2145c31c2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
@@ -0,0 +1,31 @@
@tool
extends InspectableEntity
class_name WinCristal
@export_tool_button("Update", "Callable") var update_action = update
@export_tool_button("Spawn Anim", "Callable") var spawn_action = spawn_animation
@export var data : WinCristalData = WinCristalData.random() :
set(v):
data = v
update()
func _ready():
update()
func update():
if is_node_ready() and data:
for i in range(len(%Sprites.get_children())):
%Sprites.get_children()[i].visible = data.cristal_type == i
%Sprites.get_children()[i].flip_h = data.cristal_flip
func spawn_animation():
scale = Vector2.ZERO
%CristalPlayer.play()
get_tree().create_tween().tween_property(self, "scale", Vector2.ONE, 0.3).set_trans(Tween.TRANS_BOUNCE)
func get_card_up_padding() -> float:
return Pointer.CARD_UP_PADDING * 2
func save() -> EntityData:
data.position = global_position
return data
@@ -0,0 +1 @@
uid://cismap3cn5e36
@@ -0,0 +1,22 @@
extends EntityData
class_name WinCristalData
const WIN_CRISTAL_SCENE = preload("res://entities/interactables/win_cristal/win_cristal.tscn")
@export var cristal_type : int
@export var cristal_flip : bool
func load_entity() -> Entity:
var win_cristal := WIN_CRISTAL_SCENE.instantiate() as WinCristal
win_cristal.data = self
return win_cristal
static func random() -> WinCristalData:
var data = WinCristalData.new()
data.cristal_type = randi_range(0,3)
data.cristal_flip = randi() % 2 == 0
return data
@@ -0,0 +1 @@
uid://cos0ennmyfvc2
@@ -0,0 +1,82 @@
[gd_scene format=3 uid="uid://de5pt5vyu23fb"]
[ext_resource type="Script" uid="uid://cismap3cn5e36" path="res://entities/interactables/win_cristal/scripts/win_cristal.gd" id="1_yb2ta"]
[ext_resource type="Script" uid="uid://cos0ennmyfvc2" path="res://entities/interactables/win_cristal/scripts/win_cristal_data.gd" id="2_vkbio"]
[ext_resource type="Texture2D" uid="uid://dslagvhodlepi" path="res://entities/interactables/win_cristal/assets/sprites/asset_cristals.png" id="2_yb2ta"]
[ext_resource type="AudioStream" uid="uid://dnqq2sy3dxrb2" path="res://common/audio_manager/assets/sfx/cristal/freesound_community-wine-glass-clink-36036.mp3" id="3_vkbio"]
[sub_resource type="Resource" id="Resource_5lni1"]
script = ExtResource("2_vkbio")
cristal_type = 2
cristal_flip = true
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_vkbio"]
radius = 40.0
height = 116.0
[sub_resource type="AtlasTexture" id="AtlasTexture_5lni1"]
atlas = ExtResource("2_yb2ta")
region = Rect2(52, 55, 305, 347)
[sub_resource type="AtlasTexture" id="AtlasTexture_bcx38"]
atlas = ExtResource("2_yb2ta")
region = Rect2(378, 21, 199, 385)
[sub_resource type="AtlasTexture" id="AtlasTexture_t34j2"]
atlas = ExtResource("2_yb2ta")
region = Rect2(75, 527, 316, 399)
[sub_resource type="AtlasTexture" id="AtlasTexture_55qjo"]
atlas = ExtResource("2_yb2ta")
region = Rect2(462, 542, 286, 387)
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_tfnwb"]
random_pitch = 1.4142135
streams_count = 1
stream_0/stream = ExtResource("3_vkbio")
[node name="WinCristal" type="Area2D" unique_id=247353676]
script = ExtResource("1_yb2ta")
data = SubResource("Resource_5lni1")
default_info_title = "TALION_CRISTAL"
default_info_desc = "TALION_CRISTAL_DESC_TEXT"
metadata/_custom_type_script = "uid://d3bk52402ylvl"
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=187731103]
position = Vector2(1, -42)
shape = SubResource("CapsuleShape2D_vkbio")
[node name="Sprites" type="Node2D" parent="." unique_id=940993390]
unique_name_in_owner = true
[node name="AssetCristals" type="Sprite2D" parent="Sprites" unique_id=2111863528]
scale = Vector2(0.4, 0.4)
texture = SubResource("AtlasTexture_5lni1")
offset = Vector2(0, -139.255)
flip_h = true
[node name="AssetCristals2" type="Sprite2D" parent="Sprites" unique_id=1380362341]
visible = false
scale = Vector2(0.3, 0.3)
texture = SubResource("AtlasTexture_bcx38")
offset = Vector2(0, -149)
flip_h = true
[node name="AssetCristals3" type="Sprite2D" parent="Sprites" unique_id=2082980627]
visible = false
scale = Vector2(0.3, 0.3)
texture = SubResource("AtlasTexture_t34j2")
offset = Vector2(0, -150)
flip_h = true
[node name="AssetCristals4" type="Sprite2D" parent="Sprites" unique_id=495215885]
visible = false
scale = Vector2(0.3, 0.3)
texture = SubResource("AtlasTexture_55qjo")
offset = Vector2(0, -150)
flip_h = true
[node name="CristalPlayer" type="AudioStreamPlayer2D" parent="." unique_id=1879646229]
unique_name_in_owner = true
stream = SubResource("AudioStreamRandomizer_tfnwb")
bus = &"Sfx"
+2 -2
View File
@@ -13,6 +13,7 @@ atlas = ExtResource("3_j6jm5")
region = Rect2(76, 75, 124, 135)
[sub_resource type="ViewportTexture" id="ViewportTexture_rbgiq"]
viewport_path = NodePath("LifeTimeSprite/SubViewport")
[sub_resource type="Gradient" id="Gradient_rbgiq"]
interpolation_mode = 1
@@ -185,8 +186,7 @@ texture = ExtResource("3_rbgiq")
[node name="LifeTimeSprite" type="Sprite2D" parent="." unique_id=799762981]
unique_name_in_owner = true
position = Vector2(-1, -9.999985)
scale = Vector2(0.34, 0.34)
scale = Vector2(0.26000002, 0.26000005)
texture = SubResource("ViewportTexture_rbgiq")
[node name="SubViewport" type="SubViewport" parent="LifeTimeSprite" unique_id=1809354262]
+31 -15
View File
@@ -1,7 +1,9 @@
extends InspectableEntity
class_name Plant
const PLANT_AREA_RADIUS = 20
const PLANT_AREA_RADIUS = 40
const PLANT_GROWING_AREA_HEIGHT = 70
const PLANT_MATURE_AREA_HEIGHT = 150
const HARVESTED_SEED_DISPLACEMENT_FACTOR = 100
const RANDOM_MAX_GROW_INTERVAL = Region.MIN_PASS_DAY_ANIMATION_TIME/2. - 0.1
@@ -22,6 +24,7 @@ const SPRITE_SCENE : PackedScene = preload("res://entities/plants/plant_sprite.t
@onready var influence_zone : PlantInfluenceZone
var harvested = false
var last_state : PlantData.State
func _init(
_data : PlantData
@@ -30,7 +33,7 @@ func _init(
func _ready():
plant_sprite = generate_sprite()
collision_shape = generate_collision_shape()
generate_collision_shape()
influence_zone = generate_influence_zone()
plant_sprite.setup_plant_sprite(data)
@@ -53,9 +56,6 @@ func inspect(is_inspected : bool = true):
plant_sprite.display_lifetime_sprite = is_inspected
influence_zone.show_influence = is_inspected
func affect_preview(is_affected : bool = true):
plant_sprite.sprite_modulate = MODULATE_AFFECTED_COLOR if is_affected else default_modulate
func generate_sprite() -> PlantSprite:
var sprite_object : PlantSprite = SPRITE_SCENE.instantiate()
@@ -64,15 +64,28 @@ func generate_sprite() -> PlantSprite:
return sprite_object
func generate_collision_shape() -> CollisionShape2D:
var collision = CollisionShape2D.new()
var shape = CircleShape2D.new()
func generate_collision_shape():
if collision_shape:
collision_shape.queue_free()
collision_shape = CollisionShape2D.new()
var shape = CapsuleShape2D.new()
shape.radius = PLANT_AREA_RADIUS
collision.shape = shape
add_child(collision)
var height = PLANT_AREA_RADIUS
return collision
match data.get_state():
PlantData.State.GROWING:
height = PLANT_GROWING_AREA_HEIGHT
PlantData.State.MATURE:
height = PLANT_MATURE_AREA_HEIGHT
shape.height = height
collision_shape.shape = shape
collision_shape.position.y -= height / 5.
add_child(collision_shape)
func generate_influence_zone() -> PlantInfluenceZone:
var zone = PlantInfluenceZone.new(data.get_influence_radius())
@@ -85,13 +98,14 @@ func generate_influence_zone() -> PlantInfluenceZone:
func _pass_day():
await get_tree().create_timer(randf_range(0., RANDOM_MAX_GROW_INTERVAL)).timeout
var last_state = data.get_state()
last_state = data.get_state()
data.day += 1
for m in data.mutations:
m._start_day_effect(self)
func _end_pass_day():
match data.get_state():
PlantData.State.MATURE:
if last_state != PlantData.State.MATURE:
@@ -99,7 +113,7 @@ func _pass_day():
PlantData.State.DEAD:
die()
generate_collision_shape()
plant_sprite.update_plant_sprite(data, last_state != data.get_state())
@@ -110,7 +124,7 @@ func calculate_plant_score(
func harvest():
for i in range(data.get_seed_number()):
produce_seed()
await produce_seed()
if data.get_state() == PlantData.State.MATURE:
for m in data.mutations:
@@ -128,6 +142,7 @@ func produce_seed():
global_position,
HARVESTED_SEED_DISPLACEMENT_FACTOR,
)
await plant_sprite.play_bump_animation()
func mature():
for m in data.mutations:
@@ -137,7 +152,8 @@ func die():
for m in data.mutations:
m._start_dead_effect(self)
for i in range(data.get_seed_number()):
produce_seed()
await produce_seed()
AudioManager.play_sfx("Harvest")
disappear()
func disappear():
+1 -1
View File
@@ -96,7 +96,7 @@ func is_mature() -> bool:
return get_state() == State.MATURE
func get_seed_number(state = get_state()):
var seed_number = get_plant_info().get_seed_number() if (state == State.MATURE or state == State.DEAD) else 0
var seed_number = get_plant_info().get_seed_number() if (state == State.MATURE or state == State.DEAD) else 1
for m in mutations:
seed_number = m.mutate_seed_number(self , seed_number)
+1 -1
View File
@@ -124,4 +124,4 @@ static func get_rarity_color(rarity: int) -> Color:
Color("FFA617"),
]
return rarity_colors[min(rarity, len(rarity_colors) - 1)%len(rarity_colors)]
return rarity_colors[rarity%len(rarity_colors)]
@@ -23,4 +23,4 @@ func _start_maturation_effect(plant : Plant):
func get_purification_radius() -> int:
return level * 2
return level
+8 -1
View File
@@ -1,4 +1,4 @@
extends Node2D
extends Area2D
class_name PlantSprite
const PLANTED_SEED_CROP_WIDTH = 50
@@ -64,6 +64,13 @@ func set_sprite_modulate(c := sprite_modulate):
if is_node_ready():
%Sprite.modulate = c
func affect_preview(is_affected : bool = true):
sprite_modulate = InspectableEntity.MODULATE_AFFECTED_COLOR if is_affected else Color.WHITE
func _on_body_entered(body: Node2D) -> void:
if body is Player && $AnimationPlayer.current_animation != "player_move":
$AnimationPlayer.play("player_move");
func play_bump_animation():
%AnimationPlayer.play("bump")
await %AnimationPlayer.animation_finished
@@ -17,7 +17,7 @@ func _init(size : int = 1):
seeds_size = size
func current_is_tool() -> bool:
return current_item_ind <= len(tools)
return current_item_ind < len(tools)
func set_current_item(new_ind: int):
if new_ind < 0:
+1 -1
View File
@@ -44,7 +44,7 @@ func is_action_need_press_time() -> bool:
func get_action_press_time() -> float:
return DEFAULT_PRESS_TIME
func get_usage_object_affected(_i : InspectableEntity) -> bool:
func get_usage_object_affected(_i : Area2D) -> bool:
return false
func is_one_time_use():
@@ -21,7 +21,7 @@ func get_energy_used() -> int:
func get_usage_zone_radius() -> int:
return 10
func get_usage_object_affected(i : InspectableEntity) -> bool:
func get_usage_object_affected(i : Area2D) -> bool:
return i is Plant
func use_text() -> String:
@@ -63,10 +63,10 @@ func get_energy_used() -> int:
return 1
func get_usage_zone_radius() -> int:
return 35
return 50
func get_usage_object_affected(i : InspectableEntity) -> bool:
return i is Plant
func get_usage_object_affected(i : Area2D) -> bool:
return i is PlantSprite
func use_text() -> String:
return tr("PLANT_%s") % plant_name
@@ -82,10 +82,19 @@ func can_use(player : Player, zone : Player.ActionZone) -> bool:
var is_there_a_plant_here = false
for area in zone.get_affected_areas():
if area is Plant:
if area is PlantSprite:
is_there_a_plant_here = true
return not is_there_a_plant_here and player.region.is_coords_decontaminated(zone.get_tiles())
var plant_tiles = Math.get_tiles_in_circle(
zone.get_global_position(),
20
)
return (
not is_there_a_plant_here
and player.region.is_coords_decontaminated(plant_tiles)
and not player.region.is_coords_rocky(plant_tiles)
)
func use(player : Player, zone : Player.ActionZone) -> bool:
if player.region == null:
@@ -17,7 +17,7 @@ func get_icon() -> Texture2D:
func get_usage_zone_radius() -> int:
return SHOVEL_ZONE_RADIUS
func get_usage_object_affected(i : InspectableEntity) -> bool:
func get_usage_object_affected(i : Area2D) -> bool:
return i is Plant
func use_text() -> String:
+35 -1
View File
@@ -9,11 +9,23 @@
[ext_resource type="AudioStream" uid="uid://cv5avkd3qekt7" path="res://common/audio_manager/assets/sfx/movement/movement.wav" id="7_qiwj3"]
[sub_resource type="CircleShape2D" id="CircleShape2D_sglur"]
radius = 27.0
radius = 13.0
[sub_resource type="CircleShape2D" id="CircleShape2D_abrql"]
radius = 40.0
[sub_resource type="Gradient" id="Gradient_qiwj3"]
offsets = PackedFloat32Array(0.37339056, 0.49785408)
colors = PackedColorArray(0.043137256, 0.050980393, 0.15686275, 0, 0.043137256, 0.050980393, 0.15686275, 1)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_26q78"]
gradient = SubResource("Gradient_qiwj3")
width = 600
height = 600
fill = 1
fill_from = Vector2(0.5, 0.5)
fill_to = Vector2(0.5, 0)
[sub_resource type="AtlasTexture" id="AtlasTexture_fkugw"]
atlas = ExtResource("4_bls4j")
region = Rect2(3048, 0, 762, 1080)
@@ -113,6 +125,9 @@ animations = [{
"speed": 5.0
}]
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_bectd"]
blend_mode = 1
[sub_resource type="Curve" id="Curve_fkugw"]
_data = [Vector2(0, 0.14473677), 0.0, 0.0, 0, 0, Vector2(0.972549, 0.2654798), 0.0, 0.0, 0, 0]
point_count = 2
@@ -253,6 +268,12 @@ position = Vector2(-2.3841858e-07, -7.999996)
scale = Vector2(0.29154927, 0.29154924)
texture = ExtResource("2_fkugw")
[node name="Fog" type="Sprite2D" parent="." unique_id=1590893330]
z_index = 10
position = Vector2(0.99999994, -17)
scale = Vector2(8, 8)
texture = SubResource("GradientTexture2D_26q78")
[node name="PlayerSprite" type="AnimatedSprite2D" parent="." unique_id=638545037]
unique_name_in_owner = true
position = Vector2(0.99999994, -17)
@@ -267,6 +288,7 @@ wanted_orientation = 2
[node name="Light" type="Sprite2D" parent="PlayerSprite" unique_id=1768327734]
modulate = Color(0.70603025, 0.5959886, 0.33971557, 0.09019608)
z_index = -1
material = SubResource("CanvasItemMaterial_bectd")
scale = Vector2(16.093441, 16.093441)
texture = ExtResource("5_8fjmc")
@@ -290,3 +312,15 @@ bus = &"Sfx"
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=793749564]
unique_name_in_owner = true
libraries/ = SubResource("AnimationLibrary_qiwj3")
[node name="NavigationAgent2D" type="NavigationAgent2D" parent="." unique_id=1282043308]
unique_name_in_owner = true
simplify_path = true
simplify_epsilon = 4.223
path_search_max_polygons = 1000
avoidance_enabled = true
radius = 500.0
debug_use_custom = true
debug_path_custom_color = Color(0.5882353, 0.7019608, 0.85882354, 0.3019608)
debug_path_custom_point_size = 0.0
debug_path_custom_line_width = 1.0
+84 -19
View File
@@ -5,6 +5,7 @@ const ACTION_AREA_UPDATE_TIME=0.05 # When creating an action_zone, we make sure
const MAX_REACH = 100
const HOLDING_ITEM_SPRITE_SIZE = 20.
const TURN_ANIMATION_MINIMUM_THRESHOLD = 0.2
const SPEED = 350
signal player_updated(player: Player)
signal upgraded
@@ -12,7 +13,6 @@ signal upgraded
var terrain : Terrain
var region : Region :
get(): return terrain if terrain is Region else null
@export var speed = 350
var data : PlayerData
var last_action_area_movement_timer : float = 100.
@@ -22,7 +22,13 @@ var controlling_player : bool = false :
controlling_player = v
velocity = Vector2.ZERO
var instruction : Instruction = null
var instruction : Instruction = null :
set(i):
if instruction and is_node_ready():
instruction.abort(self)
instruction = i
if instruction and is_node_ready():
instruction.spawn_indicator(self)
@onready var preview_zone : ActionZone = await setup_action_zone(Vector2.ZERO, null)
@onready var action_zone : ActionZone = await setup_action_zone(Vector2.ZERO, null)
@@ -81,7 +87,7 @@ func _process(delta):
instruction = null
input_direction = calculate_direction_instruction_direction()
velocity = input_direction * speed
velocity = input_direction * SPEED
turn_animate(input_direction)
move_preview_zone(get_global_mouse_position())
@@ -106,8 +112,11 @@ func calculate_direction_instruction_direction() -> Vector2:
instruction.position.distance_to(global_position) > (MAX_REACH - 1.)
or instruction is MoveInstruction
)
):
return self.global_position.direction_to(instruction.position)
):
if %NavigationAgent2D.target_position != instruction.position:
%NavigationAgent2D.target_position = instruction.position
return to_local(%NavigationAgent2D.get_next_path_position()).normalized()
# return self.global_position.direction_to(instruction.position)
return Vector2.ZERO
func calculate_direction_input_direction() -> Vector2:
@@ -147,8 +156,8 @@ func try_interact(interactable : Interactable):
func try_move(move_to : Vector2):
instruction = MoveInstruction.new(move_to)
func can_pick_item(item: Item):
return item.type == Item.ItemType.TOOL_ITEM || !data.inventory.is_full() || !data.inventory.current_is_tool()
func can_pick_item(_item: Item):
return true
func pick_item(item : Item):
if item.type != Item.ItemType.TOOL_ITEM && data.inventory.is_full():
@@ -163,13 +172,23 @@ func pick_item(item : Item):
func drop_item():
var ind_to_drop := data.inventory.current_item_ind
while (
(data.inventory.get_item(ind_to_drop) == null or ind_to_drop < len(data.inventory.tools))
and ind_to_drop < len(data.inventory.get_all_items()) - 1
if (
data.inventory.get_item(ind_to_drop) == null or ind_to_drop < len(data.inventory.tools)
):
ind_to_drop += 1
var item_to_drop = data.inventory.pop_item(ind_to_drop)
if item_to_drop:
var possible_ind : Array = range(
len(data.inventory.tools),
len(data.inventory.tools) + data.inventory.seeds_size
).filter(
func (i): return data.inventory.get_item(i) != null
)
if len(possible_ind):
ind_to_drop = possible_ind.pop_back()
else:
return
var item_to_drop : Item = data.inventory.pop_item(ind_to_drop)
if item_to_drop and item_to_drop.type != Item.ItemType.TOOL_ITEM:
terrain.drop_item(item_to_drop, global_position)
AudioManager.play_sfx("Drop")
region.save()
@@ -239,11 +258,10 @@ func setup_preview_zone(item : Item):
return preview_zone
elif preview_zone:
preview_zone.destroy()
preview_zone = null
if item:
preview_zone = await generate_action_zone(item)
else:
preview_zone = null
func setup_action_zone(zone_position : Vector2, item: Item) -> ActionZone:
if action_zone:
@@ -259,8 +277,11 @@ func move_preview_zone(zone_position : Vector2):
class Instruction:
const INDICATOR_COLOR := Color("#96B3DB")
var position : Vector2
var need_movement : bool = true
var indicator := Sprite2D.new()
func _init(_pos : Vector2):
position = _pos
@@ -270,8 +291,46 @@ class Instruction:
func do(_player : Player):
pass
func indicator_texture():
return preload("res://common/icons/map-pin.svg")
func indicator_size():
return 40
func indicator_shift():
return Vector2.ZERO
func spawn_indicator(player : Player):
indicator.texture = indicator_texture()
indicator.texture = indicator_texture()
indicator.scale = Vector2(
1./(float(indicator_texture().get_width())/indicator_size()),
1./(float(indicator_texture().get_height())/indicator_size())
)
indicator.modulate = Color(
INDICATOR_COLOR.r,
INDICATOR_COLOR.g,
INDICATOR_COLOR.b,
0.
)
player.get_parent().add_child(indicator)
indicator.global_position = position + indicator_shift()
player.get_tree().create_tween().tween_property(indicator, "modulate:a", 0.8, 0.2)
func abort(player : Player):
indicator.queue_free()
class MoveInstruction extends Instruction:
func indicator_shift():
return Vector2.UP * 50
func can_be_done(player : Player):
return player.global_position.distance_to(position) < 10.
@@ -289,7 +348,10 @@ class ItemActionInstruction extends Instruction:
not item.is_usage_need_proximity() or
player.global_position.distance_to(position) < player.MAX_REACH
)
func indicator_texture():
return item.icon
func do(player : Player):
player.use_item(item)
@@ -303,13 +365,16 @@ class InteractableInstruction extends Instruction:
func can_be_done(player : Player):
return player.global_position.distance_to(position) < player.MAX_REACH
func indicator_texture():
return preload("res://common/icons/hand-grab.svg")
func do(player : Player):
interactable.interact(player)
class ActionZone:
var item : Item = null
var area : Area2D = Area2D.new()
var affected_areas : Array[InspectableEntity]= []
var affected_areas : Array[Area2D]= []
func _init(_i : Item):
item = _i
@@ -330,9 +395,9 @@ class ActionZone:
func update_preview_on_affected_area():
var detected_areas = get_affected_areas()
clear_preview_on_affected_area()
var new_affected_areas : Array[InspectableEntity] = []
var new_affected_areas : Array[Area2D] = []
for a in detected_areas:
if a is InspectableEntity and item.get_usage_object_affected(a):
if a is Area2D and item.get_usage_object_affected(a) and a.has_method("affect_preview"):
a.affect_preview(true)
new_affected_areas.append(a)
affected_areas = new_affected_areas
+1 -1
View File
@@ -2,7 +2,7 @@ extends CharacterBody3D
class_name Player3D
const POINTER_TEXTURE = preload("res://common/icons/focus.svg")
const POINTER_ACTION_TEXTURE = preload("res://common/icons/hand-stop.svg")
const POINTER_ACTION_TEXTURE = preload("res://common/icons/hand-finger.svg")
@export var pointer_texture_rect : TextureRect
-3
View File
@@ -4,9 +4,6 @@ class_name EntityData
@export var position : Vector2
func _init(e : Entity):
position = e.global_position
func get_position() -> Vector2:
return position
+10 -2
View File
@@ -1,8 +1,8 @@
extends Entity
class_name InspectableEntity
const MODULATE_INSPECTED_COLOR = Color.GRAY
const MODULATE_AFFECTED_COLOR = Color.RED
const MODULATE_INSPECTED_COLOR = Color("#96B3DB")
const MODULATE_AFFECTED_COLOR = Color("#FF006E")
const DESC_ICON = preload("res://common/icons/align-right.svg")
@export var default_info_title = ""
@@ -11,6 +11,8 @@ const DESC_ICON = preload("res://common/icons/align-right.svg")
@onready var default_modulate : Color = modulate
@onready var inspectable_signals_setuped : bool = setup_inspectable_signals()
var mouse_over := false
func inspect(is_inspected : bool = true):
modulate = MODULATE_INSPECTED_COLOR if is_inspected else default_modulate
@@ -23,9 +25,11 @@ func setup_inspectable_signals() -> bool:
return true
func _on_mouse_entered():
mouse_over = true
Pointer.inspect(self)
func _on_mouse_excited():
mouse_over = false
Pointer.stop_inspect(self)
func pointer_text() -> String:
@@ -54,3 +58,7 @@ func _notification(what):
func get_card_up_padding() -> float:
return Pointer.CARD_UP_PADDING
func _process(_delta):
modulate.a = 0.3 if mouse_over and Pointer.inspected != self else 1.