11using System ;
2+ using System . Diagnostics . CodeAnalysis ;
23using System . Linq ;
34using Yafc . I18n ;
45using Yafc . Model ;
@@ -139,7 +140,7 @@ private void LoadTechnologyData(Technology technology, LuaTable table, bool forc
139140 recipeCategories . Add ( SpecialNames . Labs , technology ) ;
140141 }
141142 else if ( table . Get ( "research_trigger" , out LuaTable ? researchTriggerTable ) ) {
142- LoadResearchTrigger ( researchTriggerTable , ref technology , errorCollector ) ;
143+ LoadResearchTrigger ( researchTriggerTable , technology , errorCollector ) ;
143144 technology . ingredients ??= [ ] ;
144145 recipeCategories . Add ( SpecialNames . TechnologyTrigger , technology ) ;
145146 }
@@ -319,7 +320,7 @@ private Ingredient[] LoadResearchIngredientList(LuaTable table) {
319320 } ) . Where ( x => x is not null ) . ToArray ( ) ?? [ ] ;
320321 }
321322
322- private void LoadResearchTrigger ( LuaTable researchTriggerTable , ref Technology technology , ErrorCollector errorCollector ) {
323+ private void LoadResearchTrigger ( LuaTable researchTriggerTable , Technology technology , ErrorCollector errorCollector ) {
323324 if ( ! researchTriggerTable . Get ( "type" , out string ? type ) ) {
324325 errorCollector . Error ( $ "Research trigger of { technology . typeDotName } does not have a type field", ErrorSeverity . MinorDataLoss ) ;
325326 return ;
@@ -337,8 +338,8 @@ private void LoadResearchTrigger(LuaTable researchTriggerTable, ref Technology t
337338
338339 break ;
339340 case "craft-item" :
340- if ( ! researchTriggerTable . Get ( "item" , out string ? craftItemName ) ) {
341- errorCollector . Error ( $ "Research trigger { type } of { technology . typeDotName } does not have an item field", ErrorSeverity . MinorDataLoss ) ;
341+ if ( ! loadQualityFromFilter ( technology , researchTriggerTable , "item" , out string ? craftItemName ) ) {
342+ errorCollector . Error ( $ "Research trigger { type } of { technology . typeDotName } does not have a recognized item field", ErrorSeverity . MinorDataLoss ) ;
342343 break ;
343344 }
344345 craftCount = researchTriggerTable . Get ( "count" , 1 ) ;
@@ -368,13 +369,11 @@ private void LoadResearchTrigger(LuaTable researchTriggerTable, ref Technology t
368369 break ;
369370 case "build-entity" :
370371 technology . flags = RecipeFlags . HasResearchTriggerBuildEntity ;
371- if ( researchTriggerTable . Get ( "entity" , out entity )
372- || ( researchTriggerTable . Get ( "entity" , out LuaTable ? entityFilter ) && entityFilter . Get ( "name" , out entity ) ) ) {
373-
372+ if ( loadQualityFromFilter ( technology , researchTriggerTable , "entity" , out entity ) ) {
374373 technology . getTriggerEntities = new ( ( ) => [ ( ( Entity ) Database . objectsByTypeName [ "Entity." + entity ] ) ] ) ;
375374 }
376375 else {
377- errorCollector . Error ( $ "Research trigger { type } of { technology . typeDotName } does not have an entity field", ErrorSeverity . MinorDataLoss ) ;
376+ errorCollector . Error ( $ "Research trigger { type } of { technology . typeDotName } does not have a recognized entity field", ErrorSeverity . MinorDataLoss ) ;
378377 }
379378
380379 break ;
@@ -405,6 +404,38 @@ private void LoadResearchTrigger(LuaTable researchTriggerTable, ref Technology t
405404 errorCollector . Error ( LSs . ResearchHasAnUnsupportedTriggerType . L ( technology . typeDotName , type ) , ErrorSeverity . MinorDataLoss ) ;
406405 break ;
407406 }
407+
408+ bool loadQualityFromFilter ( Technology technology , LuaTable trigger , string key , [ NotNullWhen ( true ) ] out string ? objectName ) {
409+ if ( trigger . Get ( key , out objectName ) ) {
410+ // Basic string value
411+ return true ;
412+ }
413+
414+ if ( trigger . Get ( key , out LuaTable ? filter ) && filter . Get ( "name" , out objectName ) ) {
415+ // Load the quality specifiers from the table-based filter
416+ if ( ! registeredObjects . TryGetValue ( ( typeof ( Quality ) , filter . Get < string > ( "quality" ) ) , out var quality ) ) {
417+ return true ;
418+ }
419+
420+ switch ( filter . Get < string > ( "comparator" ) ) {
421+ // `≠ normal` is the same as `> normal`. `≠ anything-else` is the same as `= normal` for dependency analysis.
422+ case "!=" or "≠" when quality == Quality . Normal :
423+ case ">" :
424+ // This filter requires at least the quality after the specified quality.
425+ // I expect `> legendary` is a load error in Factorio, so treating it as "any quality" here should be fine.
426+ technology . triggerMinimumQuality = ( ( Quality ) quality ) . nextQuality ;
427+ break ;
428+ case ">=" or "≥" or "=" :
429+ technology . triggerMinimumQuality = ( Quality ) quality ;
430+ break ;
431+ default :
432+ // Nothing special: Normal quality is acceptable, no quality, or no comparator
433+ break ;
434+ }
435+ return true ;
436+ }
437+ return false ;
438+ }
408439 }
409440
410441 private void LoadRecipeData ( Recipe recipe , LuaTable table , bool forceDisable , ErrorCollector errorCollector ) {
0 commit comments