feat(progression): succès/achievements + toasts notification
Nouvel autoload AchievementManager avec 12 succès (Premier éclat, Mineur confirmé, Chasseur de perles, Fouilleur d'épaves, Abysses, Légende des océans, etc.). Chaque déblocage donne un bonus XP et joue un son. HUD: toasts dorés avec icône + titre + desc + fade-in/out, empilés en haut centre. Son bulle au déblocage. Long-terme: cible des milestones cumulatifs qui donnent un sentiment de progression durable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
91
scripts/progression/AchievementManager.gd
Normal file
91
scripts/progression/AchievementManager.gd
Normal file
@@ -0,0 +1,91 @@
|
||||
extends Node
|
||||
|
||||
signal achievement_unlocked(ach: Dictionary)
|
||||
|
||||
const ACHIEVEMENTS: Array = [
|
||||
{"id": "first_break", "name": "Premier éclat", "desc": "Casser ton premier bloc", "xp": 10, "icon": "⛏"},
|
||||
{"id": "ten_breaks", "name": "Mineur apprenti", "desc": "Casser 10 blocs", "xp": 20, "icon": "⛏"},
|
||||
{"id": "hundred_breaks", "name": "Mineur confirmé", "desc": "Casser 100 blocs", "xp": 80, "icon": "⛏"},
|
||||
{"id": "first_pearl", "name": "Lueur nacrée", "desc": "Collecter ta première perle", "xp": 20, "icon": "◉"},
|
||||
{"id": "ten_pearls", "name": "Chasseur de perles", "desc": "Collecter 10 perles", "xp": 120, "icon": "◉"},
|
||||
{"id": "first_craft", "name": "Artisan", "desc": "Crafter ton premier objet", "xp": 15, "icon": "✦"},
|
||||
{"id": "first_wreck", "name": "Fouilleur d'épaves", "desc": "Piller une épave", "xp": 30, "icon": "⚓"},
|
||||
{"id": "depth_50", "name": "Plongée profonde", "desc": "Atteindre -50 m", "xp": 60, "icon": "▼"},
|
||||
{"id": "depth_100", "name": "Abysses", "desc": "Atteindre -100 m", "xp": 200, "icon": "▼"},
|
||||
{"id": "level_5", "name": "Dauphin aguerri", "desc": "Atteindre le niveau 5", "xp": 50, "icon": "★"},
|
||||
{"id": "level_10", "name": "Légende des océans", "desc": "Atteindre le niveau 10", "xp": 150, "icon": "★"},
|
||||
{"id": "echo_first", "name": "Sonar aiguisé", "desc": "Utiliser l'écholocation", "xp": 10, "icon": "))"},
|
||||
]
|
||||
|
||||
var unlocked: Dictionary = {} # id -> true
|
||||
|
||||
var _break_count: int = 0
|
||||
var _pearl_count: int = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var pp: Node = get_node_or_null("/root/PlayerProgress")
|
||||
if pp != null:
|
||||
pp.level_up.connect(_on_level_up)
|
||||
|
||||
|
||||
func note_block_break(block_id: int) -> void:
|
||||
_break_count += 1
|
||||
if _break_count >= 1:
|
||||
_unlock("first_break")
|
||||
if _break_count >= 10:
|
||||
_unlock("ten_breaks")
|
||||
if _break_count >= 100:
|
||||
_unlock("hundred_breaks")
|
||||
if block_id == 7:
|
||||
_unlock("first_wreck")
|
||||
|
||||
|
||||
func note_pearl_collected() -> void:
|
||||
_pearl_count += 1
|
||||
if _pearl_count >= 1:
|
||||
_unlock("first_pearl")
|
||||
if _pearl_count >= 10:
|
||||
_unlock("ten_pearls")
|
||||
|
||||
|
||||
func note_craft() -> void:
|
||||
_unlock("first_craft")
|
||||
|
||||
|
||||
func note_depth(depth_m: int) -> void:
|
||||
if depth_m >= 50:
|
||||
_unlock("depth_50")
|
||||
if depth_m >= 100:
|
||||
_unlock("depth_100")
|
||||
|
||||
|
||||
func note_echolocation() -> void:
|
||||
_unlock("echo_first")
|
||||
|
||||
|
||||
func _on_level_up(new_level: int) -> void:
|
||||
if new_level >= 5:
|
||||
_unlock("level_5")
|
||||
if new_level >= 10:
|
||||
_unlock("level_10")
|
||||
|
||||
|
||||
func _unlock(id: String) -> void:
|
||||
if unlocked.has(id):
|
||||
return
|
||||
var ach: Dictionary = _find(id)
|
||||
if ach.is_empty():
|
||||
return
|
||||
unlocked[id] = true
|
||||
achievement_unlocked.emit(ach)
|
||||
var pp: Node = get_node_or_null("/root/PlayerProgress")
|
||||
if pp != null:
|
||||
pp.award(ach["xp"], "succès: %s" % ach["name"], Vector3.ZERO)
|
||||
|
||||
|
||||
func _find(id: String) -> Dictionary:
|
||||
for a: Dictionary in ACHIEVEMENTS:
|
||||
if a["id"] == id:
|
||||
return a
|
||||
return {}
|
||||
Reference in New Issue
Block a user