@@ -10,60 +10,97 @@ def load_graph():
1010
1111def generate_mermaid ():
1212 nodes = load_graph ()
13+
1314 lines = ["graph TD" ]
1415
15- # Define styles
16+ # Define styles with better contrast
1617 lines .append ("classDef quest fill:#4b0082,stroke:#f9f,stroke-width:2px,color:#fff;" )
1718 lines .append ("classDef location fill:#00008b,stroke:#ccf,stroke-width:2px,color:#fff;" )
1819 lines .append ("classDef cadence fill:#006400,stroke:#cfc,stroke-width:2px,color:#fff;" )
20+ lines .append ("classDef item fill:#444,stroke:#fff,stroke-width:1px,color:#fff;" )
21+ lines .append ("classDef stat fill:#8b4513,stroke:#ff8c00,stroke-width:1px,color:#fff;" )
22+ lines .append ("classDef ability fill:#2f4f4f,stroke:#00ced1,stroke-width:1px,color:#fff;" )
1923 lines .append ("classDef root fill:#8b8b00,stroke:#ff9,stroke-width:4px,color:#fff;" )
2024
21- # Filter for significant nodes to avoid clutter
22- # Focus on Quests, Locations, Cadences
23- significant_types = ["Quest" , "Location" , "Cadence" ]
24- sig_nodes = {n ["id" ]: n for n in nodes if n ["type" ] in significant_types }
25-
26- for nid , node in sig_nodes .items ():
27- # Node Label
28- name = node ["name" ].replace ('"' , "'" )
29- style = ""
25+ # We want to show almost everything now
26+ # Filter out some very common ones if they make it too noisy,
27+ # but for now let's include all for a "Complete Map"
28+
29+ for node in nodes :
30+ nid = node ["id" ]
31+ ntype = node ["type" ]
32+ name = node ["name" ]
3033
31- if node [ "name" ] == "Prologue" :
32- style = ":::root"
33- elif node [ "type" ] == "Quest " :
34- style = ":::quest "
35- elif node [ "type" ] == "Location" :
36- style = ":::location"
37- elif node [ "type" ] == "Cadence" :
38- style = " :::cadence"
34+ # 1. Define Node
35+ style = ntype . lower ()
36+ if nid == "quest_prologue " :
37+ style = "root "
38+
39+ # Shorten some names for the graph
40+ display_name = name . replace ( '"' , "'" )
41+ lines . append ( f' { nid } [" { display_name } "] :::{ style } ' )
3942
40- lines .append (f'{ nid } ["{ name } "]{ style } ' )
43+ # 2. In-Edges (Requirements)
44+ in_edges = node .get ("in_edges" , {})
45+
46+ # Quest Requirements
47+ if "requires_quest" in in_edges :
48+ for req_id in in_edges ["requires_quest" ]:
49+ # If Location requires Quest, it's an "Enables" link
50+ if ntype == "Location" :
51+ lines .append (f"{ req_id } -->|Enables| { nid } " )
52+ else :
53+ lines .append (f"{ req_id } -->|Requires| { nid } " )
54+
55+ # Ability Requirements (for Refinements usually)
56+ if "requires_ability" in in_edges :
57+ for req_id in in_edges ["requires_ability" ]:
58+ lines .append (f"{ req_id } -.->|Allows| { nid } " )
59+
60+ # Stat Requirements
61+ if "requires_stat" in in_edges :
62+ for stat_name , val in in_edges ["requires_stat" ].items ():
63+ stat_id = f"stat_{ stat_name .lower ()} "
64+ lines .append (f"{ stat_id } -.->|Requires { val } | { nid } " )
4165
42- # 2. Location Unlocks (Quest -> Location)
43- if "unlocks_location" in node ["out_edges" ]:
44- for edge in node ["out_edges" ]["unlocks_location" ]:
45- target_id = edge ["targetId" ]
46- if target_id in sig_nodes :
66+ # 3. Out-Edges (Unlocks / Rewards / Productions)
67+ out_edges = node .get ("out_edges" , {})
68+
69+ # Cadence/Ability Unlocks
70+ for unlock_type in ["unlocks_cadence" , "unlocks_ability" , "provides_ability" ]:
71+ if unlock_type in out_edges :
72+ for edge in out_edges [unlock_type ]:
73+ target_id = edge ["targetId" ]
4774 lines .append (f"{ nid } ==>|Unlocks| { target_id } " )
75+
76+ # Location Unlocks (explicit)
77+ if "unlocks_location" in out_edges :
78+ for edge in out_edges ["unlocks_location" ]:
79+ target_id = edge ["targetId" ]
80+ lines .append (f"{ nid } ==>|Unlocks| { target_id } " )
4881
49- # 3. Requirements (Location -> Quest)
50- if "requires_quest" in node ["in_edges" ]:
51- for req_id in node ["in_edges" ]["requires_quest" ]:
52- if req_id in sig_nodes :
53- # Avoid duplicate edges with 'requires_quest' which is also on Quest nodes.
54- if node ["type" ] == "Location" :
55- lines .append (f"{ req_id } -->|Enables| { nid } " )
56- elif node ["type" ] == "Quest" :
57- lines .append (f"{ req_id } -->|Requires| { nid } " )
82+ # Item Rewards / Production
83+ for reward_type in ["rewards" , "produces" , "rewards_item" ]:
84+ if reward_type in out_edges :
85+ for edge in out_edges [reward_type ]:
86+ target_id = edge ["targetId" ]
87+ qty = edge .get ("quantity" , 1 )
88+ lines .append (f"{ nid } --o|Gives { qty } | { target_id } " )
5889
59- # 4. Cadence Unlocks (Quest -> Cadence)
60- if "unlocks_cadence " in node [ " out_edges" ] :
61- for edge in node [ " out_edges" ][ "unlocks_cadence " ]:
90+ # Item Consumption
91+ if "consumes " in out_edges :
92+ for edge in out_edges [ "consumes " ]:
6293 target_id = edge ["targetId" ]
63- if target_id in sig_nodes :
64- lines .append (f"{ nid } ==>|Unlocks| { target_id } " )
94+ qty = edge .get ("quantity" , 1 )
95+ # Link Item to the consumer
96+ lines .append (f"{ target_id } --x|Consumes { qty } | { nid } " )
97+
98+ # Containment (Optional, but useful for locations)
99+ if ntype == "Location" and "contains" in out_edges :
100+ for edge in out_edges ["contains" ]:
101+ target_id = edge ["targetId" ]
102+ # lines.append(f"{nid} -.->|Home of| {target_id}") # Usually too noisy
65103
66- # Output
67104 return "\n " .join (lines )
68105
69106if __name__ == "__main__" :
0 commit comments