private static bool CheckInfoCompatibility(Vector3 pos, ItemClass.Service service, ItemClass.SubService subService, TransferManager.TransferReason[] allowedTypes, Building.Flags flagsRequired, Building.Flags flagsForbidden, BuildingManager bm, ref ushort result, ref float lastNearest, ushort buildingId, BuildingInfo info) { //doErrorLog($"CheckInfoCompatibility 0 {pos}, {service}, {subService}, {allowedTypes}, {flagsRequired}, {flagsForbidden}, {bm}, {result}, {lastNearest}, {buildingId}, {info}"); if (info != null && (info.m_class.m_service == service || service == ItemClass.Service.None) && (info.m_class.m_subService == subService || subService == ItemClass.SubService.None)) { //doErrorLog("CheckInfoCompatibility 1"); Building.Flags flags = bm.m_buildings.m_buffer[buildingId].m_flags; //doErrorLog("CheckInfoCompatibility 2"); if ((flags & (flagsRequired | flagsForbidden)) == flagsRequired) { //doErrorLog("CheckInfoCompatibility 3"); if (allowedTypes == null || allowedTypes.Length == 0 || !(info.GetAI() is DepotAI depotAI) || (depotAI.m_transportInfo != null && allowedTypes.Contains(depotAI.m_transportInfo.m_vehicleReason)) || (depotAI.m_secondaryTransportInfo != null && allowedTypes.Contains(depotAI.m_secondaryTransportInfo.m_vehicleReason))) { //doErrorLog("CheckInfoCompatibility 4"); float dist = Vector3.SqrMagnitude(pos - bm.m_buildings.m_buffer[buildingId].m_position); //doErrorLog("CheckInfoCompatibility 5"); if (dist < lastNearest) { result = buildingId; lastNearest = dist; return(true); } } } } return(false); }
public void closeDepotInfo(UIComponent component, UIMouseEventParameter eventParam) { BuildingInfo basicInfo = Singleton <BuildingManager> .instance.m_buildings.m_buffer[m_buildingIdSelecionado.Building].Info; DepotAI basicAI = basicInfo.GetAI() as DepotAI; Hide(); TLMPublicTransportManagementPanel.instance?.OpenAt(UiCategoryTab.DepotListing, TransportSystemDefinition.from(basicAI)); }
public void closeDepotInfo(UIComponent component, UIMouseEventParameter eventParam) { BuildingInfo basicInfo = Singleton <BuildingManager> .instance.m_buildings.m_buffer[m_buildingIdSelecionado.Building].Info; DepotAI basicAI = basicInfo.GetAI() as DepotAI; Hide(); m_controller.defaultListingLinesPanel.Show(); TLMPublicTransportDetailPanel.instance.SetActiveTab(TLMPublicTransportDetailPanel.tabSystemOrder.Length + Array.IndexOf(TLMPublicTransportDetailPanel.tabSystemOrder, TLMCW.getConfigIndexForTransportInfo(basicAI.m_transportInfo))); }
public static IBasicBuildingAIOverrides getBuildingOverrideExtension(BuildingInfo info) { PrefabAI targetAi = info.GetAI(); Type targetTypeAi = targetAi.GetType(); if (subtypes == null) { subtypes = new Dictionary <Type, Type>(); var subclasses = SVMUtils.GetSubtypesRecursive(typeof(BasicBuildingAIOverrides <,>), typeof(SVMBuildingAIOverrideUtils)); SVMUtils.doLog("GetOverride pré - subclasses:\r\n\t{0}", string.Join("\r\n\t", subclasses?.Select(x => x.ToString())?.ToArray() ?? new string[0])); foreach (Type t in subclasses) { try { subtypes[t.BaseType.GetGenericArguments()[1]] = t; } catch (Exception e) { SVMUtils.doErrorLog("ERROR ADDING SUBTYPE {0}!\r\n{1}", t, subclasses); } } SVMUtils.doLog("GetOverride - Classes:\r\n\t{0}", string.Join("\r\n\t", subtypes?.Select(x => x.Key.ToString() + "=>" + x.Value.ToString())?.ToArray() ?? new string[0])); } Type targetClass = null; IBasicBuildingAIOverrides value = null; if (!subtypes.ContainsKey(targetTypeAi)) { foreach (var clazz in subtypes.Keys) { if (clazz.IsAssignableFrom(targetTypeAi)) { value = (IBasicBuildingAIOverrides)SVMUtils.GetPrivateStaticField("instance", subtypes[clazz]); //SVMUtils.doLog("GetOverride - clazz = {0}; value = {1}", clazz, value); if (value.AcceptsAI(targetAi)) { targetClass = subtypes[clazz]; break; } } } SVMUtils.doLog("GetOverride - targetClass = {0} ({1})", targetClass, targetTypeAi); if (targetClass == null) { return(null); } } else { targetClass = subtypes[targetTypeAi]; value = (IBasicBuildingAIOverrides)SVMUtils.GetPrivateStaticField("instance", targetClass); } //SVMUtils.doLog("GetOverride - value = {0}", value); return((IBasicBuildingAIOverrides)value); }
/// <summary> /// Harmony Postfix patch to ZonedBuildingWorldInfoPanel.UpdateBindings to display visitor counts for commercial buildings. /// </summary> public static void Postfix() { // Currently selected building. ushort building = WorldInfoPanel.GetCurrentInstanceID().Building; // Create visit label if it isn't already set up. if (visitLabel == null) { // Get info panel. ZonedBuildingWorldInfoPanel infoPanel = UIView.library.Get <ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); // Add current visitor count label. visitLabel = UIControls.AddLabel(infoPanel.component, 65f, 280f, Translations.Translate("RPR_INF_VIS"), textScale: 0.75f); visitLabel.textColor = new Color32(185, 221, 254, 255); visitLabel.font = Resources.FindObjectsOfTypeAll <UIFont>().FirstOrDefault((UIFont f) => f.name == "OpenSans-Regular"); // Position under existing Highly Educated workers count row in line with total workplace count label. UIComponent situationLabel = infoPanel.Find("WorkSituation"); UIComponent workerLabel = infoPanel.Find("HighlyEducatedWorkers"); if (situationLabel != null && workerLabel != null) { visitLabel.absolutePosition = new Vector2(situationLabel.absolutePosition.x, workerLabel.absolutePosition.y + 25f); } else { Logging.Error("couldn't find ZonedBuildingWorldInfoPanel components"); } } // Local references. Building[] buildingBuffer = Singleton <BuildingManager> .instance.m_buildings.m_buffer; BuildingInfo buildingInfo = buildingBuffer[building].Info; // Is this a commercial building? CommercialBuildingAI commercialAI = buildingInfo.GetAI() as CommercialBuildingAI; if (commercialAI == null) { // Not a commercial building - hide the label. visitLabel.Hide(); } else { // Commercial building - show the label. visitLabel.Show(); // Get current visitor count. int aliveCount = 0, totalCount = 0; Citizen.BehaviourData behaviour = new Citizen.BehaviourData(); GetVisitBehaviour(commercialAI, building, ref buildingBuffer[building], ref behaviour, ref aliveCount, ref totalCount); // Display visitor count. visitLabel.text = totalCount.ToString() + " / " + commercialAI.CalculateVisitplaceCount((ItemClass.Level)buildingBuffer[building].m_level, new ColossalFramework.Math.Randomizer(building), buildingBuffer[building].Width, buildingBuffer[building].Length).ToString() + " " + Translations.Translate("RPR_INF_VIS"); } }
/// <summary> /// Updates all school prefabs (e.g. when the global multiplier has changed). /// </summary> internal void UpdateSchools() { // Iterate through all loaded building prefabs. for (uint i = 0; i < PrefabCollection <BuildingInfo> .LoadedCount(); ++i) { BuildingInfo building = PrefabCollection <BuildingInfo> .GetLoaded(i); // Check for schools. if (building?.name != null && building.GetAI() is SchoolAI schoolAI && (building.GetClassLevel() == ItemClass.Level.Level1 || building.GetClassLevel() == ItemClass.Level.Level2)) { // Found a school; update school record and tooltip. UpdateSchoolPrefab(building, schoolAI); } } }
public bool isFromSystem(BuildingInfo info) { if (ServiceVehiclesManagerMod.debugMode) { SVMUtils.doLog($"[{info?.GetAI()?.GetType()}->{this}]" + $" info.m_class.m_service == service = { info?.m_class?.m_service == service};" + $" subService == info.m_class.m_subService = { subService == info?.m_class?.m_subService };" + $" info?.GetAI() is OutsideConnectionAI == outsideConnection = {info?.GetAI() is OutsideConnectionAI == outsideConnection };" + $" info.m_class.m_level == level = {info?.m_class?.m_level} == {level} = {info?.m_class?.m_level == level};" + $" SVMBuildingAIOverrideUtils.getBuildingOverrideExtension(info).Count = {SVMBuildingAIOverrideUtils.getBuildingOverrideExtension(info)?.Count};" + $" ExtraAllowedLevels = [{String.Join(",", SVMBuildingAIOverrideUtils.getBuildingOverrideExtension(info).SelectMany(x => x?.ExtraAllowedLevels() ?? new List<ItemClass.Level>()).Select(x => x.ToString() ?? "<NULL>")?.ToArray())}];" + $" instance?.vehicleType ({this?.vehicleType}) ;" + $" aiOverride?.AllowVehicleType(vehicleType) = {this?.vehicleType}) ;" + $" SVMBuildingAIOverrideUtils.getBuildingOverrideExtension(info).Where = {ListAiOverrides(info).Count()} "); } return(ListAiOverrides(info).Count() > 0); }
/// <summary> /// Harmony Postfix patch to skip 'gradual construction' for plopped RICO growables, and/or to apply the 'Make Historical' and/or 'Lock level' settings on building creation, accoriding to settings. /// </summary> /// <param name="__result">Original method result (unchanged)</param> /// <param name="info">BuildingInfo prefab for this building (unchanged)</param> /// <param name="position">Building position (ignored)</param> /// <param name="angle">Building rotation (ignored)</param> /// <param name="relocating">Building relocation (ignored)</param> /// <param name="needMoney">Is money needed (ignored)</param> /// <param name="fixedHeight">Fixed height (ignored)</param> internal static void Postfix(ref ushort __result, ref BuildingInfo info, Vector3 position, float angle, int relocating, bool needMoney, bool fixedHeight) { // Check that we have a valid building ID. if (__result == 0) { return; } // Get building AI. PrivateBuildingAI buildingAI = info.GetAI() as PrivateBuildingAI; // Only interested in private building AI. if (buildingAI != null) { // Check if AI is a RICO custom AI type. bool isRICO = RICOUtils.IsRICOAI(buildingAI); // Check if it's a RICO custom AI type. // Enable 'ploppable growables' if option is set. if ((ModSettings.plopOther && !isRICO) || (ModSettings.plopRico && isRICO)) { // Check to see if construction time is greater than zero. if (buildingAI.m_constructionTime > 0) { Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result].m_frame0.m_constructState = byte.MaxValue; BuildingCompletedRev(buildingAI, __result, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result]); // Have to do this manually as CommonBuildingAI.BuildingCompleted won't if construction time isn't zero. Singleton <BuildingManager> .instance.UpdateBuildingRenderer(__result, updateGroup : true); } } // Enable 'Make Historical' if option is set. if ((ModSettings.historicalOther && !isRICO) || (ModSettings.historicalRico && isRICO)) { info.m_buildingAI.SetHistorical(__result, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result], historical: true); } // Enable ABLC level lock if option is set and ABLC is running. if (ModUtils.ablcLockBuildingLevel != null && ((ModSettings.lockLevelOther && !isRICO) || (ModSettings.lockLevelRico && isRICO))) { ModUtils.ablcLockBuildingLevel.Invoke(null, new object[] { __result, Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result].m_level }); } } }
/// <summary> /// Returns the workplace breakdowns and visitor count for the given building prefab and level. /// </summary> /// <param name="buildingPrefab">Building prefab record</param> /// <param name="level">Building level</param> /// <returns>Workplace breakdowns and visitor count </returns> public override int[] Workplaces(BuildingInfo buildingPrefab, int level) { int[] array; int minWorkers; // Need to test if we're an extractor or not for this one. if (buildingPrefab.GetAI() is IndustrialExtractorAI) { array = LegacyAIUtils.GetExtractorArray(buildingPrefab); minWorkers = 3; } else { array = LegacyAIUtils.GetIndustryArray(buildingPrefab, level); minWorkers = 4; } LegacyAIUtils.CalculateprefabWorkerVisit(buildingPrefab.GetWidth(), buildingPrefab.GetLength(), ref buildingPrefab, minWorkers, ref array, out int[] output); return(output); }
/// <summary> /// Applies a school data pack to a school prefab. /// </summary> /// <param name="prefab">School prefab to apply to</param> /// <param name="schoolPack">School data pack to apply</param> private void ApplyPack(BuildingInfo prefab, SchoolDataPack schoolPack) { // Null checks first. if (prefab?.name == null) { Logging.Error("No prefab found for SchoolPack ", schoolPack.name); return; } if (schoolPack == null) { Logging.Error("No SchoolPack found for prefab ", prefab.name); } // Apply settings to prefab. SchoolAI schoolAI = prefab.GetAI() as SchoolAI; if (prefab != null && schoolPack != null) { // Calculate workers and breakdowns. int[] workers = CalcWorkers(schoolPack, schoolAI.StudentCount); // Update prefab AI worker count with results (base + extras) per education level. schoolAI.m_workPlaceCount0 = workers[0]; schoolAI.m_workPlaceCount1 = workers[1]; schoolAI.m_workPlaceCount2 = workers[2]; schoolAI.m_workPlaceCount3 = workers[3]; // Calculate and update costs and maintenance. schoolAI.m_constructionCost = CalcCost(schoolPack, schoolAI.StudentCount); schoolAI.m_maintenanceCost = CalcMaint(schoolPack, schoolAI.StudentCount); // Force update of m_studentCount. schoolAI.m_studentCount = schoolAI.StudentCount; // Update prefab and tooltip. UpdateSchoolPrefab(prefab, schoolAI); } }
/// <summary> /// Performs task on completion of level loading - recording of school default properties and application of our settings. /// Should be called OnLevelLoaded, after prefabs have been loaded but before gameplay commences. /// </summary> internal void OnLoad() { // Initialise original properties dictionary. originalStats = new Dictionary <string, OriginalSchoolStats>(); // Iterate through all loaded building prefabs. for (uint i = 0; i < PrefabCollection <BuildingInfo> .LoadedCount(); ++i) { BuildingInfo building = PrefabCollection <BuildingInfo> .GetLoaded(i); // Check for schools. if (building?.name != null && building.GetAI() is SchoolAI schoolAI && (building.GetClassLevel() == ItemClass.Level.Level1 || building.GetClassLevel() == ItemClass.Level.Level2)) { // Found a school; add it to our dictionary. originalStats.Add(building.name, new OriginalSchoolStats { jobs0 = schoolAI.m_workPlaceCount0, jobs1 = schoolAI.m_workPlaceCount1, jobs2 = schoolAI.m_workPlaceCount2, jobs3 = schoolAI.m_workPlaceCount3, cost = schoolAI.m_constructionCost, maintenance = schoolAI.m_maintenanceCost }); // If setting is set, get currently active pack and apply it. if (ModSettings.enableSchoolProperties) { ApplyPack(building, ActivePack(building) as SchoolDataPack); // ApplyPack includes a call to UpdateSchoolPrefab, so no need to do it again here. continue; } // Update school record and tooltip. UpdateSchoolPrefab(building, schoolAI); } } }
internal IEnumerator <object> UpdateDo() { yield return(new WaitForSeconds(0.05f)); ActionStatus.text = ActionQueue.instance.current == null ? "" : $"{ActionQueue.instance.current.GetType()}"; ToolStatus.text = $"{MoveItTool.ToolState} ({MoveItTool.MT_Tool}.{MoveItTool.AlignToolPhase}), POProc:{MoveItTool.POProcessing}"; SelectedLarge.text = $"Objects Selected: {Action.selection.Count}"; ushort[] types = new ushort[8]; foreach (Instance instance in Action.selection) { if (instance is MoveableBuilding) { types[0]++; } else if (instance is MoveableProp) { PropInfo info = (PropInfo)PropLayer.Manager.GetInfo(instance.id).Prefab; if (info.m_isDecal) { types[2]++; } else if (Filters.IsSurface(info)) { types[3]++; } else { types[1]++; } } else if (instance is MoveableTree) { types[4]++; } else if (instance is MoveableProc) { types[5]++; } else if (instance is MoveableNode) { types[6]++; } else if (instance is MoveableSegment) { types[7]++; } else { throw new Exception($"Instance is invalid type (<{instance.GetType()}>)"); } } SelectedSmall.text = $"B:{types[0]}, P:{types[1]}, D:{types[2]}, S:{types[3]}, T:{types[4]}, PO:{types[5]}, N:{types[6]}, S:{types[7]}\n "; // End with updating the hovered item if (id == null) { yield break; } if (id == InstanceID.Empty) { lastId = id; HoverLarge.textColor = new Color32(255, 255, 255, 255); yield break; } if (lastId == id) { yield break; } HoverLarge.textColor = new Color32(127, 217, 255, 255); HoverLarge.text = ""; HoverSmall.text = ""; if (id.Building > 0) { BuildingInfo info = BuildingManager.instance.m_buildings.m_buffer[id.Building].Info; HoverLarge.text = $"B:{id.Building} {info.name}"; HoverLarge.tooltip = info.name; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}\n({info.m_class.m_service}.{info.m_class.m_subService})"; } else if (id.Prop > 0) { string type = "P"; PropInfo info = (PropInfo)PropLayer.Manager.GetInfo(id).Prefab; if (info.m_isDecal) { type = "D"; } HoverLarge.text = $"{type}:{PropLayer.Manager.GetId(id)} {info.name}"; HoverLarge.tooltip = info.name; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; } else if (id.NetLane > 0) { IInfo info = MoveItTool.PO.GetProcObj(id.NetLane).Info; HoverLarge.text = $"PO:{id.NetLane} {info.Name}"; HoverLarge.tooltip = info.Name; HoverSmall.text = $"\n"; } else if (id.Tree > 0) { TreeInfo info = TreeManager.instance.m_trees.m_buffer[id.Tree].Info; HoverLarge.text = $"T:{id.Tree} {info.name}"; HoverLarge.tooltip = info.name; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; } else if (id.NetNode > 0) { NetInfo info = NetManager.instance.m_nodes.m_buffer[id.NetNode].Info; HoverLarge.text = $"N:{id.NetNode} {info.name}"; HoverLarge.tooltip = info.name; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; } else if (id.NetSegment > 0) { NetInfo info = NetManager.instance.m_segments.m_buffer[id.NetSegment].Info; HoverLarge.text = $"S:{id.NetSegment} {info.name}"; HoverLarge.tooltip = info.name; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; } lastId = id; }
/// <summary> /// Called whenever the currently selected building is changed to update the panel display. /// </summary> /// <param name="building">Newly selected building</param> internal void SelectionChanged(BuildingInfo building) { // Set current building. currentBuilding = building; // Safety first! if (currentBuilding != null) { string buildingName = building.name; // Get available calculation packs for this building. popPacks = PopData.instance.GetPacks(building); floorPacks = FloorData.instance.Packs; // Get current and default packs for this item. currentPopPack = (PopDataPack)PopData.instance.ActivePack(building); currentFloorPack = (FloorDataPack)FloorData.instance.ActivePack(building); PopDataPack defaultPopPack = (PopDataPack)PopData.instance.CurrentDefaultPack(building); FloorDataPack defaultFloorPack = (FloorDataPack)FloorData.instance.CurrentDefaultPack(building); // Update multiplier before we do any other calcs. multCheck.isChecked = Multipliers.instance.HasOverride(buildingName); currentMult = Multipliers.instance.ActiveMultiplier(building); // Build pop pack menu. popMenu.items = new string[popPacks.Length]; for (int i = 0; i < popMenu.items.Length; ++i) { popMenu.items[i] = popPacks[i].displayName; // Check for default name match, if (popPacks[i].name.Equals(defaultPopPack.name)) { popMenu.items[i] += Translations.Translate("RPR_PCK_DEF"); } // Set menu selection to current pack if it matches. if (popPacks[i].name.Equals(currentPopPack.name)) { popMenu.selectedIndex = i; } } // Set population pack to current pack. UpdatePopSelection(currentPopPack); // Build floor pack menu. floorMenu.items = new string[floorPacks.Length]; for (int i = 0; i < floorPacks.Length; ++i) { floorMenu.items[i] = floorPacks[i].displayName; // Check for default name match, if (floorPacks[i].name.Equals(defaultFloorPack.name)) { floorMenu.items[i] += Translations.Translate("RPR_PCK_DEF"); } // Set menu selection to current pack if it matches. if (floorPacks[i].name.Equals(currentFloorPack.name)) { floorMenu.selectedIndex = i; // Force pack selection update. UpdateFloorSelection(i); } } // Update legacy panel for private building AIs (volumetric panel is updated by menu selection change above). if (building.GetAI() is PrivateBuildingAI) { legacyPanel.SelectionChanged(building); } // Is this a school building (need to do school building after pop and floor packs are updated)? if (building.GetAI() is SchoolAI) { // Yes - school building. Set current pack. currentSchoolPack = (SchoolDataPack)SchoolData.instance.ActivePack(building); // Are we using custom school settings? if (ModSettings.enableSchoolProperties) { // Yes - extend panel height and show school panel. volumetricPanel.relativePosition = new Vector2(0f, SchoolCalcY); applyButton.relativePosition = new Vector2(ApplyX, SchoolSaveY); // Get available school packs for this building. schoolPacks = SchoolData.instance.GetPacks(building); // Get current and default packs for this item. currentSchoolPack = (SchoolDataPack)SchoolData.instance.ActivePack(building); SchoolDataPack defaultSchoolPack = (SchoolDataPack)SchoolData.instance.CurrentDefaultPack(building); // Build school pack menu. schoolMenu.items = new string[schoolPacks.Length]; for (int i = 0; i < schoolMenu.items.Length; ++i) { schoolMenu.items[i] = schoolPacks[i].displayName; // Check for default name match, if (schoolPacks[i].name.Equals(defaultSchoolPack.name)) { schoolMenu.items[i] += Translations.Translate("RPR_PCK_DEF"); } // Set menu selection to current pack if it matches. if (schoolPacks[i].name.Equals(currentSchoolPack.name)) { schoolMenu.selectedIndex = i; // Force pack selection update. UpdateSchoolSelection(i); } } // Set multiplier value. multSlider.value = currentMult; schoolPanel.Show(); } else { // It's a school, but we're not using custom school settings, so use the non-school layout. volumetricPanel.relativePosition = new Vector2(0f, BaseCalcY); applyButton.relativePosition = new Vector2(ApplyX, BaseSaveY); schoolPanel.Hide(); } } else { // Not a school building - use non-school layout. currentSchoolPack = null; volumetricPanel.relativePosition = new Vector2(0f, BaseCalcY); applyButton.relativePosition = new Vector2(ApplyX, BaseSaveY); schoolPanel.Hide(); } } }
internal void LoadImpl(Package.Asset assetRef) { try { stack.Push(assetRef); LoadingManager.instance.m_loadingProfilerCustomAsset.BeginLoading(AssetName(assetRef.name)); GameObject go = AssetDeserializer.Instantiate(assetRef) as GameObject; CustomAssetMetaData.Type type = GetMetaType(assetRef); string packageName = assetRef.package.packageName; string fullName = type < CustomAssetMetaData.Type.RoadElevation ? packageName + "." + go.name : PillarOrElevationName(packageName, go.name); go.name = fullName; go.SetActive(false); PrefabInfo info = go.GetComponent <PrefabInfo>(); info.m_isCustomContent = true; if (info.m_Atlas != null && !string.IsNullOrEmpty(info.m_InfoTooltipThumbnail) && info.m_Atlas[info.m_InfoTooltipThumbnail] != null) { info.m_InfoTooltipAtlas = info.m_Atlas; } PropInfo pi = go.GetComponent <PropInfo>(); if (pi != null) { if (pi.m_lodObject != null) { pi.m_lodObject.SetActive(false); } Initialize(pi); loadedProps.Add(fullName); } TreeInfo ti = go.GetComponent <TreeInfo>(); if (ti != null) { Initialize(ti); loadedTrees.Add(fullName); } BuildingInfo bi = go.GetComponent <BuildingInfo>(); if (bi != null) { if (bi.m_lodObject != null) { bi.m_lodObject.SetActive(false); } bi.m_dontSpawnNormally = dontSpawnNormally.Remove(fullName); Initialize(bi); loadedBuildings.Add(fullName); if (bi.GetAI() is IntersectionAI) { loadedIntersections.Add(fullName); } } VehicleInfo vi = go.GetComponent <VehicleInfo>(); if (vi != null) { if (vi.m_lodObject != null) { vi.m_lodObject.SetActive(false); } Initialize(vi); loadedVehicles.Add(fullName); } CitizenInfo ci = go.GetComponent <CitizenInfo>(); if (ci != null) { if (ci.m_lodObject != null) { ci.m_lodObject.SetActive(false); } if (ci.InitializeCustomPrefab(citizenMetaDatas[assetRef.fullName])) { citizenMetaDatas.Remove(assetRef.fullName); ci.gameObject.SetActive(true); Initialize(ci); loadedCitizens.Add(fullName); } else { CODebugBase <LogChannel> .Warn(LogChannel.Modding, "Custom citizen [" + assetRef.fullName + "] template not available in selected theme. Asset not added in game."); } } NetInfo ni = go.GetComponent <NetInfo>(); if (ni != null) { loadedNets.Add(fullName); Initialize(ni); } } finally { stack.Pop(); assetCount++; LoadingManager.instance.m_loadingProfilerCustomAsset.EndLoading(); } }
internal void Update() { if (!MoveItTool.showDebugPanel) { return; } ToolStatus.text = $"{MoveItTool.instance.ToolState} (align:{MoveItTool.instance.AlignMode}.{MoveItTool.instance.AlignToolPhase})"; SelectedLarge.text = $"Objects Selected: {Action.selection.Count}"; ushort[] types = new ushort[8]; foreach (Instance instance in Action.selection) { if (instance is MoveableBuilding) { types[0]++; } else if (instance is MoveableProp) { PropInfo info = PropManager.instance.m_props.m_buffer[instance.id.Prop].Info; if (info.m_isDecal) { types[2]++; } else if (Filters.IsSurface(info)) { types[3]++; } else { types[1]++; } } else if (instance is MoveableTree) { types[4]++; } else if (instance is MoveableProc) { types[5]++; } else if (instance is MoveableNode) { types[6]++; } else if (instance is MoveableSegment) { types[7]++; } else { throw new Exception($"Instance is invalid type (<{instance.GetType()}>)"); } } SelectedSmall.text = $"B:{types[0]}, P:{types[1]}, D:{types[2]}, S:{types[3]}, T:{types[4]}, PO:{types[5]}, N:{types[6]}, S:{types[7]}\n "; // End with updating the hovered item if (id == null) { return; } if (id == InstanceID.Empty) { lastId = id; HoverLarge.textColor = new Color32(255, 255, 255, 255); return; } if (lastId == id) { return; } HoverLarge.textColor = new Color32(127, 217, 255, 255); HoverLarge.text = ""; HoverSmall.text = ""; if (id.Building > 0) { BuildingInfo info = BuildingManager.instance.m_buildings.m_buffer[id.Building].Info; HoverLarge.text = $"B:{id.Building} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}\n({info.m_class.m_service}.{info.m_class.m_subService})"; } else if (id.Prop > 0) { string type = "P"; PropInfo info = PropManager.instance.m_props.m_buffer[id.Prop].Info; if (info.m_isDecal) { type = "D"; } HoverLarge.text = $"{type}:{id.Prop} {info.name}"; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; } else if (id.NetLane > 0) { IInfo info = MoveItTool.PO.GetProcObj(id.NetLane).Info; HoverLarge.text = $"{id.NetLane}: {info.Name}"; HoverSmall.text = $"\n"; } else if (id.Tree > 0) { TreeInfo info = TreeManager.instance.m_trees.m_buffer[id.Tree].Info; HoverLarge.text = $"T:{id.Tree} {info.name}"; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; } else if (id.NetNode > 0) { NetInfo info = NetManager.instance.m_nodes.m_buffer[id.NetNode].Info; HoverLarge.text = $"N:{id.NetNode} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; } else if (id.NetSegment > 0) { NetInfo info = NetManager.instance.m_segments.m_buffer[id.NetSegment].Info; HoverLarge.text = $"S:{id.NetSegment} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; } lastId = id; }
internal void Update() { if (!MoveItTool.showDebugPanel) { return; } ToolStatus.text = $"{MoveItTool.instance.ToolState} (align:{MoveItTool.instance.AlignMode}.{MoveItTool.instance.AlignToolPhase})"; // End with updating the hovered item if (id == null) { return; } if (id == InstanceID.Empty) { lastId = id; HoverLarge.textColor = new Color32(255, 255, 255, 255); return; } if (lastId == id) { return; } HoverLarge.textColor = new Color32(127, 217, 255, 255); HoverLarge.text = ""; HoverSmall.text = ""; if (id.Building > 0) { BuildingInfo info = BuildingManager.instance.m_buildings.m_buffer[id.Building].Info; HoverLarge.text = $"B:{id.Building} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}\n({info.m_class.m_service}.{info.m_class.m_subService})"; if (isModToolsEnabled()) { ModTools.Id = id; } } else if (id.Prop > 0) { string type = "P"; PropInfo info = PropManager.instance.m_props.m_buffer[id.Prop].Info; if (info.m_isDecal) { type = "D"; } HoverLarge.text = $"{type}:{id.Prop} {info.name}"; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } else if (id.NetLane > 0) { IInfo info = MoveItTool.PO.GetProcObj(id.NetLane).Info; HoverLarge.text = $"{id.NetLane}: {info.Name}"; HoverSmall.text = $"\n"; if (isModToolsEnabled()) { ModTools.Id = id; } } else if (id.Tree > 0) { TreeInfo info = TreeManager.instance.m_trees.m_buffer[id.Tree].Info; HoverLarge.text = $"T:{id.Tree} {info.name}"; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } else if (id.NetNode > 0) { NetInfo info = NetManager.instance.m_nodes.m_buffer[id.NetNode].Info; HoverLarge.text = $"N:{id.NetNode} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } else if (id.NetSegment > 0) { NetInfo info = NetManager.instance.m_segments.m_buffer[id.NetSegment].Info; HoverLarge.text = $"S:{id.NetSegment} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } lastId = id; }
public static bool Filter(BuildingInfo info, bool isHover = false) { if (isHover) { // Select P&P on hover with Alt if (MITE.Settings.PillarsAsNotBuildings) { //Debug.Log($"SINGLE-Pi m_class.name:{info.m_class.name}"); if (Array.Exists(PillarClassNames, s => s.Equals(info.m_class.name))) { if (Event.current.alt) { //Debug.Log("Alt"); return(true); } return(false); } } if (MITE.Settings.PylonsAsNotBuildings) { //Debug.Log($"SINGLE-Py AI type:{info.GetAI().GetType()}"); if (Array.Exists(PylonAITypes, s => s.Equals(info.GetAI().GetType()))) { if (Event.current.alt) { //Debug.Log("Alt"); return(true); } return(false); } } if (!MoveItTool.marqueeSelection) { return(true); } } if (IsSurface(info)) { if (MITE.filterSurfaces) { return(true); } else { return(false); } } if (MoveItTool.filterBuildings) { // Filter pillars and pylons out of select if (MITE.Settings.PillarsAsNotBuildings) { //Debug.Log($"MARQUEE m_class.name:{info.m_class.name}"); if (Array.Exists(PillarClassNames, s => s.Equals(info.m_class.name))) { return(false); } } if (MITE.Settings.PylonsAsNotBuildings) { if (Array.Exists(PylonAITypes, s => s.Equals(info.GetAI().GetType()))) { return(false); } } return(true); } return(false); }
private static IEnumerable <IBasicBuildingAIOverrides> ListAiOverrides(BuildingInfo info, ServiceSystemDefinition instance) { if (SVMBuildingAIOverrideUtils.getBuildingOverrideExtension(info).Count == 0) { return(new List <IBasicBuildingAIOverrides>()); } return(SVMBuildingAIOverrideUtils.getBuildingOverrideExtension(info).Where(aiOverride => (info?.m_class?.m_service == instance?.service) && instance?.subService == info?.m_class?.m_subService && ((instance?.outsideConnection ?? false) || info?.m_class?.m_level == instance.level || (aiOverride?.ExtraAllowedLevels()?.Contains(instance.level) ?? false)) && info?.GetAI() is OutsideConnectionAI == instance?.outsideConnection && SVMUtils.logAndReturn(aiOverride?.AllowVehicleType(SVMUtils.logAndReturn(instance?.vehicleType ?? VehicleInfo.VehicleType.None, "EFF VEHICLE TYPE TESTED"), info?.GetAI()) ?? SVMUtils.logAndReturn(false, "AI OVERRIDE NULL!!!!!"), "AllowVehicleType") )); }
/// <summary> /// Called whenever the currently selected building is changed to update the panel display. /// </summary> /// <param name="building"></param> public void SelectionChanged(BuildingInfo building) { if ((building == null) || (building.name == null)) { // If no valid building selected, then hide the calculations panel. detailsPanel.height = 0; detailsPanel.isVisible = false; return; } // Variables to compare actual counts vs. mod count, to see if there's another mod overriding counts. int appliedCount; int modCount; // Building model size, not plot size. Vector3 buildingSize = building.m_size; int floorCount; // Array used for calculations depending on building service/subservice (via DataStore). int[] array; // Default minimum number of homes or jobs is one; different service types will override this. int minHomesJobs = 1; int customHomeJobs; // Check for valid building AI. if (!(building.GetAI() is PrivateBuildingAI buildingAI)) { Debugging.Message("invalid building AI type in building details"); return; } // Residential vs. workplace AI. if (buildingAI is ResidentialBuildingAI) { // Get appropriate calculation array. array = ResidentialBuildingAIMod.GetArray(building, (int)building.GetClassLevel()); // Set calculated homes label. homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_HOM_CALC"); // Set customised homes label and get value (if any). homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_HOM_CUST"); customHomeJobs = ExternalCalls.GetResidential(building); // Applied homes is what's actually being returned by the CaclulateHomeCount call to this building AI. // It differs from calculated homes if there's an override value for that building with this mod, or if another mod is overriding. appliedCount = buildingAI.CalculateHomeCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength()); homesJobsActualLabel.text = Translations.Translate("RPR_CAL_HOM_APPL") + appliedCount; } else { // Workplace AI. // Default minimum number of jobs is 4. minHomesJobs = 4; // Find the correct array for the relevant building AI. switch (building.GetService()) { case ItemClass.Service.Commercial: array = CommercialBuildingAIMod.GetArray(building, (int)building.GetClassLevel()); break; case ItemClass.Service.Office: array = OfficeBuildingAIMod.GetArray(building, (int)building.GetClassLevel()); break; case ItemClass.Service.Industrial: if (buildingAI is IndustrialExtractorAI) { array = IndustrialExtractorAIMod.GetArray(building, (int)building.GetClassLevel()); } else { array = IndustrialBuildingAIMod.GetArray(building, (int)building.GetClassLevel()); } break; default: Debugging.Message("invalid building service in building details"); return; } // Set calculated jobs label. homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_JOB_CALC") + " "; // Set customised jobs label and get value (if any). homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_JOB_CUST") + " "; customHomeJobs = ExternalCalls.GetWorker(building); // Applied jobs is what's actually being returned by the CalculateWorkplaceCount call to this building AI. // It differs from calculated jobs if there's an override value for that building with this mod, or if another mod is overriding. int[] jobs = new int[4]; buildingAI.CalculateWorkplaceCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength(), out jobs[0], out jobs[1], out jobs[2], out jobs[3]); appliedCount = jobs[0] + jobs[1] + jobs[2] + jobs[3]; homesJobsActualLabel.text = Translations.Translate("RPR_CAL_JOB_APPL") + " " + appliedCount; } // Reproduce CalcBase calculations to get building area. int calcWidth = building.GetWidth(); int calcLength = building.GetLength(); floorCount = Mathf.Max(1, Mathf.FloorToInt(buildingSize.y / array[DataStore.LEVEL_HEIGHT])); // If CALC_METHOD is zero, then calculations are based on building model size, not plot size. if (array[DataStore.CALC_METHOD] == 0) { // If asset has small x dimension, then use plot width in squares x 6m (75% of standard width) instead. if (buildingSize.x <= 1) { calcWidth *= 6; } else { calcWidth = (int)buildingSize.x; } // If asset has small z dimension, then use plot length in squares x 6m (75% of standard length) instead. if (buildingSize.z <= 1) { calcLength *= 6; } else { calcLength = (int)buildingSize.z; } } else { // If CALC_METHOD is nonzero, then caluclations are based on plot size, not building size. // Plot size is 8 metres per square. calcWidth *= 8; calcLength *= 8; } // Display calculated (and retrieved) details. detailLabels[(int)Details.width].text = Translations.Translate("RPR_CAL_BLD_X") + " " + calcWidth; detailLabels[(int)Details.length].text = Translations.Translate("RPR_CAL_BLD_Z") + " " + calcLength; detailLabels[(int)Details.height].text = Translations.Translate("RPR_CAL_BLD_Y") + " " + (int)buildingSize.y; detailLabels[(int)Details.personArea].text = Translations.Translate("RPR_CAL_BLD_M2") + " " + array[DataStore.PEOPLE]; detailLabels[(int)Details.floorHeight].text = Translations.Translate("RPR_CAL_FLR_Y") + " " + array[DataStore.LEVEL_HEIGHT]; detailLabels[(int)Details.floors].text = Translations.Translate("RPR_CAL_FLR") + " " + floorCount; // Area calculation - will need this later. int calculatedArea = calcWidth * calcLength; detailLabels[(int)Details.area].text = Translations.Translate("RPR_CAL_M2") + " " + calculatedArea; // Show or hide extra floor modifier as appropriate (hide for zero or less, otherwise show). if (array[DataStore.DENSIFICATION] > 0) { detailLabels[(int)Details.extraFloors].text = Translations.Translate("RPR_CAL_FLR_M") + " " + array[DataStore.DENSIFICATION]; detailLabels[(int)Details.extraFloors].isVisible = true; } else { detailLabels[(int)Details.extraFloors].isVisible = false; } // Set minimum residences for high density. if ((building.GetSubService() == ItemClass.SubService.ResidentialHigh) || (building.GetSubService() == ItemClass.SubService.ResidentialHighEco)) { // Minimum of 2, or 90% number of floors, whichever is greater. This helps the 1x1 high density. minHomesJobs = Mathf.Max(2, Mathf.CeilToInt(0.9f * floorCount)); } // Perform actual household or workplace calculation. modCount = Mathf.Max(minHomesJobs, (calculatedArea * (floorCount + Mathf.Max(0, array[DataStore.DENSIFICATION]))) / array[DataStore.PEOPLE]); homesJobsCalcLabel.text += modCount; // Set customised homes/jobs label (leave blank if no custom setting retrieved). if (customHomeJobs > 0) { homesJobsCustomLabel.text += customHomeJobs.ToString(); // Update modCount to reflect the custom figures. modCount = customHomeJobs; } // Check to see if Ploppable RICO Revisited is controlling this building's population. if (ModUtils.CheckRICO(building)) { messageLabel.text = Translations.Translate("RPR_CAL_RICO"); messageLabel.Show(); } else { // Hide message text by default. messageLabel.Hide(); } // We've got a valid building and results, so show panel. detailsPanel.height = 270; detailsPanel.isVisible = true; }
bool RegisterPrefab(String fullName, Package.Asset asset, CustomAssetMetaData metaData, PrefabInfo info, GameObject go) { PropInfo pi = go.GetComponent <PropInfo>(); if (pi != null) { if (pi.m_lodObject != null) { pi.m_lodObject.SetActive(false); } if (StorePropName(fullName)) { PrefabCollection <PropInfo> .InitializePrefabs("Custom Assets", pi, null); return(true); } } TreeInfo ti = go.GetComponent <TreeInfo>(); if (ti != null && StoreTreeName(fullName)) { PrefabCollection <TreeInfo> .InitializePrefabs("Custom Assets", ti, null); return(true); } BuildingInfo bi = go.GetComponent <BuildingInfo>(); if (bi != null) { if (bi.m_lodObject != null) { bi.m_lodObject.SetActive(false); } if (StoreBuildingName(fullName)) { PrefabCollection <BuildingInfo> .InitializePrefabs("Custom Assets", bi, null); bi.m_dontSpawnNormally = !IsCommonBuilding(fullName, asset, metaData); if (bi.GetAI() is IntersectionAI) { loadedIntersections.Add(fullName); } return(true); } } VehicleInfo vi = go.GetComponent <VehicleInfo>(); if (vi != null) { if (vi.m_lodObject != null) { vi.m_lodObject.SetActive(false); } if (StoreVehicleName(fullName)) { PrefabCollection <VehicleInfo> .InitializePrefabs("Custom Assets", vi, null); return(true); } } return(false); }
public Dictionary <TransferManager.TransferReason, Tuple <VehicleInfo.VehicleType, bool, bool> > GetManagedReasons(BuildingInfo info) { return(GetManagedReasons((U)info.GetAI(), default(TransferManager.TransferOffer))); }
public Dictionary <TransferManager.TransferReason, StartTransferCallStructure> GetManagedReasons(BuildingInfo info) { return(GetManagedReasons((U)info.GetAI(), default(TransferManager.TransferOffer))); }
/// <summary> /// Updates a school prefab record (and associated tooltip) with updated population. /// </summary> /// <param name="prefab">Prefab to update</param> internal void UpdateSchoolPrefab(BuildingInfo prefab) => UpdateSchoolPrefab(prefab, prefab.GetAI() as SchoolAI);
/// <summary> /// Perform and display volumetric calculations for the currently selected building. /// </summary> /// <param name="building">Selected building prefab</param> /// <param name="levelData">Population (level) calculation data to apply to calculations</param> /// <param name="floorData">Floor calculation data to apply to calculations</param> /// <param name="schoolData">School calculation data to apply to calculations</param> /// <param name="schoolData">Multiplier to apply to calculations</param> internal void CalculateVolumetric(BuildingInfo building, LevelData levelData, FloorDataPack floorData, SchoolDataPack schoolData, float multiplier) { // Safety first! if (building == null) { return; } // Reset message label. messageLabel.text = string.Empty; // Perform calculations. // Get floors and allocate area an number of floor labels. SortedList <int, float> floors = PopData.instance.VolumetricFloors(building.m_generatedInfo, floorData, out float totalArea); floorAreaLabel.text = totalArea.ToString("N0", LocaleManager.cultureInfo); numFloorsLabel.text = floors.Count.ToString(); // Get total units. int totalUnits = PopData.instance.VolumetricPopulation(building.m_generatedInfo, levelData, floorData, multiplier, floors, totalArea); // Floor labels list. List <string> floorLabels = new List <string>(); // What we call our units for this building. string unitName; switch (building.GetService()) { case ItemClass.Service.Residential: // Residential - households. unitName = Translations.Translate("RPR_CAL_UNI_HOU"); break; case ItemClass.Service.Education: // Education - students. unitName = Translations.Translate("RPR_CAL_UNI_STU"); break; default: // Default - workplaces. unitName = Translations.Translate("RPR_CAL_UNI_WOR"); break; } // See if we're using area calculations for numbers of units, i.e. areaPer is at least one. if (levelData.areaPer > 0) { // Determine area percentage to use for calculations (inverse of empty area percentage). float areaPercent = 1 - (levelData.emptyPercent / 100f); // Create new floor area labels by iterating through each floor. for (int i = 0; i < floors.Count; ++i) { // StringBuilder, because we're doing a fair bit of manipulation here. StringBuilder floorString = new StringBuilder("Floor "); // Floor number floorString.Append(i + 1); floorString.Append(" " + Translations.Translate("RPR_CAL_VOL_ARA") + " "); floorString.Append(floors[i].ToString("N0")); // See if we're calculating units per individual floor. if (!levelData.multiFloorUnits) { // Number of units on this floor - always rounded down. int floorUnits = (int)((floors[i] * areaPercent) / levelData.areaPer); // Adjust by multiplier (after rounded calculation above). floorUnits = (int)(floorUnits * multiplier); // Add extra info to label. floorString.Append(" ("); floorString.Append(floorUnits.ToString("N0")); floorString.Append(" "); floorString.Append(unitName); floorString.Append(")"); } // Add new floor label item with results for this calculation. floorLabels.Add(floorString.ToString()); } } // Do we have a current school selection, and are we using school property overrides? if (schoolData != null && ModSettings.enableSchoolProperties) { // Yes - calculate and display school worker breakdown. int[] workers = SchoolData.instance.CalcWorkers(schoolData, totalUnits); schoolWorkerLabel.Show(); schoolWorkerLabel.text = workers[0] + " / " + workers[1] + " / " + workers[2] + " / " + workers[3]; // Calculate construction cost to display. int cost = SchoolData.instance.CalcCost(schoolData, totalUnits); ColossalFramework.Singleton <EconomyManager> .instance.m_EconomyWrapper.OnGetConstructionCost(ref cost, building.m_class.m_service, building.m_class.m_subService, building.m_class.m_level); // Calculate maintenance cost to display. int maintenance = SchoolData.instance.CalcMaint(schoolData, totalUnits) * 100; ColossalFramework.Singleton <EconomyManager> .instance.m_EconomyWrapper.OnGetMaintenanceCost(ref maintenance, building.m_class.m_service, building.m_class.m_subService, building.m_class.m_level); float displayMaint = Mathf.Abs(maintenance * 0.0016f); // And display school cost breakdown. costLabel.Show(); costLabel.text = cost.ToString((!(displayMaint >= 10f)) ? Settings.moneyFormat : Settings.moneyFormatNoCents, LocaleManager.cultureInfo) + " / " + displayMaint.ToString((!(displayMaint >= 10f)) ? Settings.moneyFormat : Settings.moneyFormatNoCents, LocaleManager.cultureInfo); // Enforce school floors list position. ResetFloorListPosition(); } else { // No - hide school worker breakdown and cost labels. schoolWorkerLabel.Hide(); costLabel.Hide(); // Enforce default floors list position. ResetFloorListPosition(); } // Allocate our new list of labels to the floors list (via an interim fastlist to avoid race conditions if we 'build' manually directly into floorsList). FastList <object> fastList = new FastList <object>() { m_buffer = floorLabels.ToArray(), m_size = floorLabels.Count }; floorsList.rowsData = fastList; // Display total unit calculation result. switch (building.GetService()) { case ItemClass.Service.Residential: // Residential building. totalJobsLabel.Hide(); totalStudentsLabel.Hide(); totalHomesLabel.Show(); totalHomesLabel.text = totalUnits.ToString("N0", LocaleManager.cultureInfo); break; case ItemClass.Service.Education: // School building. totalHomesLabel.Hide(); totalJobsLabel.Hide(); totalStudentsLabel.Show(); totalStudentsLabel.text = totalUnits.ToString("N0", LocaleManager.cultureInfo); break; default: // Workplace building. totalHomesLabel.Hide(); totalStudentsLabel.Hide(); totalJobsLabel.Show(); totalJobsLabel.text = totalUnits.ToString("N0", LocaleManager.cultureInfo); break; } // Display commercial visit count, or hide the label if not commercial. if (building.GetAI() is CommercialBuildingAI) { visitCountLabel.Show(); visitCountLabel.text = RealisticVisitplaceCount.PreviewVisitCount(building, totalUnits).ToString(); } else { visitCountLabel.Hide(); } // Display production count, or hide the label if not a production building. if (building.GetAI() is PrivateBuildingAI privateAI && (privateAI is OfficeBuildingAI || privateAI is IndustrialBuildingAI || privateAI is IndustrialExtractorAI)) { productionLabel.Show(); productionLabel.text = privateAI.CalculateProductionCapacity(building.GetClassLevel(), new ColossalFramework.Math.Randomizer(), building.GetWidth(), building.GetLength()).ToString(); }
public void Update(InstanceID instanceId) { id = instanceId; if (!MITE.Settings.ShowDebugPanel) { return; } if (id == null) { return; } if (id == InstanceID.Empty) { lastId = id; HoverLarge.textColor = new Color32(255, 255, 255, 255); return; } if (lastId == id) { return; } HoverLarge.textColor = new Color32(127, 217, 255, 255); HoverLarge.text = ""; HoverSmall.text = ""; if (id.Building > 0) { BuildingInfo info = BuildingManager.instance.m_buildings.m_buffer[id.Building].Info; HoverLarge.text = $"B:{id.Building} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}\n({info.m_class.m_service}.{info.m_class.m_subService})"; if (isModToolsEnabled()) { ModTools.Id = id; } } if (id.Prop > 0) { string type = "P"; PropInfo info = PropManager.instance.m_props.m_buffer[id.Prop].Info; if (info.m_isDecal) { type = "D"; } HoverLarge.text = $"{type}:{id.Prop} {info.name}"; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } if (id.Tree > 0) { TreeInfo info = TreeManager.instance.m_trees.m_buffer[id.Tree].Info; HoverLarge.text = $"T:{id.Tree} {info.name}"; HoverSmall.text = $"{info.GetType()}\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } if (id.NetNode > 0) { NetInfo info = NetManager.instance.m_nodes.m_buffer[id.NetNode].Info; HoverLarge.text = $"N:{id.NetNode} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } if (id.NetSegment > 0) { NetInfo info = NetManager.instance.m_segments.m_buffer[id.NetSegment].Info; HoverLarge.text = $"S:{id.NetSegment} {info.name}"; HoverSmall.text = $"{info.GetType()} ({info.GetAI().GetType()})\n{info.m_class.name}"; if (isModToolsEnabled()) { ModTools.Id = id; } } lastId = id; }
public static ServiceSystemDefinition from(BuildingInfo info, VehicleInfo.VehicleType type) { if (info == null) { return(default(ServiceSystemDefinition)); } return(availableDefinitions.Keys.FirstOrDefault(x => x.service == info.m_class.m_service && x.subService == info.m_class.m_subService && (x.level == info.m_class.m_level || x.outsideConnection) && x.vehicleType == type && x.outsideConnection == info.GetAI() is OutsideConnectionAI)); }
/// <summary> /// Upgrades/downgrades the selected building to the given level, if possible. /// </summary> /// <param name="buildingID">Building instance ID</param> /// <param name="targetLevel">Level to upgrade/downgrade to</param> internal static void ForceLevel(ushort buildingID, byte targetLevel) { // BuildingInfo to change to, if this building isn't historical. BuildingInfo targetInfo = null; // References. BuildingManager buildingManager = Singleton <BuildingManager> .instance; Building[] buildingBuffer = buildingManager.m_buildings.m_buffer; BuildingInfo buildingInfo = buildingBuffer[buildingID].Info; PrivateBuildingAI buildingAI = buildingInfo?.GetAI() as PrivateBuildingAI; if (buildingInfo == null || buildingAI == null) { // If something went wrong, abort. Logging.Error("couldn't get existing building info"); return; } // Check to see if this is historical or not, or is a RICO ploppable. bool isHistorical = buildingAI.IsHistorical(buildingID, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[buildingID], out bool _) || ModUtils.CheckRICOPloppable(buildingInfo); // Get target prefab (if needed, i.e. not historical or RICO ploppable). if (!isHistorical) { // Get upgrade/downgrade building target. targetInfo = GetTargetInfo(buildingID, targetLevel); if (targetInfo == null) { // If we failed, don't do anything more. return; } } // If we have a valid upgrade/downgrade target, proceed. if (isHistorical || targetInfo != null) { // Apply target level to our building and cancel all level-up progress. buildingBuffer[buildingID].m_level = targetLevel; buildingBuffer[buildingID].m_levelUpProgress = 0; // Apply our upgrade/downgrade target if not historical if (!isHistorical) { buildingManager.UpdateBuildingInfo(buildingID, targetInfo); } // Post-downgrade processing to update instance values - call game method if new level is equal to or greater than info base level, otherwise use custom method. BuildingInfo newInfo = targetInfo ?? buildingInfo; if (newInfo.GetAI() is PrivateBuildingAI newAI) { if (targetLevel < (byte)newInfo.GetClassLevel()) { // New level is less than info base level; call custom method. CustomBuildingUpgraded(newAI, buildingID, ref buildingBuffer[buildingID]); } else { // New level is equal to or greater than info base level; call game method. newAI.BuildingUpgraded(buildingID, ref buildingBuffer[buildingID]); } } } }
public static void CalculateAllWorkplaces() { if (!ShouldWeCount) { return; } WorkplacesEducated = 0; WorkplacesHighlyEducated = 0; WorkplacesUneducated = 0; WorkplacesWellEducated = 0; for (var i = 0; i < comWorkplaces.Length; i++) { comWorkplaces[i] = 0; offWorkplaces[i] = 0; indWorkplaces[i] = 0; } BuildingManager buildingManager = Singleton <BuildingManager> .instance; if (buildingManager == null || buildingManager.m_buildings == null) { return; } // go through all buildings for (ushort buildingID = 0; buildingID < buildingManager.m_buildings.m_buffer.Length; buildingID++) { try { Building building = buildingManager.m_buildings.m_buffer[buildingID]; BuildingInfo buildingInfo = building.Info; // we have build info and created building if (buildingInfo != null && (building.m_flags & Building.Flags.Created) != Building.Flags.None) { var privateBuildingAI = buildingInfo.GetAI() as PrivateBuildingAI; // if it is zoned building (PlayerIndustry is for zoned special industry) if (privateBuildingAI != null && (ItemClass.Service.Commercial == buildingInfo.GetService() || ItemClass.Service.Industrial == buildingInfo.GetService() || ItemClass.Service.PlayerIndustry == buildingInfo.GetService() || ItemClass.Service.Office == buildingInfo.GetService())) { int wp0, wp1, wp2, wp3; privateBuildingAI.CalculateWorkplaceCount( (ItemClass.Level)building.m_level, new Randomizer(buildingID), building.Width, building.Length, out wp0, out wp1, out wp2, out wp3); privateBuildingAI.AdjustWorkplaceCount( buildingID, ref building, ref wp0, ref wp1, ref wp2, ref wp3); WorkplacesUneducated += wp0; WorkplacesEducated += wp1; WorkplacesWellEducated += wp2; WorkplacesHighlyEducated += wp3; ItemClass.Service service = buildingInfo.GetService(); switch (service) { case ItemClass.Service.Commercial: comWorkplaces[0] += wp0; comWorkplaces[1] += wp1; comWorkplaces[2] += wp2; comWorkplaces[3] += wp3; break; case ItemClass.Service.Industrial: case ItemClass.Service.PlayerIndustry: indWorkplaces[0] += wp0; indWorkplaces[1] += wp1; indWorkplaces[2] += wp2; indWorkplaces[3] += wp3; break; case ItemClass.Service.Office: offWorkplaces[0] += wp0; offWorkplaces[1] += wp1; offWorkplaces[2] += wp2; offWorkplaces[3] += wp3; break; } } // if privateBuildingAI end else { // this is for all other buildings - services, monuments, parks, INDUSTRY AREAS if (buildingInfo.GetAI().GetType().IsSubclassOf(typeof(PlayerBuildingAI))) { var ai = buildingInfo.GetAI() as PlayerBuildingAI; if (ai != null) { int swp0, swp1, swp2, swp3; // Industry are buildings provide workplace info from this common method // But it does NOT work for raw material storages (they are like normal warehouses) ai.CountWorkPlaces(out swp0, out swp1, out swp2, out swp3); // works for industry areas // if it is sum of workplaces 0, it is another type of service building if (swp0 + swp1 + swp2 + swp3 == 0) { // we will try bit of reflection // we get Type of buildingAI var serviceAI = buildingInfo.GetAI(); Type aiType = buildingInfo.GetAI().GetType(); // we get all fields of that AI Type FieldInfo[] fieldInfos = aiType.GetFields(); // we check if Types fields contains field m_workPlaceCount0 if (fieldInfos.Length > 0 && serviceAI != null && aiType.GetField("m_workPlaceCount0") != null) { // and we count them swp0 = (int)(aiType.GetField("m_workPlaceCount0").GetValue(serviceAI) ?? 0); swp1 = (int)(aiType.GetField("m_workPlaceCount1").GetValue(serviceAI) ?? 0); swp2 = (int)(aiType.GetField("m_workPlaceCount2").GetValue(serviceAI) ?? 0); swp3 = (int)(aiType.GetField("m_workPlaceCount3").GetValue(serviceAI) ?? 0); } } WorkplacesUneducated += swp0; WorkplacesEducated += swp1; WorkplacesWellEducated += swp2; WorkplacesHighlyEducated += swp3; } } } } } catch (NullReferenceException e) { // This should not happen now... Debug.Log("Demographics Mod: Trying to count building which does " + "not have workplace information. We should not get here... " + e.Message); } } ShouldWeCount = false; }
public static bool Filter(BuildingInfo info, bool isHover = false) { if (MoveItTool.filterPicker && info == Picker.Info) { return(true); } if (isHover) { //Select P&P on hover with Alt if (MoveItTool.altSelectNodeBuildings) { if (Array.Exists(PillarClassNames, s => s.Equals(info.m_class.name))) { if (Event.current.alt) { return(true); } return(false); } if (Array.Exists(PylonAITypes, s => s.Equals(info.GetAI().GetType()))) { if (Event.current.alt) { return(true); } return(false); } } if (!MoveItTool.marqueeSelection) { return(true); } } if (IsSurface(info)) { if (MoveItTool.filterSurfaces) { return(true); } else { return(false); } } if (MoveItTool.filterBuildings) { if (MoveItTool.altSelectNodeBuildings) { if (Array.Exists(PillarClassNames, s => s.Equals(info.m_class.name))) { return(false); } if (Array.Exists(PylonAITypes, s => s.Equals(info.GetAI().GetType()))) { return(false); } } return(true); } return(false); }
public void updateBidings() { BuildingInfo basicInfo = Singleton <BuildingManager> .instance.m_buildings.m_buffer[m_buildingIdSelecionado.Building].Info; DepotAI basicAI = basicInfo.GetAI() as DepotAI; if (basicAI == null) { closeDepotInfo(null, null); return; } TransportStationAI stationAI = basicInfo.GetAI() as TransportStationAI; HarborAI harborAI = basicInfo.GetAI() as HarborAI; vehiclesInUseLabel.text = LocaleFormatter.FormatGeneric("TRANSPORT_LINE_VEHICLECOUNT", new object[] { basicAI.GetVehicleCount(m_buildingIdSelecionado.Building, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[m_buildingIdSelecionado.Building]).ToString() }); if (stationAI != null) { passengersLastWeek.isVisible = true; int passengerCount = stationAI.GetPassengerCount(m_buildingIdSelecionado.Building, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[m_buildingIdSelecionado.Building]); passengersLastWeek.text = LocaleFormatter.FormatGeneric("AIINFO_PASSENGERS_SERVICED", new object[] { passengerCount }); } else { passengersLastWeek.isVisible = false; } upkeepCost.text = LocaleFormatter.FormatUpkeep(basicAI.GetResourceRate(m_buildingIdSelecionado.Building, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)m_buildingIdSelecionado.Building], EconomyManager.Resource.Maintenance), false); uint num = Singleton <BuildingManager> .instance.m_buildings.m_buffer[m_buildingIdSelecionado.Building].m_citizenUnits; int num2 = 0; int num3 = 0; int unskill = 0; int oneSchool = 0; int twoSchool = 0; int threeSchool = 0; CitizenManager instance = Singleton <CitizenManager> .instance; while (num != 0u) { uint nextUnit = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_nextUnit; if ((ushort)(instance.m_units.m_buffer[(int)((UIntPtr)num)].m_flags & CitizenUnit.Flags.Work) != 0) { for (int i = 0; i < 5; i++) { uint citizen = instance.m_units.m_buffer[(int)((UIntPtr)num)].GetCitizen(i); if (citizen != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)citizen)].Dead && (instance.m_citizens.m_buffer[(int)((UIntPtr)citizen)].m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) { num3++; switch (instance.m_citizens.m_buffer[(int)((UIntPtr)citizen)].EducationLevel) { case Citizen.Education.Uneducated: unskill++; break; case Citizen.Education.OneSchool: oneSchool++; break; case Citizen.Education.TwoSchools: twoSchool++; break; case Citizen.Education.ThreeSchools: threeSchool++; break; } } } } num = nextUnit; if (++num2 > 524288) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } workerChart.SetValues(new int[] { unskill, oneSchool, twoSchool, threeSchool }, new int[] { basicAI.m_workPlaceCount0, basicAI.m_workPlaceCount1, basicAI.m_workPlaceCount2, basicAI.m_workPlaceCount3 }); }