8const EventManager = preload(
"res://scripts/systems/eventManager/event_manager.gd")
10var catalog = EventManager.new()
11var rng := RandomNumberGenerator.new()
12var event_chance := 0.10
15var trade_progress_multiplier := 3.0
16var next_eligible_stage := 1
17var last_seen:Dictionary = {}
18var errors:Array[String] = []
25func configure(settings:Dictionary) -> void:
26 event_chance = clampf(float(settings.get(
"event_chance", event_chance)), 0.0, 1.0)
27 quiet_gap_min = maxi(1, int(settings.get(
"quiet_gap_min", quiet_gap_min)))
28 quiet_gap_max = maxi(quiet_gap_min, int(settings.get(
"quiet_gap_max", quiet_gap_max)))
29 trade_progress_multiplier = maxf(1.0, float(settings.get(
"trade_progress_multiplier", trade_progress_multiplier)))
32func load_directory(path:String) -> bool:
33 catalog.load_events(path)
36 for raw
in catalog.all_events:
37 if not raw
is Dictionary:
continue
38 var event:Dictionary = raw
39 var id := str(event.get(
"id",
""))
41 errors.append(
"Event in %s has no id" % str(event.get(
"pack",
"?")))
42 elif seen_ids.has(id):
43 errors.append(
"Duplicate room event id: %s" % id)
46 if float(event.get(
"weight", 0.0)) <= 0.0:
47 errors.append(
"Room event %s needs a positive weight" % id)
48 if float(event.get(
"duration", 0.0)) <= 0.0:
49 errors.append(
"Room event %s needs a positive duration" % id)
50 if int(event.get(
"minimum_objective", event.get(
"minimum_stage", 1))) < 1:
51 errors.append(
"Room event %s has an invalid minimum stage" % id)
52 if int(event.get(
"cooldown", 0)) < 0:
53 errors.append(
"Room event %s has a negative cooldown" % id)
54 if not event.get(
"allowed_themes", [])
is Array:
55 errors.append(
"Room event %s has invalid allowed_themes" % id)
56 var visuals:Variant = event.get(
"visuals", [])
57 if not visuals
is Array:
58 errors.append(
"Room event %s has invalid visuals" % id)
60 for visual
in visuals:
61 if not visual
is Dictionary
or str(visual.get(
"kind",
""))
not in [
"ring",
"circle",
"rect",
"glyph",
"sprite"]:
62 errors.append(
"Room event %s has an unknown visual primitive" % id)
63 if catalog.all_events.is_empty(): errors.append(
"No room events found in %s" % path)
64 if not errors.is_empty():
65 catalog.all_events.clear()
70func get_definitions() -> Array:
71 return catalog.all_events
74func get_by_id(event_id:String) -> Dictionary:
75 return catalog.get_event_by_id(event_id)
78func roll(stage:int, theme:int, context:Dictionary = {}) -> Dictionary:
79 if stage < next_eligible_stage
or rng.randf() > event_chance:
return {}
80 var candidates:Array = []
82 for raw
in catalog.all_events:
83 var event:Dictionary = raw
84 var id := str(event.get(
"id",
""))
85 if stage < int(event.get(
"minimum_objective", event.get(
"minimum_stage", 1))):
continue
86 if stage - int(last_seen.get(id, -100000)) < int(event.get(
"cooldown", 0)):
continue
87 var allowed:Array = event.get(
"allowed_themes", [])
88 if not allowed.is_empty()
and theme
not in allowed:
continue
89 var required_item := str(event.get(
"requires_item",
""))
90 if required_item !=
"" and int(context.get(
"inventory", {}).get(required_item, 0)) <= 0:
continue
91 var inventory:Dictionary = context.get(
"inventory", {})
92 var missing_requirement := false
93 for required
in event.get(
"requires_all", []):
94 if int(inventory.get(str(required), 0)) <= 0: missing_requirement = true
95 if missing_requirement:
continue
96 var blocked_by_item := false
97 for excluded
in event.get(
"excludes_items", []):
98 if int(inventory.get(str(excluded), 0)) > 0: blocked_by_item = true
99 if blocked_by_item:
continue
100 var once_key := str(event.get(
"once_key",
""))
101 if once_key !=
"" and bool(context.get(
"trade_flags", {}).get(once_key, false)):
continue
102 var effective_weight := float(event.get(
"weight", 1.0))
103 if str(event.get(
"trade_kind",
"")) !=
"" and (required_item !=
"" or not event.get(
"requires_all", []).is_empty()):
104 effective_weight *= float(event.get(
"progress_multiplier", trade_progress_multiplier))
105 total += effective_weight
106 candidates.append({
"event":event,
"limit":total})
107 if candidates.is_empty():
return {}
108 var roll_value := rng.randf_range(0.0, total)
109 for candidate
in candidates:
110 if roll_value <= float(candidate.limit):
111 var picked:Dictionary = candidate.event
112 last_seen[str(picked.get(
"id",
""))] = stage
113 next_eligible_stage = stage + rng.randi_range(quiet_gap_min, quiet_gap_max)
120 next_eligible_stage = 1
123func get_state() -> Dictionary:
124 return {
"last_seen":last_seen.duplicate(true),
"next_eligible_stage":next_eligible_stage}
127func set_state(state:Dictionary) -> void:
128 last_seen = state.get(
"last_seen", {}).duplicate(true)
129 next_eligible_stage = maxi(1, int(state.get(
"next_eligible_stage", 1)))