dooferorg

Civ6 AutoQueue_AddButton.lua

Oct 3rd, 2020 (edited)
385
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.05 KB | None | 0 0
  1. include("CitySupport");
  2. include("ProductionHelper");
  3. include("SupportFunctions"); --Split
  4.  
  5. -- When there aren't any more buildings to build, Cities will do a project
  6. local Idle_AddProject:boolean         = true;
  7. -- Once the first project has been added, nomore projects will be added to the queue, prevents all the other list entries from being picked
  8. local Idle_SingleProjectLimit:boolean = false;
  9.  
  10. -- Should we be able to repair buildings?
  11. local Repairs:boolean = true;
  12. -- Should Repairing be prioritize above the QueueList?
  13. local Repairs_Prioritize:boolean = true;
  14.  
  15. local SortedQueue_Buildings:table = {{}};
  16. -- Projects will be attempted to be added in the following order, projects not in the list will not be picked
  17. local SortedQueue_Projects:table = {{}};
  18.  
  19. local Debugging:boolean = false;
  20.  
  21. local CurrentCity:table;
  22.  
  23. function debugPrint(Message:string)
  24.     if (Debugging) then
  25.         print(Message);
  26.     end
  27. end
  28. function AddToTable(List)
  29.     local Result:table = {};
  30.  
  31.     for Item in List do
  32.         table.insert(Result, Item);
  33.     end
  34.  
  35.     return Result;
  36. end
  37. -- Copied and modified from ProductionPanel.lua
  38. function IsBuildQueueFull(City:table)
  39.     if City then
  40.         local BuildQueue = City:GetBuildQueue();
  41.  
  42.         if (BuildQueue ~= nil) then
  43.             local iQueueSize:number = BuildQueue:GetSize();
  44.  
  45.             if ((iQueueSize - 1) >= MAX_QUEUE_SIZE) then
  46.                 return true;
  47.             end
  48.         end
  49.     end
  50.  
  51.     return false;
  52. end
  53. function IsBuildQueueEmpty(City:table)
  54.     if City then
  55.         local BuildQueue = City:GetBuildQueue();
  56.  
  57.         if (BuildQueue ~= nil) then
  58.             local iQueueSize:number = BuildQueue:GetSize();
  59.  
  60.             if (iQueueSize > 0) then
  61.                 return false;
  62.             end
  63.         end
  64.     end
  65.  
  66.     return true;
  67. end
  68. function BuildBuilding(City:table, Building:table)
  69.     local tParameters = {};
  70.     tParameters[CityOperationTypes.PARAM_BUILDING_TYPE] = Building.Hash;  
  71.     tParameters[CityOperationTypes.PARAM_INSERT_MODE]   = CityOperationTypes.VALUE_APPEND;
  72.     CityManager.RequestOperation(City, CityOperationTypes.BUILD, tParameters);
  73. end
  74. function BuildProject(City:table, Project:table)
  75.     local tParameters = {};
  76.     tParameters[CityOperationTypes.PARAM_PROJECT_TYPE] = Project.Hash;
  77.     tParameters[CityOperationTypes.PARAM_INSERT_MODE]  = CityOperationTypes.VALUE_APPEND;
  78.     CityManager.RequestOperation(City, CityOperationTypes.BUILD, tParameters);
  79. end
  80. function BuildDistrict(City:table, District:table)
  81.     local tParameters = {};
  82.     tParameters[CityOperationTypes.PARAM_DISTRICT_TYPE] = District.Hash;  
  83.     tParameters[CityOperationTypes.PARAM_INSERT_MODE]   = CityOperationTypes.VALUE_APPEND;
  84.     CityManager.RequestOperation(City, CityOperationTypes.BUILD, tParameters);
  85. end
  86. function OnProductionPanelOpen()
  87.     CurrentCity = UI.GetHeadSelectedCity();
  88.  
  89.     if (CurrentCity == nil) then
  90.         return;
  91.     end
  92.  
  93.     local ProductionPanel:table = ContextPtr:LookUpControl("/InGame/ProductionPanel");
  94.     Controls.ButtonContainer:ChangeParent(ProductionPanel);
  95.     Controls.Button:RegisterCallback(Mouse.eLClick, ToggleActive);
  96.    
  97.     UpdateToggle();
  98.    
  99.     ContextPtr:SetHide(false);
  100. end
  101. function ExistsInTable(Source:table, Find:string)
  102.     for _, Value in ipairs(Source) do
  103.         if (Value == Find) then
  104.             return true;
  105.         end
  106.     end
  107.  
  108.     return false;
  109. end
  110. function CityExists(CityID:number)
  111.     for _, ID in ipairs(ExposedMembers.AutoQueue.Cities) do
  112.         if (ID == CityID) then
  113.             return true;
  114.         end
  115.     end
  116.  
  117.     return false;
  118. end
  119. function RemoveCity(CityID:number)
  120.     for Key, Value in pairs(ExposedMembers.AutoQueue.Cities) do
  121.         if (Value == CityID) then
  122.             table.remove(ExposedMembers.AutoQueue.Cities, Key);
  123.             ExposedMembers.AutoQueue.Save();
  124.             break;
  125.         end
  126.     end
  127. end
  128. function ToggleActive()
  129.     local CityID = CurrentCity:GetID();
  130.  
  131.     if CityExists(CityID) then
  132.         RemoveCity(CityID);
  133.     else
  134.         table.insert(ExposedMembers.AutoQueue.Cities, CityID);
  135.         ExposedMembers.AutoQueue.Save();
  136.         CheckCity(Game.GetLocalPlayer(), CityID);
  137.     end
  138.  
  139.     UpdateToggle();
  140. end
  141. function UpdateToggle()
  142.     local CityID = CurrentCity:GetID();
  143.  
  144.     if CityExists(CityID) then
  145.         Controls.ToggleLabel:SetText(Locale.Lookup("LOC_AUTOQUEUE_ON"));
  146.         Controls.ToggleLabel:SetColorByName("StatGoodCS");
  147.     else
  148.         Controls.ToggleLabel:SetText(Locale.Lookup("LOC_AUTOQUEUE_OFF"));
  149.         Controls.ToggleLabel:SetColorByName("White");
  150.     end
  151. end
  152. function GetQueueTypeNames(City:table)
  153.     local TypeNames:table  = {};
  154.     local BuildQueue:table = City:GetBuildQueue();
  155.  
  156.     -- The current Production is at 0, there are 8 Queue slot in total, 1 more than what's described in MAX_QUEUE_SIZE
  157.     for i = 0, (MAX_QUEUE_SIZE + 1) do
  158.         local Entry:table = BuildQueue:GetAt(i);
  159.  
  160.         if Entry then
  161.             local TypeName:string = nil;
  162.    
  163.             if (Entry.Directive == CityProductionDirectives.TRAIN) then
  164.                 TypeName = GameInfo.Units[Entry.UnitType].UnitType;
  165.  
  166.             elseif (Entry.Directive == CityProductionDirectives.CONSTRUCT) then
  167.                 TypeName = GameInfo.Buildings[Entry.BuildingType].BuildingType;
  168.  
  169.             elseif (Entry.Directive == CityProductionDirectives.ZONE) then
  170.                 TypeName = GameInfo.Districts[Entry.DistrictType].DistrictType;
  171.  
  172.             elseif (Entry.Directive == CityProductionDirectives.PROJECT) then
  173.                 TypeName = GameInfo.Projects[Entry.ProjectType].ProjectType;
  174.             end
  175.  
  176.             -- TypeName isn't Nil and the TypeName hasn't been added yet
  177.             if (TypeName and (not ExistsInTable(TypeNames, TypeName))) then
  178.                 table.insert(TypeNames, TypeName);
  179.             end
  180.         end
  181.     end
  182.  
  183.     return TypeNames;
  184. end
  185. function CheckRepairs(City:table)
  186.     if Repairs then
  187.         local CityDistricts:table   = City:GetDistricts();
  188.         local BuildQueue:table      = City:GetBuildQueue();
  189.         local QueuedTypeNames:table = GetQueueTypeNames(City);
  190.  
  191.         local Project:table = GameInfo.Projects["PROJECT_REPAIR_OUTER_DEFENSES"];
  192.         if (not IsBuildQueueFull(City)) then
  193.             if (not ExistsInTable(QueuedTypeNames, Project.ProjectType)) then
  194.                 table.insert(QueuedTypeNames, Project.ProjectType);
  195.                 BuildProject(City, Project);
  196.             end
  197.         end
  198.  
  199.         for i, District in CityDistricts:Members() do
  200.             local Plot:table = Map.GetPlot(District:GetX(), District:GetY());
  201.  
  202.             if CityDistricts:IsPillaged(District:GetType(), Plot) then
  203.                 local DistrictInfo:table = GameInfo.Districts[District:GetType()];
  204.  
  205.                 if (not IsBuildQueueFull(City)) then
  206.                     -- Don't add it if it exists in the Queue
  207.                     if (not ExistsInTable(QueuedTypeNames, District.DistrictType)) then
  208.                         table.insert(QueuedTypeNames, District.DistrictType);
  209.                         BuildDistrict(City, DistrictInfo);
  210.                     end
  211.                 else
  212.                     -- Build Queue is full, don't add more to it
  213.                     break;
  214.                 end
  215.             end
  216.         end
  217.  
  218.         local Buildings:table = City:GetBuildings();
  219.  
  220.         for Building in GameInfo.Buildings() do
  221.             if Buildings:HasBuilding(Building.Index) then
  222.                 if Buildings:IsPillaged(Building.BuildingType) then
  223.                     if (not IsBuildQueueFull(City)) then
  224.                         -- Don't add it if it exists in the Queue
  225.                         if (not ExistsInTable(QueuedTypeNames, Building.BuildingType)) then
  226.                             table.insert(QueuedTypeNames, Building.BuildingType);
  227.                             BuildBuilding(City, Building);
  228.                         end
  229.                     else
  230.                         -- Build Queue is full, don't add more to it
  231.                         break;
  232.                     end
  233.                 end
  234.             end
  235.         end
  236.     end
  237. end
  238. function CheckCity(PlayerID:number, CityID:number)
  239.     local City:table = CityManager.GetCity(PlayerID, CityID);
  240.  
  241.     if (City == nil) then
  242.         return;
  243.     end
  244.     if IsBuildQueueFull(City) then
  245.         -- Queue is full, do nothing
  246.         return;
  247.     end
  248.  
  249.     local BuildQueue:table           = City:GetBuildQueue();
  250.     local CanProduceAnything:boolean = false;
  251.     local Buildings:table            = City:GetBuildings();
  252.     local QueuedTypeNames:table      = GetQueueTypeNames(City);
  253.  
  254.     if Repairs_Prioritize then
  255.         CheckRepairs(City);
  256.     end
  257.  
  258.     debugPrint("CheckCity");
  259.     for _, Item in ipairs(ExposedMembers.AutoQueue.SortedQueue_Buildings) do
  260.         local Building:table = GameInfo.Buildings[Item.ObjectID];
  261.         local CanProduce     = BuildQueue:CanProduce(Building.Hash, true);
  262.  
  263.         if CanProduce then
  264.             CanProduceAnything = true;
  265.  
  266.             if (not IsBuildQueueFull(City)) then
  267.                 -- Don't add it if it exists in the Queue
  268.                 if (not ExistsInTable(QueuedTypeNames, Building.BuildingType)) then
  269.                     table.insert(QueuedTypeNames, Building.BuildingType);
  270.                     BuildBuilding(City, Building);
  271.                 end
  272.             else
  273.                 -- Build Queue is full, don't add more to it
  274.                 break;
  275.             end
  276.         end
  277.     end
  278.    
  279.     -- There is nothing queued right now, look for an available project
  280.     if (IsBuildQueueEmpty(City) and Idle_AddProject) then
  281.         debugPrint("Queue is empty");
  282.         local NoCurrentProject:boolean = true;
  283.  
  284.         if Idle_SingleProjectLimit then
  285.             for row in GameInfo.Projects() do
  286.                 if ExistsInTable(QueuedTypeNames, row.ProjectType) then
  287.                     -- There's already a Project running, do not add more
  288.                     NoCurrentProject = false;
  289.                     break;
  290.                 end
  291.             end
  292.         end
  293.  
  294.         if NoCurrentProject then
  295.             debugPrint("No current project");
  296.             for _, Item in ipairs(ExposedMembers.AutoQueue.SortedQueue_Projects) do
  297.                 local Project:table = GameInfo.Projects[Item.ObjectID];
  298.                 if (Project ~= nil) then
  299.                     local CanProduce = BuildQueue:CanProduce(Project.Hash, true);
  300.                    
  301.                     if CanProduce then
  302.                         debugPrint("Can product project");
  303.                         if (not IsBuildQueueFull(City)) then
  304.                             -- Don't add it if it exists in the Queue
  305.                             debugPrint("Build queue is not full");
  306.                             if (not ExistsInTable(QueuedTypeNames, Project.ProjectType)) then
  307.                                 debugPrint("Build the project");
  308.                                 table.insert(QueuedTypeNames, Project.ProjectType);
  309.                                 BuildProject(City, Project);
  310.                             end
  311.                             if Idle_SingleProjectLimit then
  312.                                 break;
  313.                             end
  314.                         else
  315.                             -- Build Queue is full, don't add more to it
  316.                             break;
  317.                         end
  318.                     end
  319.                 end
  320.             end
  321.         end
  322.     end
  323.  
  324.     CheckRepairs(City);
  325. end
  326. function OnCitySelectionChanged(PlayerID:number, CityID:number, i, j, k, isSelected:boolean, isEditable:boolean)
  327.     CurrentCity = UI.GetHeadSelectedCity();
  328.  
  329.     if (CurrentCity == nil) then
  330.         return;
  331.     end
  332.  
  333.     UpdateToggle();
  334. end
  335. function UpdateCities(PlayerID:number)
  336.     for Key, Value in pairs(ExposedMembers.AutoQueue.Cities) do
  337.         if (Value ~= nil) then
  338.             local City = CityManager.GetCity(PlayerID, Value);
  339.            
  340.             if (City ~= nil) then
  341.                 CheckCity(PlayerID, Value);
  342.             else
  343.                 -- City is either destroyed or captured by another player
  344.                 RemoveCity(Value);
  345.             end
  346.         end
  347.     end
  348. end
  349. function Save()
  350.     local PlayerConfig = PlayerConfigurations[Game.GetLocalPlayer()];
  351.  
  352.     if PlayerConfig then
  353.         -- SetValue only supports string values
  354.         PlayerConfig:SetValue("ExposedMembers_AutoQueue_Cities", Serialize(ExposedMembers.AutoQueue.Cities));
  355.     end
  356. end
  357. function OnLoadComplete(Result, Type, Options, FileType)
  358.     local PlayerConfig = PlayerConfigurations[Game.GetLocalPlayer()];
  359.     if PlayerConfig then
  360.         local Cities = Deserialize(PlayerConfig:GetValue("ExposedMembers_AutoQueue_Cities"));
  361.  
  362.         if Cities then
  363.             ExposedMembers.AutoQueue.Cities = Cities;
  364.         end
  365.     end
  366. end
  367. function Serialize(Input:table)
  368.     local Output:string = "";
  369.    
  370.     for Key, Value in ipairs(Input) do
  371.         Output = Output .. tostring(Value) .. ",";
  372.     end
  373.  
  374.     return Output;
  375. end
  376. function Deserialize(Input:string)
  377.     local Output:table = {};
  378.  
  379.     for Key, Value in ipairs(Split(Input, ",")) do
  380.         table.insert(Output, tonumber(Value));
  381.     end
  382.  
  383.     return Output;
  384. end
  385. function Initialize()  
  386.     if (not ExposedMembers.AutoQueue) then
  387.         ExposedMembers.AutoQueue = {};
  388.     end
  389.    
  390.     LuaEvents.ProductionPanel_Open.Add(OnProductionPanelOpen); 
  391.     Events.CitySelectionChanged.Add(OnCitySelectionChanged);
  392.     Events.LoadComplete.Add(OnLoadComplete);
  393.  
  394.     SortedQueue_Buildings = AddToTable(GameInfo.QueueOrder_Buildings());
  395.     table.sort(SortedQueue_Buildings, function(a, b) return (a.Priority < b.Priority); end);   
  396.     SortedQueue_Projects = AddToTable(GameInfo.QueueOrder_Projects());
  397.     table.sort(SortedQueue_Projects, function(a, b) return (a.Priority < b.Priority); end);
  398.     ExposedMembers.AutoQueue.SortedQueue_Buildings = SortedQueue_Buildings;
  399.     ExposedMembers.AutoQueue.SortedQueue_Projects  = SortedQueue_Projects;
  400.    
  401.     ExposedMembers.AutoQueue.Cities     = {};
  402.     ExposedMembers.AutoQueue.CheckCity  = CheckCity;
  403.     ExposedMembers.AutoQueue.CityExists = CityExists;
  404.     ExposedMembers.AutoQueue.RemoveCity = RemoveCity;
  405.     ExposedMembers.AutoQueue.Save       = Save;
  406. end
  407. Initialize();
  408.  
Add Comment
Please, Sign In to add comment