private static bool Prefix(UIDate __instance) { if (!Main.enabled) { return(true); } AutoHarvest.GetAllBooties(); ResourceMaintainer.TryBuyingResources(); ResourceMaintainer.UpdateResourceWarning(); TurnEvent.AddEvent(__instance); if (Main.settings.autoAssignBuildingWorkers) { HumanResource hr = new HumanResource(); int mainPartId = int.Parse(DateFile.instance.GetGangDate(16, 3)); int mainPlaceId = int.Parse(DateFile.instance.GetGangDate(16, 4)); hr.AssignBuildingWorkers(mainPartId, mainPlaceId); } return(true); }
/// <summary> /// 只要在各个 panel 创建完之后再创建 menu item,事件中的 panel 引用就都是有效的。 /// </summary> private void CreateMenuItems() { this.logsPanelButton = this.CreateMenuButton("LogsPanelButton", () => this.SwitchPanel(this.panelLogs), Path.Combine(Path.Combine(Main.resBasePath, "Texture"), $"ButtonIcon_Majordomo_LogsPanel.png"), "翻阅记录"); this.chartsPanelButton = this.CreateMenuButton("ChartsPanelButton", () => this.SwitchPanel(this.panelCharts), Path.Combine(Path.Combine(Main.resBasePath, "Texture"), $"ButtonIcon_Majordomo_ChartsPanel.png"), "查看图表"); this.assignBuildingWorkersButton = this.CreateMenuButton("AssignBuildingWorkersButton", () => { YesOrNoWindow.instance.SetYesOrNoWindow(-1, "太吾管家", "管家已重新指派了各个建筑的负责人。", canClose: false); HumanResource.AssignBuildingWorkersForTaiwuVillage(); this.panelLogs.SetPageIndex(-1); if (this.panelLogs.gameObject.activeInHierarchy) { this.panelLogs.Update(); } }, Path.Combine(Path.Combine(Main.resBasePath, "Texture"), $"ButtonIcon_Majordomo_AssignBuildingWorkers.png"), "重新指派工作"); }
/// <summary> /// 对于指定辅助厢房,生成候选人列表 /// </summary> /// <param name="bedroomIndex">厢房的建筑 ID</param> /// <param name="relatedBuildings">该厢房辅助的建筑信息列表</param> /// <returns></returns> private List <AuxiliaryBedroomWorker> GetAuxiliaryBedroomWorkers(int bedroomIndex, List <BuildingWorkInfo> relatedBuildings) { var workers = new List <AuxiliaryBedroomWorker>(); foreach (var entry in this.workerAttrs) { int workerId = entry.Key; if (this.excludedWorkers.Contains(workerId)) { continue; } var attrs = entry.Value; workers.Add(new AuxiliaryBedroomWorker { actorId = workerId, integratedAttrValue = HumanResource.GetIntegratedAttrValue(attrs, relatedBuildings), lackedMoodAndFavor = HumanResource.GetLackedMoodAndFavor(workerId), }); } return(workers); }
/// <summary> /// 计算指定地区的综合工作指数 /// /// 综合工作指数 = SUM(缩放平移过的建筑工作效率 * 建筑优先级) /// 厢房效率不计入统计 /// /// 由于必须在最开始执行,所以无法使用 prepared data /// </summary> /// <param name="partId"></param> /// <param name="placeId"></param> /// <returns></returns> private static float GetCompositeWorkIndex(int partId, int placeId) { float compositeWorkIndex = 0.0f; // 统计所有建筑的工作效率(厢房效率不计入统计) var buildings = DateFile.instance.homeBuildingsDate[partId][placeId]; foreach (int buildingIndex in buildings.Keys) { if (!Original.BuildingNeedsWorker(partId, placeId, buildingIndex)) { continue; } if (Bedroom.IsBedroom(partId, placeId, buildingIndex)) { continue; } if (DateFile.instance.actorsWorkingDate.ContainsKey(partId) && DateFile.instance.actorsWorkingDate[partId].ContainsKey(placeId) && DateFile.instance.actorsWorkingDate[partId][placeId].ContainsKey(buildingIndex)) { int workerId = DateFile.instance.actorsWorkingDate[partId][placeId][buildingIndex]; int workEffectiveness = Original.GetWorkEffectiveness(partId, placeId, buildingIndex, workerId); float scaledWorkEffectiveness = (workEffectiveness - 100f) / 100f; int priority = HumanResource.GetBuildingWorkingPriority(partId, placeId, buildingIndex); compositeWorkIndex += scaledWorkEffectiveness * priority; } } return(compositeWorkIndex); }
private void CreateMessagePageMenuControls() { this.assignBuildingWorkersButton = this.CreateMenuButton("AssignBuildingWorkersButton", () => { HumanResource.AssignBuildingWorkersForTaiwuVillage(); this.ShowMessage(showLastPage: true); }, Path.Combine(Path.Combine(Main.resBasePath, "Texture"), $"ButtonIcon_Majordomo_AssignBuildingWorkers.png"), TaiwuCommon.SetColor(TaiwuCommon.COLOR_WHITE, "重新指派工作")); }
/// <summary> /// 指派工作人员 /// </summary> public void AssignBuildingWorkers() { float compositeWorkIndex = HumanResource.GetCompositeWorkIndex(this.partId, this.placeId); MajordomoWindow.instance.AppendMessage(this.currDate, Message.IMPORTANCE_NORMAL, TaiwuCommon.SetColor(TaiwuCommon.COLOR_LIGHT_BLUE, "开始指派工作人员") + " - " + TaiwuCommon.SetColor(TaiwuCommon.COLOR_DARK_BROWN, "综合工作指数") + ": " + TaiwuCommon.SetColor(TaiwuCommon.COLOR_WHITE, compositeWorkIndex.ToString())); Original.RemoveWorkersFromBuildings(this.partId, this.placeId, this.excludedBuildings, this.excludedWorkers); MajordomoWindow.instance.AppendMessage(this.currDate, Message.IMPORTANCE_LOWEST, TaiwuCommon.SetColor(TaiwuCommon.COLOR_DARK_GRAY, "开始第一轮指派……")); this.AssignBuildingWorkers_PrepareData(); this.AssignBedroomWorkers(); MajordomoWindow.instance.AppendMessage(this.currDate, Message.IMPORTANCE_LOWEST, TaiwuCommon.SetColor(TaiwuCommon.COLOR_DARK_GRAY, "开始第二轮指派……")); // 指派完厢房后,重新计算 this.AssignBuildingWorkers_PrepareData(); this.AssignLeftBuildings(); Original.UpdateAllBuildings(this.partId, this.placeId); compositeWorkIndex = HumanResource.GetCompositeWorkIndex(this.partId, this.placeId); MajordomoWindow.instance.AppendMessage(this.currDate, Message.IMPORTANCE_NORMAL, TaiwuCommon.SetColor(TaiwuCommon.COLOR_LIGHT_BLUE, "结束指派工作人员") + " - " + TaiwuCommon.SetColor(TaiwuCommon.COLOR_DARK_BROWN, "综合工作指数") + ": " + TaiwuCommon.SetColor(TaiwuCommon.COLOR_WHITE, compositeWorkIndex.ToString())); MajordomoWindow.instance.SetCompositeWorkIndex(this.currDate, compositeWorkIndex); }
/// <summary> /// 为太吾村指派工作人员(静态方法) /// </summary> public static void AssignBuildingWorkersForTaiwuVillage() { int mainPartId = int.Parse(DateFile.instance.GetGangDate(16, 3)); int mainPlaceId = int.Parse(DateFile.instance.GetGangDate(16, 4)); HumanResource hr = new HumanResource(mainPartId, mainPlaceId); hr.AssignBuildingWorkers(); }
/// <summary> /// 获取当前据点需要工作人员的建筑,以及该建筑的工作相关信息 /// </summary> /// <returns></returns> private Dictionary <int, List <BuildingWorkInfo> > GetBuildingsNeedWorker() { // requiredAttrId -> [BuildingWorkInfo, ] var attrBuildings = new Dictionary <int, List <BuildingWorkInfo> >(); var buildings = DateFile.instance.homeBuildingsDate[this.partId][this.placeId]; var validBuildings = buildings.Where(entry => !this.excludedBuildings.Contains(entry.Key)); foreach (var entry in validBuildings) { int buildingIndex = entry.Key; int[] building = entry.Value; int baseBuildingId = building[0]; var baseBuilding = DateFile.instance.basehomePlaceDate[baseBuildingId]; bool needWorker = int.Parse(baseBuilding[3]) == 1; if (!needWorker) { continue; } int requiredAttrId = int.Parse(baseBuilding[33]); BuildingWorkInfo info = new BuildingWorkInfo { buildingIndex = buildingIndex, requiredAttrId = requiredAttrId, priority = HumanResource.GetBuildingWorkingPriority(this.partId, this.placeId, buildingIndex), halfWorkingAttrValue = 0, fullWorkingAttrValue = 0, }; if (requiredAttrId != 0) { int[] requiredAttrValues = Original.GetRequiredAttributeValues(this.partId, this.placeId, buildingIndex); info.halfWorkingAttrValue = requiredAttrValues[0]; info.fullWorkingAttrValue = requiredAttrValues[1]; } if (!attrBuildings.ContainsKey(requiredAttrId)) { attrBuildings[requiredAttrId] = new List <BuildingWorkInfo>(); } attrBuildings[requiredAttrId].Add(info); } return(attrBuildings); }
private void AssignBuildingWorkers_PrepareData() { List <int> workerIds = Original.GetWorkerIds(this.partId, this.placeId); workerIds = workerIds.Where(workerId => !this.excludedWorkers.Contains(workerId)).ToList(); Dictionary <int, List <BuildingWorkInfo> > attrBuildings = this.GetBuildingsNeedWorker(); // this.buildings = new Dictionary <int, BuildingWorkInfo>(); foreach (var currBuildingWorkInfos in attrBuildings.Values) { foreach (var info in currBuildingWorkInfos) { this.buildings[info.buildingIndex] = info; } } // this.workerAttrs = new Dictionary <int, Dictionary <int, int> >(); this.attrCandidates = new Dictionary <int, List <int> >(); foreach (int workerId in workerIds) { this.workerAttrs[workerId] = new Dictionary <int, int>(); } foreach (int requiredAttrId in attrBuildings.Keys) { foreach (int workerId in workerIds) { // 不需要资质时(厢房),放入好感和心情相对标准状态的差值 int attrValue = requiredAttrId != 0 ? int.Parse(DateFile.instance.GetActorDate(workerId, requiredAttrId)) : HumanResource.GetLackedMoodAndFavor(workerId); this.workerAttrs[workerId][requiredAttrId] = attrValue; } List <int> sortedWorkerIds = this.workerAttrs .OrderByDescending(elem => elem.Value[requiredAttrId]) .Select(elem => elem.Key) .ToList(); this.attrCandidates[requiredAttrId] = sortedWorkerIds; } }
/// <summary> /// 返回建筑指派工作人员的优先级 /// /// 优先级 = 建筑种类因子 * 标准状态下满效率需求的标准化能力值 /// 对于厢房,“标准状态下满效率需求的标准化能力值” 即为其等级 /// 虽然这会导致方向的优先级和其他建筑没有可比性,但是厢房优先级本来就不会与其他建筑比较,所以没有问题 /// </summary> /// <param name="partId"></param> /// <param name="placeId"></param> /// <param name="buildingIndex"></param> /// <param name="withAdjacentBedrooms">是否考虑邻接厢房的影响</param> /// <returns></returns> private static float GetBuildingWorkingPriority(int partId, int placeId, int buildingIndex, bool withAdjacentBedrooms) { int[] requiredAttrValues = Original.GetRequiredAttributeValues(partId, placeId, buildingIndex, withAdjacentBedrooms, getStandardAttrValue: true); int fullWorkingAttrValue = requiredAttrValues[1]; // 对于厢房,“标准状态下满效率需求的标准化能力值” 即为其等级 int[] building = DateFile.instance.homeBuildingsDate[partId][placeId][buildingIndex]; int baseBuildingId = building[0]; int buildingLevel = building[1]; int requiredAttrId = int.Parse(DateFile.instance.basehomePlaceDate[baseBuildingId][33]); if (requiredAttrId <= 0) { fullWorkingAttrValue = buildingLevel; } float typeFactor = HumanResource.GetBuildingPriorityFactor(baseBuildingId); return(typeFactor * fullWorkingAttrValue); }
/// <summary> /// 计算指定地区的工作统计信息 /// /// 综合工作指数 = SUM(缩放平移过的建筑工作效率 * 建筑优先级) /// 厢房效率不计入统计 /// /// 由于必须在最开始执行,所以无法使用 prepared data /// </summary> /// <param name="partId"></param> /// <param name="placeId"></param> /// <returns></returns> private static WorkingStats GetWorkingStats(int partId, int placeId) { var stats = new WorkingStats(); // 统计所有建筑的工作效率(厢房效率不计入统计) var buildings = DateFile.instance.homeBuildingsDate[partId][placeId]; foreach (int buildingIndex in buildings.Keys) { if (!Original.BuildingNeedsWorker(partId, placeId, buildingIndex)) { continue; } if (Bedroom.IsBedroom(partId, placeId, buildingIndex)) { continue; } if (DateFile.instance.actorsWorkingDate.ContainsKey(partId) && DateFile.instance.actorsWorkingDate[partId].ContainsKey(placeId) && DateFile.instance.actorsWorkingDate[partId][placeId].ContainsKey(buildingIndex)) { int workerId = DateFile.instance.actorsWorkingDate[partId][placeId][buildingIndex]; int workEffectiveness = Original.GetWorkEffectiveness(partId, placeId, buildingIndex, workerId); float scaledWorkEffectiveness = (workEffectiveness - 100f) / 100f; float priority = HumanResource.GetBuildingWorkingPriority(partId, placeId, buildingIndex, withAdjacentBedrooms: false); ++stats.nProductiveBuildings; stats.avgWorkEffectiveness += workEffectiveness / 200f; stats.compositeWorkIndex += scaledWorkEffectiveness * priority; } } if (stats.nProductiveBuildings > 0) { stats.avgWorkEffectiveness /= stats.nProductiveBuildings; } return(stats); }
private static bool Prefix(UIDate __instance) { if (!Main.enabled) { return(true); } AutoHarvest.GetAllBooties(); ResourceMaintainer.TryBuyingResources(); ResourceMaintainer.UpdateResourceWarning(); TurnEvent.AddEvent(__instance); if (Main.settings.autoAssignBuildingWorkers) { HumanResource.AssignBuildingWorkersForTaiwuVillage(); } return(true); }
/// <summary> /// 自动指派工作人员 /// </summary> public void AssignBuildingWorkers() { Main.Logger.Log($"自动指派前综合工作指数: {HumanResource.GetComprehensiveWorkIndex(this.partId, this.placeId)}"); Original.RemoveWorkersFromBuildings(this.partId, this.placeId, this.excludedBuildings, this.excludedWorkers); Main.Logger.Log("开始第一轮指派……"); this.AssignBuildingWorkers_PrepareData(); this.AssignBedroomWorkers(); Main.Logger.Log("开始第二轮指派……"); // 指派完厢房后,重新计算 this.AssignBuildingWorkers_PrepareData(); this.AssignLeftBuildings(); Original.UpdateAllBuildings(this.partId, this.placeId); Main.Logger.Log($"自动指派后综合工作指数: {HumanResource.GetComprehensiveWorkIndex(this.partId, this.placeId)}"); }