import { CREATION_ABILITIES , MORPH_ABILITIES } from "./creation_abilities" ; import UNITS_BY_ID from "./units_by_id" ; import UPGRADE_BY_ID from "./upgrade_by_id" ; import { ITrainedBy } from "./interfaces" ; import { sortBy , uniq , without , pull } from "lodash" ; import data from "./data.json" ; const TRAINED_BY = { } ; data . Unit . forEach ( ( trainingUnit ) => { trainingUnit . abilities . forEach ( ( ability ) => { const resultingUnitId = CREATION_ABILITIES [ ability . ability ] ; const resultingUnit = UNITS_BY_ID [ resultingUnitId ] ; if ( resultingUnit !== undefined ) { let requiredStructureId = null ; let requiredUpgradeId = null ; let requiresUnits = null ; const requires = [ ] ; let requiresTechlab = false ; const isMorph = MORPH_ABILITIES . has ( ability . ability ) ; if ( isMorph ) { const morphes = { Baneling : [ "Zergling" ] , Ravager : [ "Roach" ] , Overseer : [ "Overlord" ] , LurkerMP : [ "Hydralisk" ] , BroodLord : [ "Corruptor" ] , Archon : [ "HighTemplar" , "DarkTemplar" ] , } ; requiresUnits = morphes [ resultingUnit . name ] ; if ( morphes [ resultingUnit . name ] ) { requires . push ( ... morphes [ resultingUnit . name ] ) ; } } const isFreeMorph = resultingUnit . minerals === trainingUnit . minerals && resultingUnit . gas === trainingUnit . gas && resultingUnit . is_structure === trainingUnit . is_structure ; if ( isFreeMorph ) { return ; } const consumesUnit = resultingUnit . race === "Zerg" && resultingUnit . is_structure && ! trainingUnit . is_structure ; if ( Array . isArray ( ability . requirements ) ) { for ( const requirement of ability . requirements ) { if ( requirement . upgrade ) { requiredUpgradeId = requirement . upgrade ; } if ( requirement . building ) { requiredStructureId = requirement . building ; } if ( requirement . addon ) { requiresTechlab = true ; } } } const requiredStructure = requiredStructureId !== null ? UNITS_BY_ID [ requiredStructureId ] . name : null ; if ( requiredStructure ) { requires . push ( requiredStructure ) ; } const requiredUpgrade = requiredUpgradeId !== null ? UPGRADE_BY_ID [ requiredUpgradeId ] . name : null ; if ( requiredUpgrade ) { requires . push ( requiredUpgrade ) ; } if ( requiresTechlab ) { requires . push ( trainingUnit . name + "TechLab" ) ; } else { requires . push ( trainingUnit . name ) ; } if ( TRAINED_BY [ resultingUnit . name ] === undefined ) { TRAINED_BY [ resultingUnit . name ] = { trainedBy : new Set ( [ trainingUnit . name ] ) , requiresTechlab : requiresTechlab , requiresUnits : requiresUnits , requires : [ requires ] , isMorph : isMorph , consumesUnit : consumesUnit , requiredStructure : null , requiredUpgrade : null , } ; } else { TRAINED_BY [ resultingUnit . name ] . trainedBy . add ( trainingUnit . name ) ; TRAINED_BY [ resultingUnit . name ] . requires [ 0 ] . push ( ... requires ) ; } TRAINED_BY [ resultingUnit . name ] . requiredStructure = ! TRAINED_BY [ resultingUnit . name ] . requiredStructure ? requiredStructure : TRAINED_BY [ resultingUnit . name ] . requiredStructure ; TRAINED_BY [ resultingUnit . name ] . requiredUpgrade = ! TRAINED_BY [ resultingUnit . name ] . requiredUpgrade ? requiredUpgrade : TRAINED_BY [ resultingUnit . name ] . requiredUpgrade ; } } ) ; } ) ; for ( const itemName in TRAINED_BY ) { const trainInfo = TRAINED_BY [ itemName ] ; if ( trainInfo . requires [ 0 ] . indexOf ( "Gateway" ) >= 0 ) { const nonGatewayRequires = without ( trainInfo . requires [ 0 ] , "Gateway" , "WarpGate" ) ; trainInfo . requires = [ [ ... nonGatewayRequires , "Gateway" ] , [ "WarpGate" , ... nonGatewayRequires ] , ] ; } for ( const structureType of [ "Barracks" , "Factory" , "Starport" ] ) { pull ( trainInfo . requires [ 0 ] , structureType + "Flying" ) ; if ( trainInfo . requires [ 0 ] . indexOf ( structureType ) >= 0 && itemName . indexOf ( "Reactor" ) < 0 && itemName . indexOf ( "TechLab" ) < 0 ) { const nonBarracksRequires = without ( trainInfo . requires [ 0 ] , structureType ) ; trainInfo . requires = [ [ ... nonBarracksRequires , structureType ] , [ structureType + "Reactor" , ... nonBarracksRequires ] , [ structureType + "TechLab" , ... nonBarracksRequires ] , ] ; } } } TRAINED_BY [ "Mothership" ] . requires = [ [ "FleetBeacon" , "Nexus" ] ] ; TRAINED_BY [ "WarpGate" ] = { consumesUnit : false , isMorph : false , requiredStructure : "Pylon" , requiredUpgrade : null , requires : [ [ "WarpGateResearch" , "Gateway" ] ] , requiresTechlab : false , requiresUnits : null , trainedBy : new Set ( "Probe" ) , } ; TRAINED_BY [ "SCV" ] . requires = [ [ "CommandCenter" ] , [ "PlanetaryFortress" ] , [ "OrbitalCommand" ] ] ; TRAINED_BY [ "EngineeringBay" ] . requires = [ [ "CommandCenter" , "SCV" ] , [ "OrbitalCommand" , "SCV" ] , [ "PlanetaryFortress" , "SCV" ] , ] ; TRAINED_BY [ "Queen" ] . requires = [ [ "Hatchery" , "SpawningPool" ] , [ "Lair" , "SpawningPool" ] , [ "Hive" , "SpawningPool" ] , ] ; TRAINED_BY [ "SpawningPool" ] . requires = [ [ "Hatchery" , "Drone" ] , [ "Lair" , "Drone" ] , [ "Hive" , "Drone" ] , ] ; TRAINED_BY [ "EvolutionChamber" ] . requires = [ [ "Hatchery" , "Drone" ] , [ "Lair" , "Drone" ] , [ "Hive" , "Drone" ] , ] ; TRAINED_BY [ "LurkerDenMP" ] . requires = [ [ "HydraliskDen" , "Lair" , "Drone" ] , [ "HydraliskDen" , "Hive" , "Drone" ] , ] ; TRAINED_BY [ "HydraliskDen" ] . requires = [ [ "Lair" , "Drone" ] , [ "Hive" , "Drone" ] , ] ; TRAINED_BY [ "Spire" ] . requires = [ [ "Lair" , "Drone" ] , [ "Hive" , "Drone" ] , ] ; TRAINED_BY [ "InfestationPit" ] . requires = [ [ "Lair" , "Drone" ] , [ "Hive" , "Drone" ] , ] ; TRAINED_BY [ "Ravager" ] . requires = [ [ "Roach" , "RoachWarren" ] ] ; TRAINED_BY [ "Corruptor" ] . requires = [ [ "Spire" ] , [ "GreaterSpire" ] ] ; const requirementPriority = [ "Hive" , "GreaterSpire" , "Corruptor" , "Lair" ] ; for ( const itemName in TRAINED_BY ) { const trainInfo = TRAINED_BY [ itemName ] ; trainInfo . requires = trainInfo . requires . map ( ( requires ) => sortBy ( without ( uniq ( requires ) , "Larva" , "OverlordTransport" ) , ( name ) => - requirementPriority . indexOf ( name ) ) ) ; } /**
{Adept:
    requiredStructure: "CyberneticsCore",
    requiredUpgrade: null,
    requiresTechlab: false,
    trainedBy: { Gateway: 1, WarpGate: 1 }
    // E.g. when a hatch morphes to lair, is a morph
    isMorph: false
    // E.g. when a drone builds a spawning pool, it consumes the drone
    consumesUnit: false
}
 */ console . assert ( Object . keys ( TRAINED_BY ) . length === 116 , `${ Object . keys ( TRAINED_BY ) . length } is not 116` ) ; console . assert ( TRAINED_BY [ "Zergling" ] . requiredStructure === "SpawningPool" , `${ TRAINED_BY [ "Zergling" ] . requiredStructure }` ) ; export default TRAINED_BY ;