Zoom, nouvelles mutations et cie

* ajout d'une aide de jeu directement dans l'interface
* ajout de 8 nouvelles mutations (Productif, pressé, pur, vivace, généreux, robuste, protecteur et prolifique)
* changements d'icône pour plus de clarté
* changement de l'animation de recharge pour montrer le temps qui passe
* ajout des mutations rare et de la possibilité d'avoir des mutation niveau 2 dès le départ
* ajout d'un zoom
* correction de bugs (déplacement au dialogue, problème de score au load d'une région)
This commit is contained in:
2026-03-20 17:16:56 +01:00
parent 76707171fa
commit 4b16d52740
52 changed files with 1217 additions and 272 deletions

View File

@@ -1,14 +1,29 @@
extends Camera2D
class_name Camera
const LERP_WEIGHT = 0.9
const MOVE_LERP_WEIGHT = 0.9
const ZOOM_LERP_WEIGHT = 0.05
const ZOOM_STEP = 0.1
@export var following : Node2D
@onready var settings = GameInfo.settings_data
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()
func _ready():
if following:
zoom = Vector2.ONE * settings.zoom
global_position = following.global_position
func _process(_delta):
if following:
global_position = following.global_position.lerp(global_position, LERP_WEIGHT)
global_position = following.global_position.lerp(global_position, MOVE_LERP_WEIGHT)
zoom = zoom.lerp(Vector2.ONE * settings.zoom, MOVE_LERP_WEIGHT)

View File

@@ -11,8 +11,8 @@ const SCORE_ICON = preload("res://common/icons/growth.svg")
const DURATION_ICON = preload("res://common/icons/calendar-week.svg")
const SHOVEL_ICON = preload("res://common/icons/shovel.svg")
const GROWING_ICON = preload("res://common/icons/chevrons-up.svg")
const LIFETIME_ICON= preload("res://common/icons/skull.svg")
const SEED_ICON = preload("res://common/icons/droplets.svg")
const LIFETIME_ICON= preload("res://common/icons/clock.svg")
const SEED_ICON = preload("res://common/icons/seeds.svg")
const SPRITE_SCENE : PackedScene = preload("res://entities/plants/plant_sprite.tscn")
@@ -40,9 +40,11 @@ func _ready():
func (_d : RegionData):
await get_tree().create_timer(0.05).timeout
update_nearby_plant()
update_decontamination_area_factor()
)
await get_tree().create_timer(0.05).timeout
update_nearby_plant()
update_decontamination_area_factor()
func pointer_text() -> String:
return data.plant_name
@@ -151,6 +153,23 @@ func update_nearby_plant():
data.nearby_plant_updated.emit()
func update_decontamination_area_factor():
var factor = 0.
var full_decontaminated = true
var tiles = Math.get_tiles_in_circle(global_position, influence_zone.radius + Region.TILE_SIZE)
for tile : Vector2i in tiles:
if region.is_coords_decontaminated([tile]):
factor += 1./len(tiles)
else :
full_decontaminated = false
if full_decontaminated:
data.decontamination_area_factor = 1.
else:
data.decontamination_area_factor = factor
func save() -> EntityData:
return data

View File

@@ -13,10 +13,19 @@ class_name PlantArchetype
AncientMutation.new(),
EphemeralMutation.new(),
FertileMutation.new(),
GenerousMutation.new(),
HurriedMutation.new(),
PrecociousMutation.new(),
ProlificMutation.new(),
ProtectiveMutation.new(),
PureMutation.new(),
PurificationMutation.new(),
QualityMutation.new(),
QuickMutation.new(),
RobustMutation.new(),
SocialMutation.new(),
ToughMutation.new()
ToughMutation.new(),
VivaciousMutation.new(),
]
static func get_all() -> Array[PlantArchetype]:

View File

@@ -21,6 +21,7 @@ enum State {PLANTED, GROWING, MATURE, DEAD}
# var texture_builder: TextureBuilder = preload("res://entities/plants/scripts/texture_builder/texture_builder.tres")
var decontamination_area_factor = 0.
var nearby_plants : Array[PlantData]
func _init(
@@ -83,7 +84,10 @@ func get_score(state: State = get_state()) -> int:
score = m.mutate_score(self , score)
mult = m.mutate_score_multiplier(self , mult)
return score * mult
for pd in nearby_plants:
score += pd.get_score_buff()
return max(0,score) * mult
func get_state() -> State:
if day >= get_lifetime():
@@ -125,7 +129,7 @@ func get_lifetime_buff() -> int:
var buff = 0
for m in mutations:
buff += m.mutate_lifetime_buff(self)
buff = m.mutate_lifetime_buff(self, buff)
return buff
@@ -137,5 +141,13 @@ func get_seed_buff() -> int:
return buff
func get_score_buff() -> int:
var buff = 0
for m in mutations:
buff = m.mutate_score_buff(self, buff)
return buff
func disappear():
disappeared.emit(self )

View File

@@ -20,8 +20,7 @@ func get_mutation_id() -> String:
return ""
func get_mutation_name() -> String:
printerr("Classe abstraite PlantMutation appelée")
return ""
return tr(get_mutation_id())
func get_mutation_description() -> String:
printerr("Classe abstraite PlantMutation appelée")
@@ -48,12 +47,15 @@ func mutate_seed_number(_plant_data: PlantData, seed_number: int) -> int:
func mutate_seed_random_loose(_plant_data: PlantData, seed_random_loose) -> int:
return seed_random_loose
func mutate_lifetime_buff(_plant_data: PlantData) -> int:
return 0
func mutate_lifetime_buff(_plant_data: PlantData, lifetime_buff : int) -> int:
return lifetime_buff
func mutate_seed_buff(_plant_data: PlantData, seed_buff : int) -> int:
return seed_buff
func mutate_score_buff(_plant_data: PlantData, score_buff : int) -> int:
return score_buff
func _start_planted_effect(_plant: Plant):
pass

View File

@@ -4,6 +4,9 @@ class_name FertileMutation
func get_icon() -> Texture:
return preload("res://common/icons/seedling.svg")
func get_base_rarity() -> int:
return 1
func get_mutation_id() -> String:
return "FERTILE"
@@ -13,11 +16,19 @@ func get_mutation_name() -> String:
func get_mutation_description() -> String:
return tr("FERTILE_EFFECT_TEXT").format({
"seed_buff": get_seed_buff(),
"seed_icon": Text.bbcode_icon(Plant.SEED_ICON)
"seed_icon": Text.bbcode_icon(Plant.SEED_ICON),
"score_change": get_score_change(),
"score_icon": Text.bbcode_icon(Plant.SCORE_ICON),
})
func mutate_seed_buff(_plant_data: PlantData, seed_buff) -> int:
return seed_buff + get_seed_buff()
func mutate_score(_plant_data: PlantData, score: int) -> int:
return score + get_score_change()
func get_seed_buff():
return level
return level
func get_score_change():
return -1

View File

@@ -0,0 +1,30 @@
extends PlantMutation
class_name GenerousMutation
func get_icon() -> Texture:
return preload("res://common/icons/carambola.svg")
func get_base_rarity() -> int:
return 1
func get_mutation_id() -> String:
return "GENEROUS"
func get_mutation_description() -> String:
return tr("GENEROUS_EFFECT_TEXT").format({
"score_buff": get_score_buff(),
"score_icon": Text.bbcode_icon(Plant.SCORE_ICON)
})
func mutate_score_multiplier(plant_data: PlantData, multiplier: int) -> int:
if plant_data.get_state() == PlantData.State.MATURE:
return 0
return multiplier
func mutate_score_buff(plant_data: PlantData, score_buff : int) -> int:
if plant_data.get_state() == PlantData.State.MATURE:
return score_buff + get_score_buff()
return score_buff
func get_score_buff():
return level

View File

@@ -0,0 +1 @@
uid://7bfgsrkp6gaq

View File

@@ -0,0 +1,23 @@
extends PlantMutation
class_name HurriedMutation
func get_icon() -> Texture:
return preload("res://common/icons/chevrons-up.svg")
func get_base_rarity() -> int:
return 1
func get_mutation_id() -> String:
return "HURRIED"
func get_mutation_description() -> String:
return tr("HURRIED_EFFECT_TEXT").format({
"growing_time_change": get_growing_time_change(),
"growing_time_icon": Text.bbcode_icon(Plant.GROWING_ICON)
})
func mutate_growing_time(_plant_data: PlantData, growing_time: int) -> int:
return growing_time + get_growing_time_change()
func get_growing_time_change():
return -level

View File

@@ -0,0 +1 @@
uid://ch44r5vkwpkwc

View File

@@ -0,0 +1,20 @@
extends PlantMutation
class_name ProlificMutation
func get_icon() -> Texture:
return preload("res://common/icons/droplets.svg")
func get_mutation_id() -> String:
return "PROLIFIC"
func get_mutation_description() -> String:
return tr("PROLIFIC_EFFECT_TEXT").format({
"seeds_change": get_seed_change(),
"seeds_icon": Text.bbcode_icon(Plant.SEED_ICON)
})
func mutate_seed_number(_plant_data: PlantData, seed_number: int) -> int:
return get_seed_change() + seed_number
func get_seed_change():
return level

View File

@@ -0,0 +1 @@
uid://csk5xull465m3

View File

@@ -0,0 +1,20 @@
extends PlantMutation
class_name ProtectiveMutation
func get_icon() -> Texture:
return preload("res://common/icons/tree.svg")
func get_mutation_id() -> String:
return "PROTECTIVE"
func get_mutation_description() -> String:
return tr("PROTECTIVE_EFFECT_TEXT").format({
"lifetime_buff": get_lifetime_buff(),
"lifetime_icon": Text.bbcode_icon(Plant.LIFETIME_ICON)
})
func mutate_lifetime_buff(_plant_data: PlantData, lifetime_buff : int) -> int:
return lifetime_buff + get_lifetime_buff()
func get_lifetime_buff():
return level

View File

@@ -0,0 +1 @@
uid://b5nc8f0gnalxu

View File

@@ -0,0 +1,25 @@
extends PlantMutation
class_name PureMutation
func get_icon() -> Texture:
return preload("res://common/icons/north-star.svg")
func get_mutation_id() -> String:
return "PURE"
func get_base_rarity() -> int:
return 1
func get_mutation_description() -> String:
return tr("PURE_EFFECT_TEXT").format({
"score_icon": Text.bbcode_icon(Plant.SCORE_ICON),
"score_multiplier": get_score_multiplier(),
})
func mutate_score_multiplier(plant_data: PlantData, multiplier: int) -> int:
if plant_data.decontamination_area_factor == 1.0:
return multiplier * get_score_multiplier()
return multiplier
func get_score_multiplier()->int:
return level

View File

@@ -0,0 +1 @@
uid://dh5m6tvkewad6

View File

@@ -2,17 +2,11 @@ extends PlantMutation
class_name QualityMutation
func get_icon() -> Texture:
return preload("res://common/icons/north-star.svg")
func get_base_rarity() -> int:
return 0
return preload("res://common/icons/growth.svg")
func get_mutation_id() -> String:
return "QUALITY"
func get_mutation_name() -> String:
return tr("QUALITY")
func get_mutation_description() -> String:
return tr("QUALITY_EFFECT_TEXT").format({
"score": get_score(),

View File

@@ -0,0 +1,20 @@
extends PlantMutation
class_name RobustMutation
func get_icon() -> Texture:
return preload("res://common/icons/clock.svg")
func get_mutation_id() -> String:
return "ROBUST"
func get_mutation_description() -> String:
return tr("ROBUST_EFFECT_TEXT").format({
"lifetime_change": get_lifetime_change(),
"lifetime_icon": Text.bbcode_icon(Plant.LIFETIME_ICON)
})
func mutate_lifetime(_plant_data: PlantData, lifetime: int) -> int:
return lifetime + get_lifetime_change()
func get_lifetime_change():
return level * 2

View File

@@ -0,0 +1 @@
uid://cjcylscs6qn4x

View File

@@ -0,0 +1,22 @@
extends PlantMutation
class_name VivaciousMutation
func get_icon() -> Texture:
return preload("res://common/icons/bolt.svg")
func get_mutation_id() -> String:
return "VIVACIOUS"
func get_mutation_description() -> String:
return tr("VIVACIOUS_EFFECT_TEXT").format({
"score_change": get_score_change(),
"score_icon": Text.bbcode_icon(Plant.SCORE_ICON)
})
func mutate_score(data : PlantData, score : int) -> int:
if data.day == data.get_growing_time():
return score + get_score_change()
return score
func get_score_change():
return level * 2

View File

@@ -0,0 +1 @@
uid://boq38l1dmjvot

View File

@@ -125,8 +125,9 @@ func build_plant_texture(plant_data: PlantData) -> Texture:
parts_to_place[OriginType.BASE_LEAF_ORIGIN] = base_leaves
var mutation_weights: Array[int] = []
for mutation in plant_data.mutations:
parts_to_place[OriginType.MUTATION_ORIGIN].append(parts_mutation_associations[mutation.id].parts)
mutation_weights.append(mutation_weight_base)
if mutation.id in parts_mutation_associations:
parts_to_place[OriginType.MUTATION_ORIGIN].append(parts_mutation_associations[mutation.id].parts)
mutation_weights.append(mutation_weight_base)
var base_image_coord = blend_part(image_center, -base_part.root.position, base_part)
populate_part(parts_to_place, weight_per_origin_type, mutation_weights, base_part, base_image_coord)

View File

@@ -7,6 +7,8 @@ const SHOVEL_ICON = preload("res://common/icons/shovel.svg")
const GROWING_ICON = preload("res://common/icons/chevrons-up.svg")
const SCORE_ICON = preload("res://common/icons/growth.svg")
const RARITY_POOL : Array[int] = [0,0,0,0,0,0,0,1,1,1]
@export var plant_name : String
@export var plant_archetype: PlantArchetype
@export var plant_mutations: Array[PlantMutation]
@@ -39,12 +41,11 @@ static func generate_from_parent(plant_data : PlantData) -> Seed:
static func generate_random() -> Seed:
var archetype = PlantArchetype.get_random()
var random_mutations : Array[PlantMutation] = []
random_mutations.append(archetype.available_mutations.pick_random().duplicate_deep())
var new_seed = Seed.new(
Random.generate_random_word(),
PlantArchetype.get_random(),
random_mutations
[generate_first_mutation(archetype)]
)
return new_seed
@@ -141,6 +142,19 @@ func get_particles() -> Array[EffectParticles.Parameters]:
return param
static func generate_first_mutation(archetype : PlantArchetype) -> PlantMutation:
var rarity : int = RARITY_POOL.pick_random()
var possible_mutation : PlantMutation = archetype.available_mutations.filter(
func (m : PlantMutation): return m.get_base_rarity() <= rarity
).pick_random().duplicate_deep()
var level_to_add = rarity - possible_mutation.get_base_rarity()
possible_mutation.level += level_to_add
return possible_mutation
static func mutate_mutations(parent : PlantData) -> Array[PlantMutation]:
var mutation_possibility : Array[MutationPossibility] = [
@@ -152,13 +166,11 @@ static func mutate_mutations(parent : PlantData) -> Array[PlantMutation]:
):
mutation_possibility = [
UpgradeMutation.new(),
RemoveMutation.new(),
]
elif len(parent.mutations) > 0:
mutation_possibility = [
AddMutation.new(),
UpgradeMutation.new(),
RemoveMutation.new(),
]
var chosen_mutation_possibility = mutation_possibility.pick_random()

View File

@@ -7,6 +7,7 @@ const PARTICLES_DISTANCE = 100
const DEFAULT_ICON = preload("res://common/icons/north-star.svg")
const ENERGY_ICON = preload("res://common/icons/bolt.svg")
const DOOR_ICON = preload("res://common/icons/logout.svg")
const PLANT_ICON = preload("res://common/icons/seedling.svg")
var started_time = 0.
var signals : Array[DetectorSignalIndividual] = []
@@ -30,6 +31,13 @@ func _init(region : Region, pos : Vector2):
DOOR_ICON
)
)
if e is Plant:
signals.append(
DetectorSignalIndividual.new(
(pos - e.global_position).normalized().angle(),
PLANT_ICON
)
)
func _draw():
if started_time < SIGNAL_DURATION:

View File

@@ -59,6 +59,8 @@ func _physics_process(delta):
else:
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
else :
velocity = Vector3.ZERO
# Add the gravity.
if not is_on_floor():