/// <summary> /// モード設定の1ブロックの文字列から設定を抽出 /// </summary> /// <param name="modeLines"></param> private Mode(List <string> modeLines) { Name = ApplicationUtil.ExtractModProperty(modeLines, "#mode"); Year = int.Parse(ApplicationUtil.ExtractModProperty(modeLines, "year")); Money = long.Parse(ApplicationUtil.ExtractModProperty(modeLines, "money")); Message = ApplicationUtil.ExtractModProperty(modeLines, "message").Replace(',', '\n'); MYear = int.Parse(ApplicationUtil.ExtractModProperty(modeLines, "myear")); DefautltCompositions = ApplicationUtil.ExtractModProperties(modeLines, "car").Select(value => { string[] arr = value.Split(","); int ck = int.Parse(arr[2]); //編成規格 bool isLinear = (ck & 32) > 0; bool isDiesel = (ck & 16) > 0; bool isElectric = (ck & 8) > 0; bool isSteam = (ck & 4) > 0; bool isNarrow = (ck & 1) > 0; bool isRegular = (ck & 2) > 0; bool isPendulum = (ck & 64) > 0; bool isFreeGauge = (ck & 128) > 0; RailTypeEnum railType = isLinear ? RailTypeEnum.LinearMotor : RailTypeEnum.Iron; CarGaugeEnum?carGauge = isLinear ? (CarGaugeEnum?)null : isNarrow ? CarGaugeEnum.Narrow : isRegular ? CarGaugeEnum.Regular : isFreeGauge ? CarGaugeEnum.FreeGauge : throw new ArgumentException("軌間が未定義です"); PowerEnum powerSource = isLinear ? PowerEnum.LinearMotor : isElectric ? PowerEnum.Electricity : isDiesel ? PowerEnum.Diesel : isSteam ? PowerEnum.Steam : throw new ArgumentException("動力源が未指定です"); return(new DefautltComposition { Name = arr[0], BestSpeed = int.Parse(arr[1]), CarCount = int.Parse(arr[3]), HeldUnits = int.Parse(arr[4]), Price = int.Parse(arr[5]), seat = LogicUtil.ConvertSeatModToInternalId(int.Parse(arr[6])), Gauge = carGauge, Power = powerSource, Tilt = isPendulum ? CarTiltEnum.Pendulum : CarTiltEnum.None, Type = railType }); }).ToList(); }
/// <summary> /// モード設定文字列からモードオブジェクト作成 /// </summary> /// <param name="modeLines"></param> /// <returns></returns> private static Mode CreateMode(List <string> modeLines) { Mode mode = new Mode(); //ゲーム設定 mode.Name = ExtractModProperty(modeLines, "#mode"); mode.Year = int.Parse(ExtractModProperty(modeLines, "year")); mode.Money = long.Parse(ExtractModProperty(modeLines, "money")); mode.Message = ExtractModProperty(modeLines, "message").Replace(',', '\n'); mode.MYear = int.Parse(ExtractModProperty(modeLines, "myear")); mode.genkaiJoki = ParseIntOrNull(ExtractModProperty(modeLines, "steam")) ?? 40; mode.genkaiDenki = ParseIntOrNull(ExtractModProperty(modeLines, "elect")); mode.genkaiKidosha = ParseIntOrNull(ExtractModProperty(modeLines, "diesel")); mode.genkaiLinear = ParseIntOrNull(ExtractModProperty(modeLines, "linear")); var tecno = ParseIntOrNull(ExtractModProperty(modeLines, "tecno")); if (tecno.HasValue) { int tecnoV = tecno.Value; if ((tecnoV & 256) > 0) //動的信号 { mode.isDevelopedDynamicSignal = true; mode.isDevelopedFreeGauge = true; mode.isDevelopedMachineTilt = true; mode.isDevelopedDualSeat = true; mode.isDevelopedRetructableLong = true; mode.isDevelopedRichCross = true; mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 4) > 0) //フリーゲージトレイン { mode.isDevelopedFreeGauge = true; mode.isDevelopedMachineTilt = true; mode.isDevelopedDualSeat = true; mode.isDevelopedRetructableLong = true; mode.isDevelopedRichCross = true; mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 512) > 0) //機械式車体傾斜装置 { mode.isDevelopedMachineTilt = true; mode.isDevelopedDualSeat = true; mode.isDevelopedRetructableLong = true; mode.isDevelopedRichCross = true; mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 8) > 0) //デュアルシート { mode.isDevelopedDualSeat = true; mode.isDevelopedRetructableLong = true; mode.isDevelopedRichCross = true; mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 32) > 0) //収納式ロングシート { mode.isDevelopedRetructableLong = true; mode.isDevelopedRichCross = true; mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 16) > 0) //豪華クロスシート { mode.isDevelopedRichCross = true; mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 1) > 0) //振り子式車体傾斜装置 { mode.isDevelopedCarTiltPendulum = true; mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 128) > 0) //自動改札機 { mode.isDevelopedAutoGate = true; mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 64) > 0) //転換クロスシート { mode.isDevelopedConvertibleCross = true; mode.isDevelopedBlockingSignal = true; } else if ((tecnoV & 2) > 0) //閉塞信号 { mode.isDevelopedBlockingSignal = true; } } int[] people = ExtractModProperty(modeLines, "people")?.Split(",").Select(it => int.Parse(it)).Take(2).ToArray() ?? new int[] { 1, 1 }; if (people.Count() == 2) { mode.peopleNume = people[0]; mode.peopleDenom = people[1]; } //デフォルト編成 mode.DefautltCompositions = ExtractModProperties(modeLines, "car").Select(value => { string[] arr = value.Split(","); int ck = int.Parse(arr[2]); //編成規格 bool isLinear = (ck & 32) > 0; bool isDiesel = (ck & 16) > 0; bool isElectric = (ck & 8) > 0; bool isSteam = (ck & 4) > 0; bool isNarrow = (ck & 1) > 0; bool isRegular = (ck & 2) > 0; bool isPendulum = (ck & 64) > 0; bool isFreeGauge = (ck & 128) > 0; RailTypeEnum railType = isLinear ? RailTypeEnum.LinearMotor : RailTypeEnum.Iron; CarGaugeEnum?carGauge = isLinear ? (CarGaugeEnum?)null : isNarrow ? CarGaugeEnum.Narrow : isRegular ? CarGaugeEnum.Regular : isFreeGauge ? CarGaugeEnum.FreeGauge : throw new ArgumentException("軌間が未定義です"); PowerEnum powerSource = isLinear ? PowerEnum.LinearMotor : isElectric ? PowerEnum.Electricity : isDiesel ? PowerEnum.Diesel : isSteam ? PowerEnum.Steam : throw new ArgumentException("動力源が未指定です"); return(new DefautltComposition { Name = arr[0], BestSpeed = int.Parse(arr[1]), CarCount = int.Parse(arr[3]), HeldUnits = int.Parse(arr[4]), Price = int.Parse(arr[5]), seat = LogicUtil.ConvertSeatModToInternalId(int.Parse(arr[6])), Gauge = carGauge, Power = powerSource, Tilt = isPendulum ? CarTiltEnum.Pendulum : CarTiltEnum.None, Type = railType }); }).ToList(); //路線 List <LineDefaultSetting> lineDefaultSettings = new List <LineDefaultSetting>(); bool[] ltn = ExtractModProperty(modeLines, "ltn")?.Split(",").Select(flg => int.Parse(flg) != 0).ToArray() ?? new bool[0]; int[] lk = ExtractModProperty(modeLines, "lk")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[ltn.Length]; int[] lbs = ExtractModProperty(modeLines, "lbs")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[ltn.Length]; int[] las = ExtractModProperty(modeLines, "las")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[ltn.Length]; int[] lwe = ExtractModProperty(modeLines, "lwe")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? Enumerable.Repeat(GameConstants.RetentionRateDefault, ltn.Length).ToArray(); int[] lts = ExtractModProperty(modeLines, "lts")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[ltn.Length]; int[] ulc = ExtractModProperty(modeLines, "ulc")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? null; int[] ulcr = ExtractModProperty(modeLines, "ulcr")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[ltn.Length]; for (int i = 0; i < ltn.Length; i++) { LineDefaultSetting setting = new LineDefaultSetting(); setting.IsExist = ltn[i]; if (setting.IsExist) { if (i < lk.Length) { setting.Type = (lk[i] & 4) > 0 ? RailTypeEnum.LinearMotor : RailTypeEnum.Iron; setting.gauge = (lk[i] & 1) > 0 ? RailGaugeEnum.Regular : RailGaugeEnum.Narrow; setting.IsElectrified = (lk[i] & 2) > 0; } if (i < lbs.Length) { setting.bestSpeed = lbs[i]; } if (i < las.Length) { setting.LaneNum = las[i]; } if (i < lwe.Length) { setting.retentionRate = lwe[i]; } if (i < lts.Length) { setting.taihisen = (TaihisenEnum)lts[i]; } if (ulc != null) { setting.useComposition = mode.DefautltCompositions[ulc[i] - 1]; } if (i < ulcr.Length) { setting.runningPerDay = ulcr[i]; } } lineDefaultSettings.Add(setting); } mode.LineSettings = lineDefaultSettings; //運行系統 List <KeitoDefaultSetting> keitoDefaultSettings = new List <KeitoDefaultSetting>(); int[] udc = ExtractModProperty(modeLines, "udc")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[0]; int[] udcr = ExtractModProperty(modeLines, "udcr")?.Split(",").Select(value => int.Parse(value)).ToArray() ?? new int[udc.Length]; for (int i = 0; i < udc.Length; i++) { KeitoDefaultSetting setting = new KeitoDefaultSetting() { useComposition = mode.DefautltCompositions[udc[i] - 1], runningPerDay = udcr[i] }; keitoDefaultSettings.Add(setting); } mode.KeitoDefaultSettings = keitoDefaultSettings; //目標 mode.goalLineMake = (LineGoalTargetEnum?)ParseIntOrNull(ExtractModProperty(modeLines, "mmake")); mode.goalTechDevelop = ExtractModProperties(modeLines, "mtec").ToDictionary( value => (PowerEnum)(int.Parse(value.Split(",")[0]) - 1), value => int.Parse(value.Split(",")[1])); string[] mlbsValues = ExtractModProperty(modeLines, "mlbs")?.Split(",") ?? null; if (mlbsValues != null) { mode.goalLineBestSpeed = ((LineGoalTargetEnum?)ParseIntOrNull(mlbsValues[0]), int.Parse(mlbsValues[1])); } string[] mmanegeValues = ExtractModProperty(modeLines, "mmanage")?.Split(",") ?? null; if (mmanegeValues != null) { mode.goalLineManage = (LineGoalTargetEnum?)ParseIntOrNull(mmanegeValues[0]); } mode.goalMoney = ParseIntOrNull(ExtractModProperty(modeLines, "mmoney")); mode.gameoverYear = int.Parse(ExtractModProperty(modeLines, "myear")); return(mode); }
/// <summary> /// 路線建造コスト計算ロジック /// </summary> /// <param name="bestSpeed"></param> /// <param name="laneSu"></param> /// <param name="distance"></param> /// <param name="railType"></param> /// <param name="railGauge"></param> /// <param name="isElectrified"></param> /// <param name="taihisen"></param> /// <param name="lineProperty"></param> /// <param name="gameInfo"></param> /// <returns></returns> public static long CalcLineConstructionCost( int bestSpeed, int laneSu, int distance, RailTypeEnum railType, RailGaugeEnum?railGauge, bool?isElectrified, TaihisenEnum taihisen, LinePropertyType lineProperty, GameInfo gameInfo) { if (gameInfo is null) { throw new ArgumentNullException(nameof(gameInfo)); } int railCostKeisu = gameInfo.LineMakeCost, year = gameInfo.Year, basicYear = gameInfo.BasicYear, economicIndex = gameInfo.CalcEconomicIndex(); long railCost; long taihiCost; int taihiKeisu; if (laneSu == 3) { laneSu = 4; } switch (lineProperty) { case LinePropertyType.JapaneseInterCity: railCost = (bestSpeed + 40) * (laneSu + 1) * (distance + 10) * 4; taihiKeisu = 400; break; case LinePropertyType.Surburb: railCost = (bestSpeed + 40) * (laneSu) * (distance + 1) * 6; taihiKeisu = 500; break; case LinePropertyType.Outskirts: railCost = (bestSpeed + 40) * (laneSu) * (distance + 1) * 8; taihiKeisu = 700; break; case LinePropertyType.Plain: railCost = (bestSpeed + 200) * (laneSu + 1) * (distance + 10) * 4 / 3; taihiKeisu = 300; break; case LinePropertyType.Mountain: if (bestSpeed > 80) { railCost = (bestSpeed + 200) * (laneSu + 1) * (distance + 10) * 4; taihiKeisu = 500; } else { railCost = (bestSpeed + 40) * (laneSu + 1) * (distance + 10) * 4; taihiKeisu = 400; } break; case LinePropertyType.Alpine: if (bestSpeed > 60) { railCost = (bestSpeed + 200) * (laneSu + 1) * (distance + 10) * 5; taihiKeisu = 550; } else { railCost = (bestSpeed + 30) * (laneSu + 1) * (distance + 10) * 5; taihiKeisu = 450; } break; case LinePropertyType.Sea: if (bestSpeed > 40) { railCost = (bestSpeed + 500) * (laneSu + 1) * (distance + 10) * 5; taihiKeisu = 800; } else { railCost = 240 * (laneSu + 1) * (distance + 10) * 5; taihiKeisu = 500; } break; case LinePropertyType.RussianPlain: railCost = (bestSpeed + 500) * (laneSu + 1) / 7 * (distance + 20) * 4; taihiKeisu = 200; break; case LinePropertyType.Underground: if (bestSpeed > 40) { railCost = (bestSpeed + 200) * (laneSu + 1) * (distance + 10) * 8; taihiKeisu = 200; } else { railCost = 240 * (laneSu + 1) * (distance + 10); taihiKeisu = 500; } break; default: throw new ArgumentException($"引数の内容が誤りです 内容:{lineProperty}", nameof(lineProperty)); } //標準軌、リニア if (railType == RailTypeEnum.LinearMotor || railGauge == RailGaugeEnum.Regular) { railCost = railCost * 6 / 5; } //電化(リニアは電化) if (railType == RailTypeEnum.LinearMotor || isElectrified.GetValueOrDefault(true)) { railCost = railCost * 3 / 2; } //リニア地下鉄(都営大江戸線、福岡市営地下鉄七隈線みたいな) if (lineProperty == LinePropertyType.Underground && railType == RailTypeEnum.LinearMotor && bestSpeed < 200) { railCost /= 2; } switch (taihisen) { case TaihisenEnum.None: taihiCost = 0; break; case TaihisenEnum.Every100km: taihiCost = (distance / 100 + 1) * taihiKeisu * laneSu; break; case TaihisenEnum.Every50km: taihiCost = (distance / 50 + 1) * taihiKeisu * laneSu; break; case TaihisenEnum.Every20km: taihiCost = (distance / 20 + 1) * taihiKeisu * laneSu; break; case TaihisenEnum.Every10km: taihiCost = (distance / 10 + 1) * taihiKeisu * laneSu; break; case TaihisenEnum.Every5km: taihiCost = (distance / 5 + 1) * taihiKeisu * laneSu; break; case TaihisenEnum.Every2km: taihiCost = (distance / 2 + 1) * taihiKeisu * laneSu; break; default: throw new ArgumentException($"引数の内容が誤りです 内容:{taihisen}", nameof(taihisen)); } var totalCost = railCost + taihiCost; return(totalCost / 100 * railCostKeisu / 188 * (year / 10 - basicYear / 10 + 188) / 10 * economicIndex / 10); }