diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fa66161 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,107 @@ +cmake_minimum_required(VERSION 3.8.2) +project(RealCity VERSION 0.1.0 LANGUAGES CSharp) + +set(CITIES_STEAM_ID 255710) +set(REAL_CITY_REVISED_STEAM_ID 2949699934) + +file(GLOB_RECURSE SRCS *.cs) +file(GLOB_RECURSE RES Resources/*) +file(GLOB_RECURSE ICONS Icon/*) + + +if(WIN32) + set(MOD_INSTALL_INITAL_PATH "$ENV{LOCALAPPDATA}/Colossal Order/Cities_Skylines/${PROJECT_NAME}") +elseif(APPLE) + set(MOD_INSTALL_INITAL_PATH "$ENV{HOME}//Library/Application Support/Colossal Order/Cities_Skylines/${PROJECT_NAME}" ) +else() + set(MOD_INSTALL_INITAL_PATH "$ENV{HOME}/.local/share/Colossal Order/Cities_Skylines/${PROJECT_NAME}" ) +endif() + +set(MOD_INSTALL_PATH "${MOD_INSTALL_INITAL_PATH}" CACHE PATH "Path for publishing mod") + +set(STEAM_CITIES_LIBRARY "C:/Program Files (x86)/Steam" CACHE PATH "Path to steam library which contents Cities:Skylines") +find_path(CITIES_MOD_PARENT_PATH + ${CITIES_STEAM_ID} + PATHS "${STEAM_CITIES_LIBRARY}/steamapps/workshop/content" + DOC "Path to RealCity installation") + +set(MOD_PATH "${CITIES_MOD_PARENT_PATH}/${CITIES_STEAM_ID}/${REAL_CITY_REVISED_STEAM_ID}") + +add_library(${PROJECT_NAME} ${SRCS} ${RES}) + +find_path(CITIES_MANAGED_PATH + ICities.dll + PATHS "${STEAM_CITIES_LIBRARY}/steamapps/common/Cities_Skylines/Cities_Data/Managed" DOC "Path to Cities Skylines managed libs") + +set(REFS + System + System.Core + System.Xml.Linq + System.Data.DataSetExtensions + System.Data + System.Net.Http + System.Xml + ) + +set(CITIES_REFS + Assembly-CSharp + Assembly-CSharp-firstpass + ColossalManaged + ICities + ICSharpCode.SharpZipLib + Mono.Posix + Mono.Security + UnityEngine + UnityEngine.Networking + UnityEngine.UI +) + +set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_REFERENCES ${REFS}) + +foreach(CITIES_REF IN ITEMS ${CITIES_REFS}) + set_target_properties(${PROJECT_NAME} PROPERTIES VS_DOTNET_REFERENCE_${CITIES_REF} "${CITIES_MANAGED_PATH}/${CITIES_REF}.dll") +endforeach() + +find_program(NUGET nuget HINTS "${CMAKE_SOURCE_DIR}") + +add_custom_command(TARGET ${PROJECT_NAME} + PRE_BUILD + COMMAND "${NUGET}" restore "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.sln") + + +target_compile_options(${PROJECT_NAME} PRIVATE "/langversion:latestMajor" "/unsafe" "/platform:anycpu") + +set_target_properties(${PROJECT_NAME} PROPERTIES + VS_GLOBAL_ROOTNAMESPACE ${PROJECT_NAME} + VS_GLOBAL_ProjectGuid "{40017200-7278-44D7-A12C-8DDC6BD98440}" + VS_GLOBAL_CodeAnalysisRuleSet "${CMAKE_SOURCE_DIR}/RealCity.ruleset" + VS_GLOBAL_FileAlignment "512" + VS_GLOBAL_Prefer32Bit "false" + VS_GLOBAL_LangVersion "7.3" + VS_GLOBAL_AllowUnsafeBlocks "true" + VS_GLOBAL_Platform "AnyCPU" + VS_GLOBAL_WarningLevel "4" + VS_GLOBAL_PlatformTarget "AnyCPU" + ) + +set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v3.5") +set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_REFERENCES_COPY_LOCAL False) + +set_target_properties(${PROJECT_NAME} PROPERTIES VS_DOTNET_REFERENCE_0Harmony "${CMAKE_BINARY_DIR}/packages/Lib.Harmony.2.0.0.9/lib/net35/0Harmony.dll") +set_target_properties(${PROJECT_NAME} PROPERTIES VS_DOTNET_REFERENCE_CitiesHarmony.API "${CMAKE_BINARY_DIR}/packages/CitiesHarmony.API.1.0.4/lib/net35/CitiesHarmony.API.dll") + +function(add_mod_file SRC DEST) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SRC}" "${DEST}" COMMENT "Copying ${SRC} -> ${DEST}\r") + install(FILES "${DEST}" DESTINATION "${MOD_INSTALL_PATH}") +endfunction(add_mod_file) + +function(add_mod_directory SRC DEST) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${SRC}" "${DEST}" COMMENT "Copying ${SRC} -> ${DEST}\r") + install(DIRECTORY "${DEST}" DESTINATION "${MOD_INSTALL_PATH}") +endfunction(add_mod_directory) + +add_mod_directory("${CMAKE_SOURCE_DIR}/Resources" "${MOD_PATH}/Resources") +add_mod_directory("${CMAKE_SOURCE_DIR}/Icon" "${MOD_PATH}/Icon") + +add_mod_file("${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${PROJECT_NAME}.dll" "${MOD_PATH}/${PROJECT_NAME}.dll") +execute_process(COMMAND "${NUGET}" install "${CMAKE_SOURCE_DIR}/packages.config" -OutputDirectory "${CMAKE_BINARY_DIR}/packages" -SolutionDirectory "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}") diff --git a/Patch/CommonBuildingAIGetColorPatch.cs b/Patch/CommonBuildingAIGetColorPatch.cs index d71c158..73f16b9 100644 --- a/Patch/CommonBuildingAIGetColorPatch.cs +++ b/Patch/CommonBuildingAIGetColorPatch.cs @@ -16,11 +16,11 @@ public static MethodBase TargetMethod() "GetColor", BindingFlags.Instance | BindingFlags.Public, null, - new[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(InfoManager.InfoMode) }, + new[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(InfoManager.InfoMode), typeof(InfoManager.SubInfoMode) }, new ParameterModifier[0]); } - public static void Postfix(ushort buildingID, ref Building data, InfoManager.InfoMode infoMode, ref Color __result) + public static void Postfix(ushort buildingID, ref Building data, InfoManager.InfoMode infoMode, InfoManager.SubInfoMode subInfoMode, ref Color __result) { if (infoMode == InfoManager.InfoMode.LandValue) { diff --git a/Patch/PrivateBuildingAISimulationStepActivePatch.cs b/Patch/PrivateBuildingAISimulationStepActivePatch.cs index 5ba9f67..3970920 100644 --- a/Patch/PrivateBuildingAISimulationStepActivePatch.cs +++ b/Patch/PrivateBuildingAISimulationStepActivePatch.cs @@ -125,23 +125,23 @@ public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buil } } - if (buildingData.m_problems == Notification.Problem.None) + if (buildingData.m_problems == Notification.Problem1.None) { //mark no good if ((buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) && (RealCity.debugMode)) { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoGoods); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoGoods); if (buildingData.m_customBuffer2 < 500) { - problem = Notification.AddProblems(problem, Notification.Problem.NoGoods | Notification.Problem.MajorProblem); + problem = Notification.AddProblems(problem, Notification.Problem1.NoGoods | Notification.Problem1.MajorProblem); } else if (buildingData.m_customBuffer2 < 1000) { - problem = Notification.AddProblems(problem, Notification.Problem.NoGoods); + problem = Notification.AddProblems(problem, Notification.Problem1.NoGoods); } else { - problem = Notification.Problem.None; + problem = Notification.Problem1.None; } buildingData.m_problems = problem; } diff --git a/Patch/ResidentAIStartMovingPatch.cs b/Patch/ResidentAIStartMovingPatch.cs new file mode 100644 index 0000000..752393f --- /dev/null +++ b/Patch/ResidentAIStartMovingPatch.cs @@ -0,0 +1,67 @@ +using System; +using ColossalFramework; +using UnityEngine; +using RealCity.Util; +using HarmonyLib; +using System.Reflection; +using RealCity.CustomData; +using RealCity.CustomAI; +using ColossalFramework.Math; + +namespace RealCity.Patch +{ + [HarmonyPatch] + public class ResidentAIStartMovingPatch + { + public static MethodBase TargetMethod() + { + return typeof(ResidentAI).GetMethod("StartMoving", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint), typeof(Citizen).MakeByRefType(), typeof(ushort), typeof(ushort) }, null); + } + + public static void Prefix(uint citizenID, ref Citizen data, ref ushort sourceBuilding, ref ushort targetBuilding) + { + if (data.m_workBuilding != targetBuilding) + { + var building = Singleton.instance.m_buildings.m_buffer[targetBuilding]; + if (building.Info.m_class.m_service == ItemClass.Service.Commercial) + { + CitizenManager instance = Singleton.instance; + ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; + uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); + uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); + + Citizen.BehaviourData behaviour = default; + int aliveVisitCount = 0; + int totalVisitCount = 0; + RealCityCommercialBuildingAI.InitDelegate(); + RealCityCommercialBuildingAI.GetVisitBehaviour((CommercialBuildingAI)(building.Info.m_buildingAI), targetBuilding, ref building, ref behaviour, ref aliveVisitCount, ref totalVisitCount); + var amount = building.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount; + var CommercialBuildingAI = building.Info.m_buildingAI as CommercialBuildingAI; + var maxCount = CommercialBuildingAI.CalculateVisitplaceCount((ItemClass.Level)building.m_level, new Randomizer(targetBuilding), building.m_width, building.m_length); + if ((amount <= 0) || (maxCount <= totalVisitCount)) + { + //Close CommercialBuilding + //Reject citizen to building which lack of goods + sourceBuilding = targetBuilding; + building.m_flags &= ~Building.Flags.Active; + return; + } + + if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)) + { + //Reject poor citizen to building + sourceBuilding = targetBuilding; + return; + } + else if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { + //Reject citizen who already have enough goods to building + sourceBuilding = targetBuilding; + return; + } + + } + } + } + } +} \ No newline at end of file diff --git a/Patch/TouristAIStartMovingPatch.cs b/Patch/TouristAIStartMovingPatch.cs new file mode 100644 index 0000000..923abc2 --- /dev/null +++ b/Patch/TouristAIStartMovingPatch.cs @@ -0,0 +1,52 @@ +using System; +using ColossalFramework; +using UnityEngine; +using RealCity.Util; +using HarmonyLib; +using System.Reflection; +using RealCity.CustomData; +using RealCity.CustomAI; +using ColossalFramework.Math; + +namespace RealCity.Patch +{ + [HarmonyPatch] + public class TouristAIStartMovingPatch + { + public static MethodBase TargetMethod() + { + return typeof(TouristAI).GetMethod("StartMoving", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint), typeof(Citizen).MakeByRefType(), typeof(ushort), typeof(ushort) }, null); + } + + public static void Prefix(uint citizenID, ref Citizen data, ref ushort sourceBuilding, ref ushort targetBuilding) + { + if (data.m_workBuilding != targetBuilding) + { + var building = Singleton.instance.m_buildings.m_buffer[targetBuilding]; + if (building.Info.m_class.m_service == ItemClass.Service.Commercial) + { + CitizenManager instance = Singleton.instance; + ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; + uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); + uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); + + Citizen.BehaviourData behaviour = default(Citizen.BehaviourData); + int aliveVisitCount = 0; + int totalVisitCount = 0; + RealCityCommercialBuildingAI.GetVisitBehaviour((CommercialBuildingAI)(building.Info.m_buildingAI), targetBuilding, ref building, ref behaviour, ref aliveVisitCount, ref totalVisitCount); + var amount = building.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount; + var CommercialBuildingAI = building.Info.m_buildingAI as CommercialBuildingAI; + var maxCount = CommercialBuildingAI.CalculateVisitplaceCount((ItemClass.Level)building.m_level, new Randomizer(targetBuilding), building.m_width, building.m_length); + if ((amount <= 0) || (maxCount <= totalVisitCount)) + { + //Close CommercialBuilding + //Reject citizen to building which lack of goods + sourceBuilding = targetBuilding; + building.m_flags &= ~Building.Flags.Active; + return; + } + } + } + } + } +} \ No newline at end of file diff --git a/RealCity.sln b/RealCity.sln deleted file mode 100644 index 23f231c..0000000 --- a/RealCity.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29609.76 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RealCity", "RealCity.csproj", "{40017200-7278-44D7-A12C-8DDC6BD98440}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - FASTRUNTIME|Any CPU = FASTRUNTIME|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {40017200-7278-44D7-A12C-8DDC6BD98440}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {40017200-7278-44D7-A12C-8DDC6BD98440}.Debug|Any CPU.Build.0 = Debug|Any CPU - {40017200-7278-44D7-A12C-8DDC6BD98440}.FASTRUNTIME|Any CPU.ActiveCfg = FASTRUNTIME|Any CPU - {40017200-7278-44D7-A12C-8DDC6BD98440}.FASTRUNTIME|Any CPU.Build.0 = FASTRUNTIME|Any CPU - {40017200-7278-44D7-A12C-8DDC6BD98440}.Release|Any CPU.ActiveCfg = Release|Any CPU - {40017200-7278-44D7-A12C-8DDC6BD98440}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {84893815-40F6-4615-BCF2-0E71069D365A} - EndGlobalSection -EndGlobal diff --git a/Resources/ja.txt b/Resources/ja.txt new file mode 100644 index 0000000..e3a4aca --- /dev/null +++ b/Resources/ja.txt @@ -0,0 +1,196 @@ +ECONOMIC_DATA 経済データ +CITIZEN_STATUS 1. 市民の状態(単位: 1/100₡) +CITIZEN_COUNT 市民数 +FAMILY_COUNT 世帯数 +SALARY_PER_FAMILY 一世帯あたりの給与 +CITIZEN_TAX_PER_FAMILY 一世帯あたりの市民税 +EXPENSE_PER_FAMILY 一世帯あたりの支出 +AVERAGE_TRANPORT_FEE 平均交通費 +LEVEL3_HIGH_WEALTH レベル3の富裕層 +LEVEL2_HIGH_WEALTH レベル2の富裕層 +LEVEL1_HIGH_WEALTH レベル1の富裕層 +WEALTH_HIGH_COUNT 富裕層の人数 +WEALTH_MEDIUM_COUNT 中間層の人数 +WEALTH_LOW_COUNT 貧困層の人数 +BUILDING_STATUS 2. 建物の状況 +PROFIT_BUIDLING_COUNT 建物の利益 (I&C) +EXTERNAL_INVESTMENTS 外部投資 (オフィス用) +TIP1 ヒント1 +TIP2 ヒント2 +TIP3 ヒント3 +TIP4 ヒント4 +TIP5 ヒント5 +TIP6 ヒント6 +POLICY_COST 3. Modの方針費用 (₡) +LIVING_ALLOWANCE 生活保護と手当て +UNFINISHED_DEAL_LOST 未払い金の返金 +USE_TMPE_TIP TMPEを使用して車両のスポーンを無効化 +STARTUP_TIP 工業化は経済と財政を最初から改善するために重要です。 +TOURIST_TIP 観光客の呼び込むために商業地区の観光化に挑戦してみて下さい。 +OFFICE_TIP オフィスは都市の産業に依存して、「外部投資」を受けることができます。 +UNLOCK_TIP ゲーム開始時に全てをアンロック MODで解除しないで下さい! +UG_TIP 詳細はUGで確認して下さい +CITY_SALARY_TAX_INCOME_TITLE 都市の所得税の収入 +SALARY_TAX_INCOME 都市の所得税の収入 +TOURIST_INCOME_TITLE 2. 都市の観光収入 +FROM_RESIDENT 住民から +FROM_TOURIST 観光客から +LAND_TAX_INCOME_TITLE 3. 都市の地価税の収入 +RESIDENT_HIGH_LAND_INCOME 高密度住宅の地価収入 +RESIDENT_LOW_LAND_INCOME 低密度住宅の地価収入 +RESIDENT_HIGH_ECO_LAND_INCOME 高密度エコ住宅の地価収入 +RESIDENT_LOW_ECO_LAND_INCOME 低密度エコ住宅の地価収入 +COMMERICAL_HIGH_LAND_INCOME 高密度商業の地価収入 +COMMERICAL_LOW_LAND_INCOME 低密度商業の地価収入 +COMMERICAL_ECO_LAND_INCOME エコ特化商業の地価収入 +COMMERICAL_TOURISM_LAND_INCOME 観光特化商業の地価収入 +COMMERICAL_LEISURE_LAND_INCOME レジャー特化商業の地価収入 +INDUSTRIAL_GENERAL_LAND_INCOME 一般産業の地価収入 +INDUSTRIAL_FARMING_LAND_INCOME 農業特化産業の地価収入 +INDUSTRIAL_FORESTY_LAND_INCOME 林業特化産業の地価収入 +INDUSTRIAL_OIL_LAND_INCOME 石油特化産業の地価収入 +INDUSTRIAL_ORE_LAND_INCOME 鉱石特化産業の地価収入 +OFFICE_GENERAL_LAND_INCOME 一般オフィスの地価収入 +OFFICE_HIGH_TECH_LAND_INCOME ハイテクオフィスの地価収入 +CITY_TRADE_INCOME_TITLE 4. 都市の貿易関税の収入 +COMMERICAL_HIGH_TRADE_INCOME 高密度商業の貿易収入 +COMMERICAL_LOW_TRADE_INCOME 低密度商業の貿易収入 +COMMERICAL_ECO_TRADE_INCOME エコ特化商業の貿易収入 +COMMERICAL_TOURISM_TRADE_INCOME 観光特化商業の収入 +COMMERICAL_LEISURE_TRADE_INCOME レジャー特化商業の収入 +INDUSTRIAL_GENERAL_TRADE_INCOME 一般産業の収入 +INDUSTRIAL_FARMING_TRADE_INCOME 農業特化産業の収入 +INDUSTRIAL_FORESTY_TRADE_INCOME 林業特化産業の収入 +INDUSTRIAL_OIL_TRADE_INCOME 石油特化産業の収入 +INDUSTRIAL_ORE_TRADE_INCOME 鉱石特化産業の収入 +CITY_PUBLIC_TRANSPORT_INCOME_TITLE 5. 都市の公共交通の収入 +BUS バス +TRAM トラム +TRAIN 鉄道 +SHIP 船舶 +PLANE 飛行機 +METRO 地下鉄 +TAXI タクシー +CABLECAR ロープウェイ +MONORAIL モノレール +CITY_PLAYER_BUILDING_INCOME_TITLE 6. 都市の建物の収入 +ROAD 道路 (ガソリンスタンド付) +GARBAGE ゴミ処理 +SCHOOL 教育施設 +HEALTHCARE 健康管理 +FIRESTATION 消防施設 +POLICESTATION 警察施設 +PLAYERINDUSTRY 都市所有の産業 +CITY_TOTAL_INCOME_TITLE 7. 都市の総収入 +CITY_INCOME_DATA 都市の収入データ (₡) +PARLIAMENT_HALL 市役所 +PARLIAMENT_SEATS 市議会の議席数 +COMMUNIST 共産主義者 +GREEN 自然保護主義者 +SOCIALIST 社会主義者 +LIBERAL 自由主義者 +NATIONAL ナショナリズム主義者 +GOVERMENT 政府機関 +LEFT_UNION (左派の組合) +WIDE_LEFT_UNION (広域左派の組合) +RIGHT_UNION (右派の組合) +ALL_UNION (連合の組合) +NEXT_VOTE 次の投票 +CURRENT_MEETING_ITEM 現在の議題 +RISE_RESIDENT_TAX 住民税を上げる +FALL_RESIDENT_TAX 住民税を下げる +RISE_BENEFIT 手当を上げる +FALL_BENEFIT 手当を下げる +RISE_COMMERIAL_TAX 商業税を上げる +FALL_COMMERIAL_TAX 商業税を下げる +RISE_INDUSTRIAL_TAX 産業税を上げる +FALL_INDUSTRIAL_TAX 産業税を下げる +VOTE_RESULT 投票結果 +YES はい +NO いいえ +NO_ATTEND 参加しない +CURRENT_POLICY 現在の方針 +BENEFIT 手当て +RESIDENT_SALARY_TAX 住民税の収入 +COMMERICAL_TRADE_TAX 商業の貿易税 +INDUSTRIAL_TRADE_TAX 産業の貿易税 +BUILDING_MONEY 建物の資産 (1/100₡) +MATERIAL_BUFFER 原料の一時保管 +PRODUCTION_BUFFER 製品の一時保管 +AVERAGE_EMPLOYFEE 労働者の平均給与 +BUILDING_LANDRENT 建物の地代 +PROFIT-SHARING 利益の共有 +BUY_PRICE 平均購入価格 +SELL_PRICE 平均販売価格 +MATERIAL_DIV_PRODUCTION 原料/製品 +SELL_TAX 消費税 +PROFIT 販売利益 +EXCLUDE_VISIT_INCOME (訪問収入を除外) +FAMILY_STATUS 世帯の状況 +FOOD 食品 +COAL 石炭 +LUMBER 材木 +PETROL ガソリン/ガス +GRAIN_MEAT 穀物や肉 +ORE 鉱石 +LOG 丸太 +OIL 原油 +PREGOODS 先行商品 +GOODS 商品 +PRICE 価格 +ANIMALPRODUCTS 畜産物 +FLOURS 小麦粉 +PAPER 紙 +PLANEDTIMBER 製材 +PETROLEUM 石油 +PLASTICS プラスチック +GLASS ガラス +METALS 金属 +LUXURY_PRODUCTS 高級品 +FAMILY_MONEY 世帯の資産 (1/100₡) +CITIZEN_MONEY 市民の資産 (1/100₡) +FAMILY_SALARY 世帯の給与 +FAMILY_GOODS 家庭用品 +FAMILY_NEED_GOODS (家族の必須商品) +CAR_USED 自家用車を使用 +MAINTAIN_FEE_TIPS UIに表示される維持費は、車両の代金に含みません。 +LOCAL_WORKERS_DIV_TOTAL_WORKERS 現地の労働者 / 全ての労働者 +TOURIST_MONEY 観光客の交通費 +SHOW_LACK_OF_RESOURCE 売り切れ時の商業施設で、リソース不足のアイコンを表示 +DEBUG_MODE 詳しい情報 +REDUCE_CARGO_DESCRIPTION 貨物の量を削減 (DLC Industriesと区画内の建物両方) +REDUCE_CARGO_ENABLE 貨物の減少機能を有効化 +INCOMPATIBILITY_CHECK_TIP Real City(series) Mod が、互換性のないMODを検出しました! +REMOVE_STUCK_DESCRIPTION スタックした市民と車両を自動的に削除 (パフォーマンスに少し影響有り) +REMOVE_STUCK_ENABLE スタックした市民と車両を削除を有効化 +BASIC_SETTING 基本設定 +SPTB SPTB機能 +SMART_PUBLIC_TRANSPORT_BUDGET_WEEKDAY 効率的な公共交通の予算 (平日) +SMART_PUBLIC_TRANSPORT_BUDGET_WEEKEND 効率的な公共交通の予算 (週末) +WEEKDAY_MORNING_BUDGET 平日朝の予算 (8~10) +WEEKDAY_EVENING_BUDGET 平日夕方の予算 (17~19) +WEEKDAY_DEEPNIGHT_BUDGET 平日深夜の予算 (0~4) +WEEKDAY_OTHER_BUDGET 平日その他の予算 +WEEKEND_MORNING_BUDGET 週末朝の予算 (8~10) +WEEKEND_EVENING_BUDGET 週末夕方の予算 (17~19) +WEEKEND_DEEPNIGHT_BUDGET 週末深夜の予算 (0~4) +WEEKEND_OTHER_BUDGET 週末その他の予算 +WeekDayPlan 平日の案 +WeekEndPlan 週末の案 +NoPlan 計画無し +TLMRUNNING Transport Line Managerが動作中かReal Timeが実行していない場合は、SPTB機能が無効です。 +TLMNOTRUNNING Transport Line Managerが動作していないので、SPTB機能を使用可能です。 +MAX_MORNING_BUDGET 朝の最大予算 (8~10) +MAX_EVENING_BUDGET 夕方の最大予算 (17~19) +MAX_DEEPNIGHT_BUDGET 深夜の最大予算 (0~4) +MAX_OTHER_BUDGET その他の最大予算 +MIN_MORNING_BUDGET 朝の最小予算 (8~10) +MIN_EVENING_BUDGET 夕方の最小予算 (17~19) +MIN_DEEPNIGHT_BUDGET 深夜の最小予算 (0~4) +MIN_OTHER_BUDGET その他の最小予算 +MaxPlan 最大の案 +MinPlan 最小の案 +SPTB2 SPTB機能2 +SMART_PUBLIC_TRANSPORT_BUDGET_MAX 効率的な公共交通の予算 (最大) +SMART_PUBLIC_TRANSPORT_BUDGET_MIN 効率的な公共交通の予算 (最小) +RESET_VALUE リセットキー diff --git a/UI/BusinessBuildingUI.cs b/UI/BusinessBuildingUI.cs new file mode 100644 index 0000000..50bd746 --- /dev/null +++ b/UI/BusinessBuildingUI.cs @@ -0,0 +1,523 @@ +using System; +using ColossalFramework.UI; + +using System.Text; +using RealCity.Util; +using UnityEngine; +using ColossalFramework.Math; +using RealCity.CustomAI; +using RealCity.CustomData; +using ColossalFramework; + +namespace RealCity.UI +{ + class BusinessBuildingUI + { + private UILabel buildingMoney; + private UILabel buildingIncomeBuffer; + private UILabel buildingOutgoingBuffer; + private UILabel employFee; + private UILabel landRent; + private UILabel buyPrice; + private UILabel sellPrice; + private UILabel comsuptionDivide; + private UILabel sellTax; + private UILabel profit; + private UILabel usedcar; + private static readonly float SPACING = 15f; + private static readonly float SPACING22 = 22f; + + public BusinessBuildingUI(UIPanel parent) + { + buildingMoney = parent.AddUIComponent(); + buildingIncomeBuffer = parent.AddUIComponent(); + buildingOutgoingBuffer = parent.AddUIComponent(); + employFee = parent.AddUIComponent(); + landRent = parent.AddUIComponent(); + buyPrice = parent.AddUIComponent(); + sellPrice = parent.AddUIComponent(); + comsuptionDivide = parent.AddUIComponent(); + sellTax = parent.AddUIComponent(); + profit = parent.AddUIComponent(); + usedcar = parent.AddUIComponent(); + + buildingMoney.text = Localization.Get("BUILDING_MONEY"); + buildingMoney.relativePosition = new Vector3(SPACING, 50f); + buildingMoney.autoSize = true; + + buildingIncomeBuffer.text = Localization.Get("MATERIAL_BUFFER"); + buildingIncomeBuffer.relativePosition = new Vector3(SPACING, buildingMoney.relativePosition.y + SPACING22); + buildingIncomeBuffer.autoSize = true; + + buildingOutgoingBuffer.text = Localization.Get("PRODUCTION_BUFFER"); + buildingOutgoingBuffer.relativePosition = new Vector3(SPACING, buildingIncomeBuffer.relativePosition.y + SPACING22); + buildingOutgoingBuffer.autoSize = true; + + employFee.text = Localization.Get("AVERAGE_EMPLOYFEE"); + employFee.relativePosition = new Vector3(SPACING, buildingOutgoingBuffer.relativePosition.y + SPACING22); + employFee.autoSize = true; + + landRent.text = Localization.Get("BUILDING_LANDRENT"); + landRent.relativePosition = new Vector3(SPACING, employFee.relativePosition.y + SPACING22); + landRent.autoSize = true; + + buyPrice.text = Localization.Get("BUY_PRICE"); + buyPrice.relativePosition = new Vector3(SPACING, landRent.relativePosition.y + SPACING22); + buyPrice.autoSize = true; + + sellPrice.text = Localization.Get("SELL_PRICE"); + sellPrice.relativePosition = new Vector3(SPACING, buyPrice.relativePosition.y + SPACING22); + sellPrice.autoSize = true; + + comsuptionDivide.text = Localization.Get("MATERIAL_DIV_PRODUCTION"); + comsuptionDivide.relativePosition = new Vector3(SPACING, sellPrice.relativePosition.y + SPACING22); + comsuptionDivide.autoSize = true; + + sellTax.text = Localization.Get("SELL_TAX"); + sellTax.relativePosition = new Vector3(SPACING, comsuptionDivide.relativePosition.y + SPACING22); + sellTax.autoSize = true; + + profit.text = Localization.Get("PROFIT"); + profit.relativePosition = new Vector3(SPACING, sellTax.relativePosition.y + SPACING22); + profit.autoSize = true; + + usedcar.text = Localization.Get("CAR_USED"); + usedcar.relativePosition = new Vector3(SPACING, profit.relativePosition.y + SPACING22); + usedcar.autoSize = true; + } + + + public void Hide() + { + buildingMoney.Hide(); + buildingIncomeBuffer.Hide(); + buildingOutgoingBuffer.Hide(); + employFee.Hide(); + landRent.Hide(); + buyPrice.Hide(); + sellPrice.Hide(); + comsuptionDivide.Hide(); + sellTax.Hide(); + profit.Hide(); + usedcar.Hide(); + } + + public void Show() + { + buildingMoney.Show(); + buildingIncomeBuffer.Show(); + buildingOutgoingBuffer.Show(); + employFee.Show(); + landRent.Show(); + buyPrice.Show(); + sellPrice.Show(); + comsuptionDivide.Show(); + sellTax.Show(); + profit.Show(); + usedcar.Show(); + } + + public void Update(Building buildingData) + { + float averageEmployeeFee = CaculateEmployeeOutcome(buildingData, out int totalWorkerCount); + int landRentFee = CaculateLandFee(buildingData, BuildingData.lastBuildingID); + string incomeType = RealCityPrivateBuildingAI.GetProductionType(false, BuildingData.lastBuildingID, buildingData); + string outgoingType = RealCityPrivateBuildingAI.GetProductionType(true, BuildingData.lastBuildingID, buildingData); + float incomePrice = RealCityPrivateBuildingAI.GetPrice(false, BuildingData.lastBuildingID, buildingData); + float outgoingPrice = RealCityPrivateBuildingAI.GetPrice(true, BuildingData.lastBuildingID, buildingData); + buildingMoney.text = string.Format(Localization.Get("BUILDING_MONEY") + " [{0}]", BuildingData.buildingMoney[BuildingData.lastBuildingID]); + buildingIncomeBuffer.text = string.Format(Localization.Get("MATERIAL_BUFFER") + " [{0}]" + " " + incomeType, buildingData.m_customBuffer1); + buildingOutgoingBuffer.text = string.Format(Localization.Get("PRODUCTION_BUFFER") + " [{0}]" + " " + outgoingType, buildingData.m_customBuffer2); + employFee.text = Localization.Get("AVERAGE_EMPLOYFEE") + " " + averageEmployeeFee.ToString() + " " + Localization.Get("PROFIT_SHARING"); + landRent.text = string.Format(Localization.Get("BUILDING_LANDRENT") + " [{0:N2}]", landRentFee); + buyPrice.text = string.Format(Localization.Get("BUY_PRICE") + " " + incomeType + "[{0:N2}]", incomePrice); + sellPrice.text = string.Format(Localization.Get("SELL_PRICE") + " " + outgoingType + " [{0:N2}]", outgoingPrice); + + float consumptionDivider = 0f; + if (buildingData.Info.m_class.m_subService == ItemClass.SubService.IndustrialGeneric) + { + consumptionDivider = RealCityPrivateBuildingAI.GetComsumptionDivider(buildingData, BuildingData.lastBuildingID) * 4f; + comsuptionDivide.text = string.Format(Localization.Get("MATERIAL_DIV_PRODUCTION") + " [1:{0:N2}]", consumptionDivider); + } + else + { + if (buildingData.Info.m_buildingAI is IndustrialExtractorAI) + { + comsuptionDivide.text = string.Format(Localization.Get("MATERIAL_DIV_PRODUCTION") + " N/A"); + } + else + { + consumptionDivider = RealCityPrivateBuildingAI.GetComsumptionDivider(buildingData, BuildingData.lastBuildingID); + comsuptionDivide.text = string.Format(Localization.Get("MATERIAL_DIV_PRODUCTION") + " [1:{0:N2}]", consumptionDivider); + } + } + + int m_sellTax = RealCityPrivateBuildingAI.GetTaxRate(buildingData); + sellTax.text = string.Format(Localization.Get("SELL_TAX") + " [{0}%]", m_sellTax); + + if (consumptionDivider == 0f) + { + profit.text = string.Format(Localization.Get("SELL_TAX") + " N/A"); + } + else + { + float profitRatio = (outgoingPrice * (1f - m_sellTax / 100f) - (incomePrice / consumptionDivider)) / outgoingPrice; + if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) + { + profit.text = string.Format(Localization.Get("PROFIT") + " [{0}%]" + Localization.Get("EXCLUDE_VISIT_INCOME"), (int)(profitRatio * 100f)); + } + else + { + profit.text = string.Format(Localization.Get("PROFIT") + " [{0}%]", (int)(profitRatio * 100f)); + } + } + + int usedCar = 0; + int num = 0; + int num1 = 0; + int num2 = 0; + int car = 0; + if (buildingData.Info.m_class.m_service == ItemClass.Service.Industrial) + { + TransferManager.TransferReason tempReason = default(TransferManager.TransferReason); + if (buildingData.Info.m_buildingAI is IndustrialExtractorAI) + { + RealCityIndustrialExtractorAI.InitDelegate(); + var industrialExtractorAI = (IndustrialExtractorAI)buildingData.Info.m_buildingAI; + int productionCapacity = industrialExtractorAI.CalculateProductionCapacity((ItemClass.Level)buildingData.m_level, new Randomizer(BuildingData.lastBuildingID), buildingData.m_width, buildingData.m_length); + car = Mathf.Max(1, productionCapacity / 6); + tempReason = RealCityIndustrialExtractorAI.GetOutgoingTransferReason((IndustrialExtractorAI)buildingData.Info.m_buildingAI); + RealCityCommonBuildingAI.InitDelegate(); + RealCityCommonBuildingAI.CalculateOwnVehicles((IndustrialExtractorAI)buildingData.Info.m_buildingAI, BuildingData.lastBuildingID, ref buildingData, tempReason, ref usedCar, ref num, ref num1, ref num2); + } + else + { + RealCityIndustrialBuildingAI.InitDelegate(); + var industrialBuildingAI = (IndustrialBuildingAI)buildingData.Info.m_buildingAI; + int productionCapacity = industrialBuildingAI.CalculateProductionCapacity((ItemClass.Level)buildingData.m_level, new Randomizer(BuildingData.lastBuildingID), buildingData.m_width, buildingData.m_length); + car = Mathf.Max(1, productionCapacity / 6); + tempReason = RealCityIndustrialBuildingAI.GetOutgoingTransferReason((IndustrialBuildingAI)buildingData.Info.m_buildingAI); + RealCityCommonBuildingAI.InitDelegate(); + RealCityCommonBuildingAI.CalculateOwnVehicles((IndustrialBuildingAI)buildingData.Info.m_buildingAI, BuildingData.lastBuildingID, ref buildingData, tempReason, ref usedCar, ref num, ref num1, ref num2); + } + + usedcar.text = string.Format(Localization.Get("CAR_USED") + " [{0}/{1}]", usedCar, car); + } + else if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) + { + Citizen.BehaviourData behaviour = default; + int aliveVisitCount = 0; + int totalVisitCount = 0; + RealCityCommercialBuildingAI.InitDelegate(); + RealCityCommercialBuildingAI.GetVisitBehaviour((CommercialBuildingAI)(buildingData.Info.m_buildingAI), BuildingData.lastBuildingID, ref buildingData, ref behaviour, ref aliveVisitCount, ref totalVisitCount); + var amount = buildingData.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount; + var commercialBuildingAI = buildingData.Info.m_buildingAI as CommercialBuildingAI; + var maxCount = commercialBuildingAI.CalculateVisitplaceCount((ItemClass.Level)buildingData.m_level, new Randomizer(BuildingData.lastBuildingID), buildingData.m_width, buildingData.m_length); + usedcar.text = string.Format("FORDEBUG" + " [{0}/{1}/{2}/{3}]", aliveVisitCount, totalVisitCount, maxCount, amount); + } + else + { + usedcar.text = Localization.Get("CAR_USED") + " 0/0"; + } + } + + + public TransferManager.TransferReason IndustrialExtractorGetOutgoingTransferReason(Building data) + { + switch (data.Info.m_class.m_subService) + { + case ItemClass.SubService.IndustrialForestry: + return TransferManager.TransferReason.Logs; + case ItemClass.SubService.IndustrialFarming: + return TransferManager.TransferReason.Grain; + case ItemClass.SubService.IndustrialOil: + return TransferManager.TransferReason.Oil; + case ItemClass.SubService.IndustrialOre: + return TransferManager.TransferReason.Ore; + default: + return TransferManager.TransferReason.None; + } + } + + private TransferManager.TransferReason IndustrialGetOutgoingTransferReason(Building data) + { + switch (data.Info.m_class.m_subService) + { + case ItemClass.SubService.IndustrialForestry: + return TransferManager.TransferReason.Lumber; + case ItemClass.SubService.IndustrialFarming: + return TransferManager.TransferReason.Food; + case ItemClass.SubService.IndustrialOil: + return TransferManager.TransferReason.Petrol; + case ItemClass.SubService.IndustrialOre: + return TransferManager.TransferReason.Coal; + default: + return TransferManager.TransferReason.Goods; + } + } + + protected void CalculateOwnVehicles(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int count, ref int cargo, ref int capacity, ref int outside) + { + VehicleManager instance = Singleton.instance; + ushort num = data.m_ownVehicles; + int num2 = 0; + while (num != 0) + { + if ((TransferManager.TransferReason)instance.m_vehicles.m_buffer[num].m_transferType == material) + { + VehicleInfo info = instance.m_vehicles.m_buffer[num].Info; + int a; + int num3; + info.m_vehicleAI.GetSize(num, ref instance.m_vehicles.m_buffer[num], out a, out num3); + cargo += Mathf.Min(a, num3); + capacity += num3; + count++; + if ((instance.m_vehicles.m_buffer[num].m_flags & (Vehicle.Flags.Importing | Vehicle.Flags.Exporting)) != 0) + { + outside++; + } + } + num = instance.m_vehicles.m_buffer[num].m_nextOwnVehicle; + if (++num2 > 16384) + { + CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); + break; + } + } + } + + public int CalculateProductionCapacity(Building buildingData, ItemClass.Level level, Randomizer r, int width, int length) + { + ItemClass @class = buildingData.Info.m_class; + int num; + if (@class.m_subService == ItemClass.SubService.IndustrialGeneric) + { + if (level == ItemClass.Level.Level1) + { + num = 100; + } + else if (level == ItemClass.Level.Level2) + { + num = 140; + } + else + { + num = 160; + } + } + else + { + num = 100; + } + if (num != 0) + { + num = Mathf.Max(100, width * length * num + r.Int32(100u)) / 100; + } + return num; + } + + + public static float CaculateEmployeeOutcome(Building building, out int totalWorkerCount) + { + totalWorkerCount = 0; + float allSalary = 0; + CitizenManager instance = Singleton.instance; + uint num = building.m_citizenUnits; + int num2 = 0; + while (num != 0u) + { + if ((ushort)(instance.m_units.m_buffer[(int)((UIntPtr)num)].m_flags & CitizenUnit.Flags.Work) != 0) + { + var citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen0; + if (citizenID != 0u) + { + totalWorkerCount++; + allSalary += RealCityResidentAI.ProcessCitizenSalary(citizenID, true); + } + citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen1; + if (citizenID != 0u) + { + totalWorkerCount++; + allSalary += RealCityResidentAI.ProcessCitizenSalary(citizenID, true); + } + citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen2; + if (citizenID != 0u) + { + totalWorkerCount++; + allSalary += RealCityResidentAI.ProcessCitizenSalary(citizenID, true); + } + citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen3; + if (citizenID != 0u) + { + totalWorkerCount++; + allSalary += RealCityResidentAI.ProcessCitizenSalary(citizenID, true); + } + citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen4; + if (citizenID != 0u) + { + totalWorkerCount++; + allSalary += RealCityResidentAI.ProcessCitizenSalary(citizenID, true); + } + } + num = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_nextUnit; + if (++num2 > 524288) + { + CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); + break; + } + } + + if (totalWorkerCount == 0) + return 0; + else + return allSalary / totalWorkerCount; + } + + public static void GetWorkBehaviour(ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount) + { + CitizenManager instance = Singleton.instance; + uint num = buildingData.m_citizenUnits; + int num2 = 0; + while (num != 0u) + { + if ((ushort)(instance.m_units.m_buffer[(int)((UIntPtr)num)].m_flags & CitizenUnit.Flags.Work) != 0) + { + instance.m_units.m_buffer[(int)((UIntPtr)num)].GetCitizenWorkBehaviour(ref behaviour, ref aliveCount, ref totalCount); + } + num = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_nextUnit; + if (++num2 > 524288) + { + CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); + break; + } + } + } + + + public int CaculateLandFee(Building building, ushort buildingID) + { + DistrictManager instance = Singleton.instance; + byte district = instance.GetDistrict(building.m_position); + DistrictPolicies.Services servicePolicies = instance.m_districts.m_buffer[district].m_servicePolicies; + DistrictPolicies.Taxation taxationPolicies = instance.m_districts.m_buffer[district].m_taxationPolicies; + DistrictPolicies.CityPlanning cityPlanningPolicies = instance.m_districts.m_buffer[district].m_cityPlanningPolicies; + + GetLandRent(building, out int landFee); + int taxRate; + taxRate = Singleton.instance.GetTaxRate(building.Info.m_class, taxationPolicies); + + if (instance.IsPolicyLoaded(DistrictPolicies.Policies.ExtraInsulation)) + { + if ((servicePolicies & DistrictPolicies.Services.ExtraInsulation) != DistrictPolicies.Services.None) + { + taxRate = taxRate * 95 / 100; + } + } + if ((servicePolicies & DistrictPolicies.Services.Recycling) != DistrictPolicies.Services.None) + { + taxRate = taxRate * 95 / 100; + } + + if (((taxationPolicies & DistrictPolicies.Taxation.DontTaxLeisure) != DistrictPolicies.Taxation.None) && (building.Info.m_class.m_subService == ItemClass.SubService.CommercialLeisure)) + { + landFee = 0; + } + + if (BuildingData.buildingMoney[buildingID] > 0) + { + if ((building.Info.m_class.m_service == ItemClass.Service.Commercial) || (building.Info.m_class.m_service == ItemClass.Service.Industrial)) + { + if (BuildingData.buildingMoney[buildingID] > (taxRate * landFee / 100f)) + return (int)(taxRate * landFee / 100f); + else + return 0; + } + else if (building.Info.m_class.m_service == ItemClass.Service.Office) + { + Citizen.BehaviourData behaviourData = default; + int aliveWorkerCount = 0; + int totalWorkerCount = 0; + RealCityCommonBuildingAI.InitDelegate(); + RealCityCommonBuildingAI.GetWorkBehaviour((OfficeBuildingAI)building.Info.m_buildingAI, buildingID, ref building, ref behaviourData, ref aliveWorkerCount, ref totalWorkerCount); + return (int)(totalWorkerCount * taxRate / 10f); + } + } + + return 0; + } + + public void GetLandRent(Building building, out int incomeAccumulation) + { + ItemClass @class = building.Info.m_class; + incomeAccumulation = 0; + ItemClass.SubService subService = @class.m_subService; + switch (subService) + { + case ItemClass.SubService.IndustrialFarming: + incomeAccumulation = MainDataStore.induFarm; + break; + case ItemClass.SubService.IndustrialForestry: + incomeAccumulation = MainDataStore.induForest; + break; + case ItemClass.SubService.IndustrialOil: + incomeAccumulation = MainDataStore.induOil; + break; + case ItemClass.SubService.IndustrialOre: + incomeAccumulation = MainDataStore.induOre; + break; + case ItemClass.SubService.IndustrialGeneric: + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { + incomeAccumulation = MainDataStore.induGenLevel1; + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { + incomeAccumulation = MainDataStore.induGenLevel2; + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { + incomeAccumulation = MainDataStore.induGenLevel3; + } + break; + case ItemClass.SubService.CommercialHigh: + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { + incomeAccumulation = MainDataStore.commHighLevel1; + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { + incomeAccumulation = MainDataStore.commHighLevel2; + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { + incomeAccumulation = MainDataStore.commHighLevel3; + } + break; + case ItemClass.SubService.CommercialLow: + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { + incomeAccumulation = MainDataStore.commLowLevel1; + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { + incomeAccumulation = MainDataStore.commLowLevel2; + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { + incomeAccumulation = MainDataStore.commLowLevel3; + } + break; + case ItemClass.SubService.CommercialLeisure: + incomeAccumulation = MainDataStore.commLeisure; + break; + case ItemClass.SubService.CommercialTourist: + incomeAccumulation = MainDataStore.commTourist; + break; + case ItemClass.SubService.CommercialEco: + incomeAccumulation = MainDataStore.commEco; + break; + default: break; + } + } + } +} diff --git a/nuget.exe b/nuget.exe new file mode 100644 index 0000000..212f26c Binary files /dev/null and b/nuget.exe differ