@@ -11,9 +11,34 @@ def load_graph():
1111def generate_mermaid ():
1212 nodes = load_graph ()
1313
14+ # 1. Map associations
15+ location_map = {} # QuestID -> LocationName
16+ cadence_map = {} # AbilityID -> CadenceName
17+
18+ for node in nodes :
19+ nid = node ["id" ]
20+ ntype = node ["type" ]
21+ out_edges = node .get ("out_edges" , {})
22+
23+ if ntype == "Location" :
24+ if "contains" in out_edges :
25+ for edge in out_edges ["contains" ]:
26+ location_map [edge ["targetId" ]] = node ["name" ]
27+
28+ if ntype == "Cadence" :
29+ for field in ["provides_ability" , "unlocks_ability" ]:
30+ if field in out_edges :
31+ for edge in out_edges [field ]:
32+ cadence_map [edge ["targetId" ]] = node ["name" ]
33+
34+ # 2. Group nodes
35+ by_location = {} # LocName -> [NodeLines]
36+ by_cadence = {} # CadName -> [NodeLines]
37+ globals = []
38+
1439 lines = ["graph TD" ]
1540
16- # Define styles with better contrast
41+ # Styles
1742 lines .append ("classDef quest fill:#4b0082,stroke:#f9f,stroke-width:2px,color:#fff;" )
1843 lines .append ("classDef location fill:#00008b,stroke:#ccf,stroke-width:2px,color:#fff;" )
1944 lines .append ("classDef cadence fill:#006400,stroke:#cfc,stroke-width:2px,color:#fff;" )
@@ -22,85 +47,84 @@ def generate_mermaid():
2247 lines .append ("classDef ability fill:#2f4f4f,stroke:#00ced1,stroke-width:1px,color:#fff;" )
2348 lines .append ("classDef root fill:#8b8b00,stroke:#ff9,stroke-width:4px,color:#fff;" )
2449
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"
50+ edge_lines = []
2851
2952 for node in nodes :
3053 nid = node ["id" ]
3154 ntype = node ["type" ]
3255 name = node ["name" ]
3356
34- # 1. Define Node
3557 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 } ' )
58+ if nid == "quest_prologue" : style = "root"
59+
60+ node_def = f'{ nid } ["{ name .replace ('"' , "'" )} "]:::{ style } '
61+
62+ # Assign to group
63+ if ntype == "Quest" and nid in location_map :
64+ loc = location_map [nid ]
65+ if loc not in by_location : by_location [loc ] = []
66+ by_location [loc ].append (node_def )
67+ elif ntype == "Ability" and nid in cadence_map :
68+ cad = cadence_map [nid ]
69+ if cad not in by_cadence : by_cadence [cad ] = []
70+ by_cadence [cad ].append (node_def )
71+ elif ntype == "Location" :
72+ # Locations themselves stay global or we could group them by region?
73+ # Let's keep them global to connect subgraphs
74+ globals .append (node_def )
75+ else :
76+ globals .append (node_def )
4277
43- # 2. In- Edges (Requirements)
78+ # Edges
4479 in_edges = node .get ("in_edges" , {})
80+ out_edges = node .get ("out_edges" , {})
4581
46- # Quest Requirements
4782 if "requires_quest" in in_edges :
4883 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 } " )
84+ label = "Enables" if ntype == "Location" else "Requires"
85+ edge_lines .append (f"{ req_id } -->|{ label } | { nid } " )
5486
55- # Ability Requirements (for Refinements usually)
5687 if "requires_ability" in in_edges :
5788 for req_id in in_edges ["requires_ability" ]:
58- lines .append (f"{ req_id } -.->|Allows| { nid } " )
89+ edge_lines .append (f"{ req_id } -.->|Allows| { nid } " )
5990
60- # Stat Requirements
6191 if "requires_stat" in in_edges :
6292 for stat_name , val in in_edges ["requires_stat" ].items ():
6393 stat_id = f"stat_{ stat_name .lower ()} "
64- lines .append (f"{ stat_id } -.->|Requires { val } | { nid } " )
94+ edge_lines .append (f"{ stat_id } -.->|Req { val } | { nid } " )
6595
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" ]:
96+ for unlock_type in ["unlocks_cadence" , "unlocks_ability" , "provides_ability" , "unlocks_location" ]:
7197 if unlock_type in out_edges :
7298 for edge in out_edges [unlock_type ]:
73- target_id = edge ["targetId" ]
74- 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 } " )
99+ edge_lines .append (f"{ nid } ==>|Unlocks| { edge ['targetId' ]} " )
81100
82- # Item Rewards / Production
83101 for reward_type in ["rewards" , "produces" , "rewards_item" ]:
84102 if reward_type in out_edges :
85103 for edge in out_edges [reward_type ]:
86- target_id = edge ["targetId" ]
87104 qty = edge .get ("quantity" , 1 )
88- lines .append (f"{ nid } --o|Gives { qty } | { target_id } " )
105+ edge_lines .append (f"{ nid } --o|Gives { qty } | { edge [ 'targetId' ] } " )
89106
90- # Item Consumption
91107 if "consumes" in out_edges :
92108 for edge in out_edges ["consumes" ]:
93- target_id = edge ["targetId" ]
94109 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
110+ edge_lines .append (f"{ edge ['targetId' ]} --x|Consumes { qty } | { nid } " )
103111
112+ # Build final output
113+ for node_def in globals :
114+ lines .append (node_def )
115+
116+ for loc , nodes_in_loc in by_location .items ():
117+ lines .append (f'subgraph "Location: { loc } "' )
118+ lines .extend (nodes_in_loc )
119+ lines .append ("end" )
120+
121+ for cad , nodes_in_cad in by_cadence .items ():
122+ lines .append (f'subgraph "Cadence: { cad } "' )
123+ lines .extend (nodes_in_cad )
124+ lines .append ("end" )
125+
126+ lines .extend (edge_lines )
127+
104128 return "\n " .join (lines )
105129
106130if __name__ == "__main__" :
0 commit comments