Loading...
Loading...
Expert blueprint for RPG stat systems (attributes, leveling, modifiers, damage formulas) using Resource-based stats, stackable modifiers, and derived stat calculations. Use when implementing character progression OR equipment/buff systems. Keywords stats, attributes, leveling, modifiers, CharacterStats, derived stats, damage calculation, XP.
npx skill4agent add thedivergentai/gd-agentic-skills godot-rpg-statsvar critical_chance: int = 50floatstats.current_health -= 10add_modifier("strength", 5)xp_to_next = level * 1000max_health = vitality * 10maxi(value, 1)# stats.gd
class_name Stats
extends Resource
signal stat_changed(stat_name: String, old_value: float, new_value: float)
signal level_up(new_level: int)
@export var level: int = 1
@export var experience: int = 0
@export var experience_to_next_level: int = 100
# Base stats
@export var strength: int = 10
@export var dexterity: int = 10
@export var intelligence: int = 10
@export var vitality: int = 10
# Derived stats (calculated from base)
var max_health: int:
get: return vitality * 10
var attack_power: int:
get: return strength * 2
var defense: int:
get: return strength + (vitality / 2)
var magic_power: int:
get: return intelligence * 3
var critical_chance: float:
get: return dexterity * 0.01
# Modifiers
var modifiers: Dictionary = {}
func add_experience(amount: int) -> void:
experience += amount
while experience >= experience_to_next_level:
level_up_character()
func level_up_character() -> void:
level += 1
experience -= experience_to_next_level
experience_to_next_level = int(experience_to_next_level * 1.5)
# Increase base stats
strength += 2
dexterity += 2
intelligence += 2
vitality += 2
level_up.emit(level)
func get_stat(stat_name: String) -> float:
var base_value: float = get(stat_name)
var modifier_bonus := get_modifier_total(stat_name)
return base_value + modifier_bonus
func add_modifier(stat_name: String, modifier_id: String, value: float) -> void:
if not modifiers.has(stat_name):
modifiers[stat_name] = {}
modifiers[stat_name][modifier_id] = value
func remove_modifier(stat_name: String, modifier_id: String) -> void:
if modifiers.has(stat_name):
modifiers[stat_name].erase(modifier_id)
func get_modifier_total(stat_name: String) -> float:
if not modifiers.has(stat_name):
return 0.0
var total := 0.0
for value in modifiers[stat_name].values():
total += value
return total# equipment_item.gd
extends Item
class_name EquipmentItem
@export var stat_bonuses: Dictionary = {
"strength": 5,
"dexterity": 3
}
func on_equip(stats: Stats) -> void:
for stat_name in stat_bonuses:
stats.add_modifier(stat_name, "equipment_" + id, stat_bonuses[stat_name])
func on_unequip(stats: Stats) -> void:
for stat_name in stat_bonuses:
stats.remove_modifier(stat_name, "equipment_" + id)# status_effect.gd
class_name StatusEffect
extends Resource
@export var effect_id: String
@export var duration: float
@export var stat_modifiers: Dictionary = {}
func apply(stats: Stats) -> void:
for stat_name in stat_modifiers:
stats.add_modifier(stat_name, "status_" + effect_id, stat_modifiers[stat_name])
func remove(stats: Stats) -> void:
for stat_name in stat_modifiers:
stats.remove_modifier(stat_name, "status_" + effect_id)func calculate_damage(attacker_stats: Stats, defender_stats: Stats) -> float:
var base_damage := float(attacker_stats.attack_power)
var defense := float(defender_stats.defense)
# Damage reduction formula
var damage := base_damage * (100.0 / (100.0 + defense))
# Critical hit
if randf() < attacker_stats.critical_chance:
damage *= 2.0
return maxf(damage, 1.0) # Minimum 1 damage# skill.gd
class_name Skill
extends Resource
@export var required_level: int = 1
@export var required_stats: Dictionary = {
"strength": 15,
"intelligence": 10
}
func can_use(stats: Stats) -> bool:
if stats.level < required_level:
return false
for stat_name in required_stats:
if stats.get_stat(stat_name) < required_stats[stat_name]:
return false
return truegodot-combat-systemgodot-inventory-system