Files
DartGame/game/core/modding/mod_registry.gd
T

93 lines
2.5 KiB
GDScript

extends Node
## Loads modifier definitions and serves them by id.
##
## ⚠️ PROTOTYPE. This is scaffolding, not the real mod loader.
##
## What's wrong with it, to be fixed in Phase 3:
## - DirAccess cannot walk into a PCK. This works in the editor and silently
## returns NOTHING in an exported build. Needs a build-time manifest.
## - No namespacing. Ids are bare strings, so two mods can collide.
## - No mod.json, no api_version, no dependency resolution.
## - Only reads content/official/. Doesn't touch user://mods/.
##
## Autoload name is ModRegistry (PascalCase), so call sites read as
## ModRegistry.get_by_id(...) rather than looking like a local variable.
const MODIFIER_DIR := "res://content/official/modifiers/"
var modifiers: Array[Modifier] = []
var _by_id: Dictionary = {}
func _ready() -> void:
_load_from_folder(MODIFIER_DIR)
_reindex()
print("ModRegistry: loaded %d modifiers." % modifiers.size())
## Recursive, because each modifier now lives in its own folder:
## modifiers/mjolnir/mjolnir.tres
func _load_from_folder(path: String) -> void:
var dir := DirAccess.open(path)
if dir == null:
push_warning("ModRegistry: can't open %s" % path)
return
dir.list_dir_begin()
var fname := dir.get_next()
while fname != "":
var full := path.path_join(fname)
if dir.current_is_dir():
if not fname.begins_with("."):
_load_from_folder(full)
elif fname.ends_with(".tres"):
var res := load(full)
if res is Modifier:
modifiers.append(res)
else:
push_warning("ModRegistry: %s is not a Modifier" % full)
fname = dir.get_next()
dir.list_dir_end()
func _reindex() -> void:
_by_id.clear()
for m in modifiers:
if m.id.is_empty():
push_warning("ModRegistry: modifier with empty id, skipping.")
continue
if _by_id.has(m.id):
push_warning("ModRegistry: duplicate id '%s'." % m.id)
_by_id[m.id] = m
func get_by_id(id: String) -> Modifier:
return _by_id.get(id)
## Pick `count` distinct modifiers, weighted by rarity.
func pick_random(count: int) -> Array[Modifier]:
var pool := modifiers.duplicate()
var chosen: Array[Modifier] = []
count = mini(count, pool.size())
for _i in count:
var total := 0.0
for m in pool:
total += maxf(m.weight, 0.0001)
var r := randf() * total
var acc := 0.0
var picked := 0
for j in pool.size():
acc += maxf(pool[j].weight, 0.0001)
if r <= acc:
picked = j
break
chosen.append(pool[picked])
pool.remove_at(picked) # distinct — don't offer the same one twice
return chosen