RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
card_modifier_manager.gd
Go to the documentation of this file.
1extends RefCounted
2
3
10
11const MODIFIERS := {
12 "metal": {
13 "name": "Metal",
14 "rarity": "Common",
15 "health": 0,
16 "attack": 0,
17 "defense": 3,
18 "description": "+3 DEF"
19 },
20 "sharp": {
21 "name": "Sharp",
22 "rarity": "Common",
23 "health": 0,
24 "attack": 3,
25 "defense": 0,
26 "description": "+3 ATK"
27 },
28 "hardy": {
29 "name": "Hardy",
30 "rarity": "Common",
31 "health": 6,
32 "attack": 0,
33 "defense": 0,
34 "description": "+6 HP"
35 },
36 "blessed": {
37 "name": "Blessed",
38 "rarity": "Rare",
39 "health": 3,
40 "attack": 3,
41 "defense": 3,
42 "description": "+3 all stats"
43 },
44 "giant": {
45 "name": "Giant",
46 "rarity": "Rare",
47 "health": 10,
48 "attack": 2,
49 "defense": 0,
50 "description": "+10 HP, +2 ATK"
51 },
52 "mythic": {
53 "name": "Mythic",
54 "rarity": "Ultra Rare",
55 "health": 8,
56 "attack": 4,
57 "defense": 4,
58 "description": "+8 HP, +4 ATK, +4 DEF"
59 }
60}
61
62const MAX_MERGES_BY_RARITY := {
63 "Common": 5,
64 "Rare": 4,
65 "Epic": 3,
66 "Legendary": 2
67}
68const GLOBAL_MAX_LEVEL := 5
69
70var next_uid := 1
71
72
73
74func make_card_instance(base_card:Dictionary, modifier_ids:Array = [], level:int = 1) -> Dictionary:
75 var instance = {
76 "uid": _make_uid(),
77 "base_id": str(base_card.get("id", "")),
78 "modifier_ids": modifier_ids.duplicate(),
79 "level": max(1, level)
80 }
81 return apply_instance(base_card, instance)
82
83
84
85func roll_card_instance(base_card:Dictionary) -> Dictionary:
86 return make_card_instance(base_card, _roll_modifiers())
87
88
89
91func apply_instance(base_card:Dictionary, instance:Dictionary) -> Dictionary:
92 var card = base_card.duplicate(true)
93 var level = max(1, int(instance.get("level", 1)))
94 var modifier_ids = instance.get("modifier_ids", [])
95 card["uid"] = str(instance.get("uid", ""))
96 card["base_id"] = str(instance.get("base_id", card.get("id", "")))
97 card["base_card_id"] = str(card.get("base_id", card.get("id", "")))
98 card["modifier_ids"] = modifier_ids.duplicate()
99 card["level"] = level
100 card["locked"] = bool(instance.get("locked", false))
101 card["health"] = int(card.get("health", 0)) + ((level - 1) * 4)
102 card["attack"] = int(card.get("attack", 0)) + (level - 1)
103 card["defense"] = int(card.get("defense", 0)) + int((level - 1) / 2)
104 for modifier_id in modifier_ids:
105 var modifier = MODIFIERS.get(str(modifier_id), {})
106 card["health"] = int(card.get("health", 0)) + int(modifier.get("health", 0))
107 card["attack"] = int(card.get("attack", 0)) + int(modifier.get("attack", 0))
108 card["defense"] = int(card.get("defense", 0)) + int(modifier.get("defense", 0))
109 card["value"] = _calculate_value(base_card, card, level, modifier_ids)
110 card["name"] = _format_instance_name(base_card, level, modifier_ids)
111 return card
112
113
114
115func get_modifier_names(modifier_ids:Array) -> Array:
116 var names = []
117 for modifier_id in modifier_ids:
118 var modifier = MODIFIERS.get(str(modifier_id), {})
119 if not modifier.is_empty():
120 names.append(str(modifier.get("name", modifier_id)))
121 return names
122
123
124
125func get_modifier_summary(modifier_ids:Array) -> String:
126 var parts = []
127 for modifier_id in modifier_ids:
128 var modifier = MODIFIERS.get(str(modifier_id), {})
129 if not modifier.is_empty():
130 parts.append("%s (%s)" % [modifier.get("name", modifier_id), modifier.get("description", "")])
131 return ", ".join(parts) if not parts.is_empty() else "None"
132
133
134
135func get_instance_record(card:Dictionary) -> Dictionary:
136 return {
137 "uid": str(card.get("uid", "")),
138 "base_id": str(card.get("base_id", card.get("base_card_id", card.get("id", "")))),
139 "modifier_ids": card.get("modifier_ids", []).duplicate(),
140 "level": int(card.get("level", 1)),
141 "locked": bool(card.get("locked", false))
142 }
143
144
145
146func get_max_merges(base_card:Dictionary) -> int:
147 return int(MAX_MERGES_BY_RARITY.get(str(base_card.get("rarity", "Common")), 1))
148
149
150
151func get_max_level(base_card:Dictionary) -> int:
152 return min(get_max_merges(base_card) + 1, GLOBAL_MAX_LEVEL)
153
154
155
156func can_upgrade(base_card:Dictionary, instance:Dictionary) -> bool:
157 return int(instance.get("level", 1)) < get_max_level(base_card)
158
159
160
161func preview_upgrade(base_card:Dictionary, instance:Dictionary, material_instance:Dictionary = {}) -> Dictionary:
162 var preview = instance.duplicate(true)
163 var material_level = int(material_instance.get("level", 1))
164 preview["level"] = min(int(preview.get("level", 1)) + material_level, get_max_level(base_card))
165 return apply_instance(base_card, preview)
166
167
168func reset_counter() -> void:
169 next_uid = 1
170
171
172func sync_counter(instances:Array) -> void:
173 var highest := 0
174 for instance in instances:
175 var uid = str(instance.get("uid", ""))
176 if uid.begins_with("card_"):
177 highest = max(highest, int(uid.trim_prefix("card_")))
178 next_uid = highest + 1
179
180
181func _roll_modifiers() -> Array:
182 var roll = randi_range(1, 100)
183 if roll <= 70:
184 return []
185 if roll <= 92:
186 return [[ "metal", "sharp", "hardy" ].pick_random()]
187 if roll <= 99:
188 return [[ "blessed", "giant" ].pick_random()]
189 return ["mythic", [ "metal", "sharp", "hardy" ].pick_random()]
190
191
192func _make_uid() -> String:
193 var uid = "card_%d" % next_uid
194 next_uid += 1
195 return uid
196
197
198func _format_instance_name(base_card:Dictionary, level:int, modifier_ids:Array) -> String:
199 var names = get_modifier_names(modifier_ids)
200 var prefix = " ".join(names)
201 var base_name = str(base_card.get("name", "Card"))
202 var level_suffix = " +%d" % (level - 1) if level > 1 else ""
203 return ("%s %s%s" % [prefix, base_name, level_suffix]).strip_edges()
204
205
206func _calculate_value(base_card:Dictionary, card:Dictionary, level:int, modifier_ids:Array) -> int:
207 var base_value = int(base_card.get("value", 0))
208 var stat_gain = max(0, int(card.get("health", 0)) - int(base_card.get("health", 0)))
209 stat_gain += max(0, int(card.get("attack", 0)) - int(base_card.get("attack", 0))) * 8
210 stat_gain += max(0, int(card.get("defense", 0)) - int(base_card.get("defense", 0))) * 8
211 return int(round((base_value + stat_gain + (modifier_ids.size() * 12)) * (1.0 + ((level - 1) * 0.25))))