@@ -48,7 +48,18 @@ function renderQuestFlow() {
4848 abilities = nodesData . filter ( n => n . type === 'Ability' && cadenceProvidedAbilityIds . has ( n . id ) ) ;
4949 }
5050
51- const flowEntities = [ ...quests , ...cadences , ...abilities ] ;
51+ let refinements = [ ] ;
52+ if ( currentView === 'progressive' ) {
53+ const abilityIds = new Set ( abilities . map ( a => a . id ) ) ;
54+ refinements = nodesData . filter ( n =>
55+ n . type === 'Refinement' &&
56+ n . in_edges &&
57+ n . in_edges . requires_ability &&
58+ n . in_edges . requires_ability . some ( aId => abilityIds . has ( aId ) )
59+ ) ;
60+ }
61+
62+ const flowEntities = [ ...quests , ...cadences , ...abilities , ...refinements ] ;
5263 const entityMap = new Map ( flowEntities . map ( n => [ n . id , n ] ) ) ;
5364
5465 // 3. Build Dependency Graph for Layout (Base Progression)
@@ -91,6 +102,17 @@ function renderQuestFlow() {
91102 }
92103 } ) ;
93104 }
105+ // Refinement Dependencies (Ability -> Refinement)
106+ if ( q . type === 'Refinement' ) {
107+ if ( q . in_edges && q . in_edges . requires_ability ) {
108+ q . in_edges . requires_ability . forEach ( reqId => {
109+ if ( entityMap . has ( reqId ) ) {
110+ adj . get ( reqId ) . push ( q . id ) ;
111+ revAdj . get ( q . id ) . push ( reqId ) ;
112+ }
113+ } ) ;
114+ }
115+ }
94116 } ) ;
95117
96118 // 4. Calculate Tiers for Core Entities
@@ -111,32 +133,81 @@ function renderQuestFlow() {
111133 } ) ;
112134 }
113135
114- // 5. Add Non-Shared Item Nodes (Local to producing quest)
136+ // 5. Intelligence: Sustainability Propagation
137+ const sustainablyAvailable = new Map ( ) ;
138+ const sortedEntities = [ ...flowEntities ] . sort ( ( a , b ) => ( entityTiers . get ( a . id ) || 0 ) - ( entityTiers . get ( b . id ) || 0 ) ) ;
139+
140+ sortedEntities . forEach ( node => {
141+ node . sustainableOutputs = new Set ( ) ;
142+ node . availableSustainable = new Set ( ) ;
143+
144+ const parents = revAdj . get ( node . id ) || [ ] ;
145+ parents . forEach ( pId => {
146+ const pAvailable = sustainablyAvailable . get ( pId ) ;
147+ if ( pAvailable ) {
148+ pAvailable . forEach ( itemId => node . availableSustainable . add ( itemId ) ) ;
149+ }
150+ } ) ;
151+
152+ if ( node . type === 'Quest' && node . data . quest_type === 'Recurring' ) {
153+ if ( node . out_edges && node . out_edges . rewards ) {
154+ node . out_edges . rewards . forEach ( rew => node . sustainableOutputs . add ( rew . targetId ) ) ;
155+ }
156+ } else if ( node . type === 'Refinement' && currentView === 'progressive' ) {
157+ let canRun = true ;
158+ if ( node . out_edges && node . out_edges . consumes ) {
159+ node . out_edges . consumes . forEach ( cons => {
160+ if ( ! node . availableSustainable . has ( cons . targetId ) ) canRun = false ;
161+ } ) ;
162+ } else {
163+ canRun = false ; // Refinement without inputs?
164+ }
165+
166+ if ( canRun ) {
167+ node . isSustainablyActive = true ;
168+ if ( node . out_edges && node . out_edges . produces ) {
169+ node . out_edges . produces . forEach ( prod => node . sustainableOutputs . add ( prod . targetId ) ) ;
170+ }
171+ }
172+ }
173+
174+ const nodeTotalAvailable = new Set ( node . availableSustainable ) ;
175+ node . sustainableOutputs . forEach ( itemId => nodeTotalAvailable . add ( itemId ) ) ;
176+ sustainablyAvailable . set ( node . id , nodeTotalAvailable ) ;
177+ } ) ;
178+
179+ // 6. Add Non-Shared Item Nodes (Local to producing entity)
115180 const productionNodes = [ ] ;
116181 const productionEdges = [ ] ;
117182
118183 if ( currentView === 'advanced' || currentView === 'progressive' ) {
119- quests . forEach ( q => {
120- if ( q . data . quest_type === 'Recurring' && q . out_edges && q . out_edges . rewards ) {
121- const questTier = entityTiers . get ( q . id ) || 0 ;
122- q . out_edges . rewards . forEach ( rew => {
123- const itemTemplate = nodesData . find ( n => n . id === rew . targetId ) ;
184+ sortedEntities . forEach ( node => {
185+ if ( node . sustainableOutputs . size > 0 ) {
186+ const nodeTier = entityTiers . get ( node . id ) || 0 ;
187+ node . sustainableOutputs . forEach ( itemId => {
188+ const itemTemplate = nodesData . find ( n => n . id === itemId ) ;
124189 if ( itemTemplate ) {
125- const uniqueId = `prod-${ q . id } -${ itemTemplate . id } ` ;
126- const rate = ( rew . quantity * 60 ) / ( q . data . duration || 10 ) ;
190+ const uniqueId = `prod-${ node . id } -${ itemTemplate . id } ` ;
127191
192+ let rateInfo = "" ;
193+ if ( node . type === 'Quest' ) {
194+ const rew = node . out_edges . rewards . find ( r => r . targetId === itemId ) ;
195+ const rate = ( rew . quantity * 60 ) / ( node . data . duration || 10 ) ;
196+ rateInfo = ` (${ rate . toFixed ( 1 ) } /m)` ;
197+ }
198+
128199 const itemNode = {
129200 ...itemTemplate ,
130201 id : uniqueId ,
131- baseId : itemTemplate . id , // For selection/sidebar
132- name : `${ itemTemplate . name } ( ${ rate . toFixed ( 1 ) } /m) ` ,
133- tier : questTier + 1 ,
202+ baseId : itemTemplate . id ,
203+ name : `${ itemTemplate . name } ${ rateInfo } ` ,
204+ tier : nodeTier + 1 ,
134205 isProduction : true
135206 } ;
136207 productionNodes . push ( itemNode ) ;
137208 productionEdges . push ( {
138- id : `edge-${ q . id } -${ uniqueId } ` ,
139- source : q . id ,
209+ id : `edge-${ node . id } -${ uniqueId } ` ,
210+ source : node . id ,
140211 target : uniqueId ,
141212 category : 'economy'
142213 } ) ;
@@ -240,6 +311,16 @@ function renderQuestFlow() {
240311 shape = document . createElementNS ( "http://www.w3.org/2000/svg" , "polygon" ) ;
241312 shape . setAttribute ( 'points' , '0,-14 14,0 0,14 -14,0' ) ;
242313 shape . setAttribute ( 'fill' , 'var(--ability-color)' ) ;
314+ } else if ( node . type === 'Refinement' ) {
315+ shape = document . createElementNS ( "http://www.w3.org/2000/svg" , "rect" ) ;
316+ shape . setAttribute ( 'x' , '-12' ) ; shape . setAttribute ( 'y' , '-12' ) ;
317+ shape . setAttribute ( 'width' , '24' ) ; shape . setAttribute ( 'height' , '24' ) ;
318+ shape . setAttribute ( 'rx' , '8' ) ;
319+ shape . setAttribute ( 'fill' , node . isSustainablyActive ? 'var(--refinement-color)' : '#333' ) ;
320+ if ( ! node . isSustainablyActive && currentView === 'progressive' ) {
321+ shape . setAttribute ( 'stroke' , '#666' ) ;
322+ shape . setAttribute ( 'stroke-dasharray' , '2,2' ) ;
323+ }
243324 } else {
244325 shape = document . createElementNS ( "http://www.w3.org/2000/svg" , "polygon" ) ;
245326 shape . setAttribute ( 'points' , '-14,-7 -14,7 0,14 14,7 14,-7 0,-14' ) ;
0 commit comments