예제 #1
0
 /// <summary>
 ///     componentセクションを書き出す
 /// </summary>
 /// <param name="component">小研究データ</param>
 /// <param name="writer">ファイル書き込み用</param>
 private static void WriteComponent(TechComponent component, StreamWriter writer)
 {
     writer.WriteLine("    # {0}", Config.ExistsKey(component.Name) ? Config.GetText(component.Name) : "");
     writer.Write(
         "    component = {{ id = {0} name = {1} type = {2} difficulty = {3}",
         component.Id,
         component.Name,
         Techs.SpecialityStrings[(int)component.Speciality],
         component.Difficulty);
     if (component.DoubleTime)
     {
         writer.Write(" double_time = yes");
     }
     writer.WriteLine(" }");
 }
예제 #2
0
        /// <summary>
        ///     componentセクションを構文解析する
        /// </summary>
        /// <param name="lexer">字句解析器</param>
        /// <returns>小研究データ</returns>
        private static TechComponent ParseComponent(TextLexer lexer)
        {
            // =
            Token token = lexer.GetToken();

            if (token.Type != TokenType.Equal)
            {
                Log.InvalidToken(LogCategory, token, lexer);
                return(null);
            }

            // {
            token = lexer.GetToken();
            if (token.Type != TokenType.OpenBrace)
            {
                Log.InvalidToken(LogCategory, token, lexer);
                return(null);
            }

            TechComponent component = new TechComponent();

            while (true)
            {
                token = lexer.GetToken();

                // ファイルの終端
                if (token == null)
                {
                    break;
                }

                // } (セクション終端)
                if (token.Type == TokenType.CloseBrace)
                {
                    break;
                }

                // 無効なトークン
                if (token.Type != TokenType.Identifier)
                {
                    Log.InvalidToken(LogCategory, token, lexer);
                    lexer.SkipLine();
                    continue;
                }

                string keyword = token.Value as string;
                if (string.IsNullOrEmpty(keyword))
                {
                    continue;
                }
                keyword = keyword.ToLower();

                // id
                if (keyword.Equals("id"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Number)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 小研究ID
                    component.Id = (int)(double)token.Value;
                    continue;
                }

                // name
                if (keyword.Equals("name"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Identifier && token.Type != TokenType.String)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 小研究名
                    component.Name = token.Value as string;
                    continue;
                }

                // type
                if (keyword.Equals("type"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Identifier)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効な研究特性文字列
                    string s = token.Value as string;
                    if (string.IsNullOrEmpty(s))
                    {
                        continue;
                    }
                    s = s.ToLower();
                    if (!Techs.SpecialityStringMap.ContainsKey(s))
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 小研究特性
                    component.Speciality = Techs.SpecialityStringMap[s];
                    continue;
                }

                // difficulty
                if (keyword.Equals("difficulty"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Number)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 難易度
                    component.Difficulty = (int)(double)token.Value;
                    continue;
                }

                // double_time
                if (keyword.Equals("double_time"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Identifier)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    string s = token.Value as string;
                    if (string.IsNullOrEmpty(s))
                    {
                        continue;
                    }
                    s = s.ToLower();

                    if (s.Equals("yes"))
                    {
                        // 倍の時間を要するかどうか
                        component.DoubleTime = true;
                        continue;
                    }

                    if (s.Equals("no"))
                    {
                        // 倍の時間を要するかどうか
                        component.DoubleTime = false;
                        continue;
                    }

                    // 無効なトークン
                    Log.InvalidToken(LogCategory, token, lexer);
                    lexer.SkipLine();
                    continue;
                }

                // 無効なトークン
                Log.InvalidToken(LogCategory, token, lexer);
                lexer.SkipLine();
            }

            return(component);
        }
예제 #3
0
        /// <summary>
        ///     applicationセクションを構文解析する
        /// </summary>
        /// <param name="lexer">字句解析器</param>
        /// <returns>技術データ</returns>
        private static TechItem ParseApplication(TextLexer lexer)
        {
            // =
            Token token = lexer.GetToken();

            if (token.Type != TokenType.Equal)
            {
                Log.InvalidToken(LogCategory, token, lexer);
                return(null);
            }

            // {
            token = lexer.GetToken();
            if (token.Type != TokenType.OpenBrace)
            {
                Log.InvalidToken(LogCategory, token, lexer);
                return(null);
            }

            TechItem application = new TechItem();

            while (true)
            {
                token = lexer.GetToken();

                // ファイルの終端
                if (token == null)
                {
                    break;
                }

                // } (セクション終端)
                if (token.Type == TokenType.CloseBrace)
                {
                    break;
                }

                // 無効なトークン
                if (token.Type != TokenType.Identifier)
                {
                    Log.InvalidToken(LogCategory, token, lexer);
                    lexer.SkipLine();
                    continue;
                }

                string keyword = token.Value as string;
                if (string.IsNullOrEmpty(keyword))
                {
                    continue;
                }
                keyword = keyword.ToLower();

                // id
                if (keyword.Equals("id"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Number)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 技術ID
                    application.Id = (int)(double)token.Value;
                    continue;
                }

                // name
                if (keyword.Equals("name"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Identifier && token.Type != TokenType.String)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 技術名
                    application.Name = token.Value as string;

                    // 短縮名
                    application.ShortName = "SHORT_" + application.Name;
                    continue;
                }

                // desc
                if (keyword.Equals("desc"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Identifier && token.Type != TokenType.String)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 技術説明
                    application.Desc = token.Value as string;
                    continue;
                }

                // position
                if (keyword.Equals("position"))
                {
                    TechPosition position = ParsePosition(lexer);
                    if (position == null)
                    {
                        Log.InvalidSection(LogCategory, "position", lexer);
                        continue;
                    }

                    // 座標リスト
                    application.Positions.Add(position);
                    continue;
                }

                // picture
                if (keyword.Equals("picture"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.String)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 画像ファイル名
                    application.PictureName = token.Value as string;
                    continue;
                }

                // year
                if (keyword.Equals("year"))
                {
                    // =
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Equal)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 無効なトークン
                    token = lexer.GetToken();
                    if (token.Type != TokenType.Number)
                    {
                        Log.InvalidToken(LogCategory, token, lexer);
                        lexer.SkipLine();
                        continue;
                    }

                    // 史実年
                    application.Year = (int)(double)token.Value;
                    continue;
                }

                // component
                if (keyword.Equals("component"))
                {
                    TechComponent component = ParseComponent(lexer);
                    if (component == null)
                    {
                        Log.InvalidSection(LogCategory, "component", lexer);
                        continue;
                    }

                    // 小研究
                    application.Components.Add(component);
                    continue;
                }

                // required
                if (keyword.Equals("required"))
                {
                    IEnumerable <int> ids = ParseRequired(lexer);
                    if (ids == null)
                    {
                        Log.InvalidSection(LogCategory, "required", lexer);
                        continue;
                    }

                    // 必要とする技術群(AND)
                    foreach (int id in ids)
                    {
                        RequiredTech tech = new RequiredTech {
                            Id = id
                        };
                        application.AndRequiredTechs.Add(tech);
                    }
                    continue;
                }

                // or_required
                if (keyword.Equals("or_required"))
                {
                    IEnumerable <int> ids = ParseRequired(lexer);
                    if (ids == null)
                    {
                        Log.InvalidSection(LogCategory, "or_required", lexer);
                        continue;
                    }

                    // 必要とする技術群(OR)
                    foreach (int id in ids)
                    {
                        RequiredTech tech = new RequiredTech {
                            Id = id
                        };
                        application.OrRequiredTechs.Add(tech);
                    }
                    continue;
                }

                // effects
                if (keyword.Equals("effects"))
                {
                    IEnumerable <Command> commands = ParseEffects(lexer);
                    if (commands == null)
                    {
                        Log.InvalidSection(LogCategory, "effects", lexer);
                        continue;
                    }

                    // 技術効果
                    application.Effects.AddRange(commands);
                    continue;
                }

                // 無効なトークン
                Log.InvalidToken(LogCategory, token, lexer);
                lexer.SkipLine();
            }

            return(application);
        }
예제 #4
0
        /// <summary>
        ///     研究速度の基本進捗率を取得する
        /// </summary>
        /// <param name="component">小研究</param>
        /// <param name="team">研究機関</param>
        /// <returns>研究速度の基本進捗率</returns>
        private static double GetBaseProgress(TechComponent component, Team team)
        {
            int d = component.Difficulty + 2;
            int s = team.Skill;

            // 特性が一致する場合はスキルを倍にして6を加える
            if (team.Specialities.Contains(component.Speciality))
            {
                s += team.Skill + 6;
            }

            // 研究施設がある場合は施設の規模を設定する
            int t = 0;

            switch (component.Speciality)
            {
            case TechSpeciality.Rocketry:
                t = Researches.RocketTestingSites;
                break;

            case TechSpeciality.NuclearPhysics:
            case TechSpeciality.NuclearEngineering:
                t = Researches.NuclearReactors;
                break;
            }

            // ゲームごとの基本進捗率を取得する
            double progress;

            switch (Game.Type)
            {
            case GameType.HeartsOfIron2:
                progress = (9.3 + 1.5 * s + 10 * t) / d;
                break;

            case GameType.ArsenalOfDemocracy:
                progress = (3.0 + 0.5 * (s + 10 * Math.Sqrt(t))) / d;
                break;

            case GameType.DarkestHour:
                progress = (9.0 + 1.5 * (s + 5.62 * t)) / d;
                break;

            default:
                // ゲームの種類が不明な場合はHoI2として扱う
                progress = (9.3 + 1.5 * s + 10 * t) / d;
                break;
            }

            // 2倍時間設定の場合は進捗率半分として扱う
            if (component.DoubleTime)
            {
                progress /= 2;
            }

            // 青写真補正
            if (Researches.Blueprint)
            {
                progress *= Misc.BlueprintBonus;
            }

            // AoDの場合Miscの補正を考慮
            if (Game.Type == GameType.ArsenalOfDemocracy)
            {
                progress *= Misc.TechSpeedModifier;
            }

            // その他諸々の補正(計算機技術/閣僚/難易度/シナリオ設定など)
            progress *= Researches.Modifier;

            return(progress);
        }
예제 #5
0
        /// <summary>
        ///     小研究に必要な日数を取得する
        /// </summary>
        /// <param name="component">小研究</param>
        /// <param name="offset">史実年度との差分日数</param>
        /// <param name="team">研究機関</param>
        /// <returns>日数</returns>
        private static int GetComponentDays(TechComponent component, int offset, Team team)
        {
            int    totalDays     = 0;
            double totalProgress = 0;

            // 基準となる進捗率を求める
            double baseProgress = GetBaseProgress(component, team);

            // STEP1: 史実年度前ペナルティ下限値で研究する日数を求める
            if ((offset < 0) && (Misc.PreHistoricalDateModifier < 0))
            {
                // 史実年度前ペナルティを求める
                double preHistoricalModifier = Misc.PreHistoricalDateModifier;

                // 史実年度前ペナルティの下限値を求める
                double preHistoricalLimit = Game.Type == GameType.ArsenalOfDemocracy
                    ? Misc.PreHistoricalPenaltyLimit
                    : 0.1;

                // 史実年度前ペナルティが下限値になる日を求める
                int preHistoricalLimitOffset = (int)Math.Floor((1 - preHistoricalLimit) / preHistoricalModifier);

                // 差分日数が下限値日数を超える場合
                if (offset <= preHistoricalLimitOffset)
                {
                    // 下限値で研究完了する日数を求める
                    int preHistoricalLimitDays = (int)Math.Ceiling(100 / (baseProgress * preHistoricalLimit));

                    // 下限値で研究完了する場合は日数を返す
                    if (offset + preHistoricalLimitDays <= preHistoricalLimitOffset)
                    {
                        return(preHistoricalLimitDays);
                    }

                    // 下限値で研究する日数と進捗を加算する
                    preHistoricalLimitDays = preHistoricalLimitOffset - offset;
                    totalDays     = preHistoricalLimitDays;
                    totalProgress = baseProgress * preHistoricalLimit * preHistoricalLimitDays;
                    offset       += preHistoricalLimitDays;
                }
            }

            // STEP2: 下限未達の史実年度前ペナルティで研究する日数を求める
            if (offset < 0)
            {
                // 史実年度前ペナルティを求める
                double preHistoricalModifier = Misc.PreHistoricalDateModifier;

                // 史実年度前ペナルティありで研究する日数を求める
                int preHistricalDays = GetPreHistoricalDays(baseProgress, 100 - totalProgress, offset,
                                                            preHistoricalModifier);

                // 史実年度前に研究完了する場合は日数を返す
                if (offset + preHistricalDays <= 0)
                {
                    totalDays += preHistricalDays;
                    return(totalDays);
                }

                // 史実年度前に研究する日数と進捗を加算する
                preHistricalDays = -offset;
                totalDays       += preHistricalDays;
                totalProgress   += GetPreHistoricalProgress(baseProgress, preHistricalDays, offset, preHistoricalModifier);
                offset           = 0;
            }

            // STEP3: 史実年度前後の補正がない状態で研究する日数を求める

            // HoI2の場合史実年度後補正がない
            if (Game.Type == GameType.HeartsOfIron2)
            {
                totalDays += (int)Math.Ceiling((100 - totalProgress) / baseProgress);
                return(totalDays);
            }

            // 史実年度後ボーナスを求める
            double postHistoricalModifier = Game.Type == GameType.ArsenalOfDemocracy
                ? Misc.PostHistoricalDateModifierAoD
                : Misc.PostHistoricalDateModifierDh;

            // 史実年度後ボーナスがない場合
            if (postHistoricalModifier <= 0)
            {
                totalDays += (int)Math.Ceiling((100 - totalProgress) / baseProgress);
                return(totalDays);
            }

            // DHの場合、1年経過までは補正なし
            if (Game.Type == GameType.DarkestHour)
            {
                // ロケット技術/核技術には史実年度後ボーナスが適用されない
                switch (component.Speciality)
                {
                case TechSpeciality.Rocketry:
                case TechSpeciality.NuclearPhysics:
                case TechSpeciality.NuclearEngineering:
                    totalDays += (int)Math.Ceiling((100 - totalProgress) / baseProgress);
                    return(totalDays);
                }

                offset -= 360;
                if (offset < 0)
                {
                    // 史実年度後ボーナスなしで研究する日数を求める
                    int historicalDays = (int)Math.Ceiling((100 - totalProgress) / baseProgress);

                    // 史実年度後ボーナスなしの機関に研究が完了する場合
                    if (offset + historicalDays < 0)
                    {
                        totalDays += historicalDays;
                        return(totalDays);
                    }

                    // 史実年度後ボーナスなしで研究する日数と進捗を加算する
                    historicalDays = -offset;
                    totalDays     += historicalDays;
                    totalProgress += baseProgress * historicalDays;
                    offset         = 0;
                }
            }

            // STEP4: 上限未達の史実年度後ボーナスで研究する日数を求める

            // 史実年度後ボーナスの上限値を求める
            double postHistoricalLimit = Game.Type == GameType.ArsenalOfDemocracy
                ? Misc.PostHistoricalBonusLimit
                : Misc.BlueprintBonus;

            // 史実年度後ボーナスが上限値になる日を求める
            int postHistoricalLimitOffset =
                (int)Math.Ceiling(Math.Abs((postHistoricalLimit - 1) / postHistoricalModifier));

            if (offset < postHistoricalLimitOffset)
            {
                // 史実年度後ボーナスありで研究する日数を求める
                int postHistoricalDays = GetPostHistoricalDays(baseProgress, 100 - totalProgress, offset,
                                                               postHistoricalModifier);

                // 史実年度後ボーナスが上限値に到達する前に研究が完了する場合
                if (offset + postHistoricalDays < postHistoricalLimitOffset)
                {
                    totalDays += postHistoricalDays;
                    return(totalDays);
                }

                // 史実年度後に研究する日数と進捗を加算する
                postHistoricalDays = postHistoricalLimitOffset - offset - 1;
                totalDays         += postHistoricalDays;
                totalProgress     += GetPostHistoricalProgress(baseProgress, postHistoricalDays, offset,
                                                               postHistoricalModifier);
            }

            // STEP5: 史実年度後ボーナス上限値で研究する日数を求める
            totalDays += (int)Math.Ceiling((100 - totalProgress) / (baseProgress * postHistoricalLimit));
            return(totalDays);
        }