Esempio n. 1
0
        static void TestRecruitment()
        {
            var calculator = new RecruitmentCalculator(2, 25, 20, 10, 1);

            for (int i = 0; i < 5; i++)
            {
                var timeSpan = TimeSpan.FromDays(3 * (i + 1));
                var defense  = calculator.CalculatePossibleDefenseRecruitment(timeSpan);
                var offense  = calculator.CalculatePossibleOffenseRecruitment(timeSpan);

                Console.WriteLine("\n\nIn {0} hours:", timeSpan.TotalHours);
                Console.WriteLine("[Offense]");
                PrintArmy(offense);

                Console.WriteLine("\n[Defense]");
                PrintArmy(defense);
            }
        }
        public async Task<IActionResult> GetVillageArmy(long villageId, int? morale)
        {
            if (!await CanReadVillage(villageId))
                return StatusCode(401);

            PreloadWorldData();

            var uploadHistory = await Profile("Get user upload history", () =>
                context.UserUploadHistory.Where(h => h.Uid == CurrentUserId).FirstOrDefaultAsync()
            );

            var validationInfo = UploadRestrictionsValidate.ValidateInfo.FromMapRestrictions(CurrentUser, uploadHistory);
            List<String> needsUpdateReasons = UploadRestrictionsValidate.GetNeedsUpdateReasons(CurrentServerTime, validationInfo);

            if (needsUpdateReasons != null && needsUpdateReasons.Any())
            {
                return StatusCode(423, needsUpdateReasons.Select(r => Translate(r)).ToList()); // Status code "Locked"
            }

            //  Start getting village data

            var currentVillage = await Profile("Get current village", () => (
                from cv in CurrentSets.CurrentVillage
                                    .Include(v => v.ArmyAtHome)
                                    .Include(v => v.ArmyOwned)
                                    .Include(v => v.ArmyStationed)
                                    .Include(v => v.ArmyTraveling)
                                    .Include(v => v.ArmyRecentLosses)
                                    .Include(v => v.CurrentBuilding)
                where cv.VillageId == villageId
                select cv
            ).FirstOrDefaultAsync());

            var commandsToVillage = await Profile("Get commands to village", () => (
                from command in CurrentSets.Command
                                            .Include(c => c.Army)
                where command.TargetVillageId == villageId
                where !command.IsReturning
                where command.LandsAt > CurrentServerTime
                select command
            ).ToListAsync());

            var latestConquerTimestamp = await Profile("Get latest conquer", () => (
                from conquer in CurrentSets.Conquer
                where conquer.VillageId == villageId
                orderby conquer.UnixTimestamp descending
                select conquer.UnixTimestamp
            ).FirstOrDefaultAsync());
            
            var jsonData = new JSON.VillageData();

            //  Return empty data if no data is available for the village
            if (currentVillage == null)
                return Ok(jsonData);

            Profile("Populate JSON data", () =>
            {
                if (currentVillage.ArmyOwned?.LastUpdated != null)
                {
                    jsonData.OwnedArmy = ArmyConvert.ArmyToJson(currentVillage.ArmyOwned);
                    jsonData.OwnedArmySeenAt = currentVillage.ArmyOwned.LastUpdated;
                }

                if (currentVillage.ArmyRecentLosses?.LastUpdated != null)
                {
                    jsonData.RecentlyLostArmy = ArmyConvert.ArmyToJson(currentVillage.ArmyRecentLosses);
                    jsonData.RecentlyLostArmySeenAt = currentVillage.ArmyRecentLosses.LastUpdated;
                }

                if (currentVillage.ArmyStationed?.LastUpdated != null)
                {
                    jsonData.StationedArmy = ArmyConvert.ArmyToJson(currentVillage.ArmyStationed);
                    jsonData.StationedSeenAt = currentVillage.ArmyStationed.LastUpdated;
                }

                if (currentVillage.ArmyTraveling?.LastUpdated != null)
                {
                    jsonData.TravelingArmy = ArmyConvert.ArmyToJson(currentVillage.ArmyTraveling);
                    jsonData.TravelingSeenAt = currentVillage.ArmyTraveling.LastUpdated;
                }

                if (currentVillage.ArmyAtHome?.LastUpdated != null)
                {
                    jsonData.AtHomeArmy = ArmyConvert.ArmyToJson(currentVillage.ArmyAtHome);
                    jsonData.AtHomeSeenAt = currentVillage.ArmyAtHome.LastUpdated;
                }

                jsonData.LastLoyalty = currentVillage.Loyalty;
                jsonData.LastLoyaltySeenAt = currentVillage.LoyaltyLastUpdated;

                if (currentVillage.Loyalty != null)
                {
                    var loyaltyCalculator = new LoyaltyCalculator(CurrentWorldSettings.GameSpeed);
                    jsonData.PossibleLoyalty = loyaltyCalculator.PossibleLoyalty(currentVillage.Loyalty.Value, CurrentServerTime - currentVillage.LoyaltyLastUpdated.Value);
                }

                jsonData.LastBuildings = BuildingConvert.CurrentBuildingToJson(currentVillage.CurrentBuilding);
                jsonData.LastBuildingsSeenAt = currentVillage.CurrentBuilding?.LastUpdated;

                if (currentVillage.CurrentBuilding?.LastUpdated != null)
                {
                    var constructionCalculator = new ConstructionCalculator();
                    jsonData.PossibleBuildings = constructionCalculator.CalculatePossibleBuildings(jsonData.LastBuildings, CurrentServerTime - currentVillage.CurrentBuilding.LastUpdated.Value);
                }

                if (currentVillage.ArmyStationed?.LastUpdated != null)
                {
                    var battleSimulator = new BattleSimulator();
                    short wallLevel = currentVillage.CurrentBuilding?.Wall ?? 20;
                    short hqLevel = currentVillage.CurrentBuilding?.Main ?? 20;

                    if (currentVillage.CurrentBuilding != null)
                        wallLevel += new ConstructionCalculator().CalculateLevelsInTimeSpan(BuildingType.Wall, hqLevel, wallLevel, CurrentServerTime - currentVillage.CurrentBuilding.LastUpdated.Value);

                    var nukeEstimation = battleSimulator.EstimateRequiredNukes(jsonData.StationedArmy, wallLevel, CurrentWorldSettings.ArchersEnabled, morale ?? 100);

                    jsonData.NukesRequired = nukeEstimation.NukesRequired;
                    jsonData.LastNukeLossPercent = (int)(nukeEstimation.LastNukeLossesPercent);
                }

                //  Might have CurrentArmy entries but they're just empty/null - not based on any report data
                if (jsonData.OwnedArmy != null && (jsonData.OwnedArmySeenAt == null || jsonData.OwnedArmy.Count == 0))
                {
                    jsonData.OwnedArmy = null;
                    jsonData.OwnedArmySeenAt = null;
                }

                if (jsonData.StationedArmy != null && (jsonData.StationedSeenAt == null || jsonData.StationedArmy.Count == 0))
                {
                    jsonData.StationedArmy = null;
                    jsonData.StationedSeenAt = null;
                }

                if (jsonData.TravelingArmy != null && (jsonData.TravelingSeenAt == null || jsonData.TravelingArmy.Count == 0))
                {
                    jsonData.TravelingArmy = null;
                    jsonData.TravelingSeenAt = null;
                }

                if (jsonData.RecentlyLostArmy != null && (jsonData.RecentlyLostArmySeenAt == null || jsonData.RecentlyLostArmy.Count == 0))
                {
                    jsonData.RecentlyLostArmy = null;
                    jsonData.RecentlyLostArmySeenAt = null;
                }


                var armyCalculator = new RecruitmentCalculator(2, jsonData.LastBuildings);
                DateTime? localArmyLastSeenAt = null;
                int? availableArmyPopulation = null;

                if (jsonData.StationedArmy != null)
                {
                    localArmyLastSeenAt = jsonData.StationedSeenAt.Value;
                    var existingPop = ArmyStats.CalculateTotalPopulation(jsonData.StationedArmy);
                    availableArmyPopulation = Math.Max(0, armyCalculator.MaxPopulation - existingPop);
                }

                var conquerTime = DateTimeOffset.FromUnixTimeMilliseconds(latestConquerTimestamp).UtcDateTime;

                bool useConquer = false;
                if (localArmyLastSeenAt == null)
                    useConquer = true;
                else
                    useConquer = conquerTime > localArmyLastSeenAt.Value;

                if (useConquer)
                {
                    localArmyLastSeenAt = conquerTime;
                    availableArmyPopulation = armyCalculator.MaxPopulation;
                }

                //  Add recruitment estimations
                if (localArmyLastSeenAt != null)
                {
                    var timeSinceSeen = CurrentServerTime - localArmyLastSeenAt.Value;
                    armyCalculator.MaxPopulation = availableArmyPopulation.Value;

                    //  No point in estimating troops if there's been 2 weeks since we saw stationed troops
                    if (timeSinceSeen.TotalDays < 14)
                    {
                        jsonData.PossibleRecruitedOffensiveArmy = armyCalculator.CalculatePossibleOffenseRecruitment(timeSinceSeen);
                        jsonData.PossibleRecruitedDefensiveArmy = armyCalculator.CalculatePossibleDefenseRecruitment(timeSinceSeen);
                    }
                }

                //  Add command summaries
                jsonData.DVs = new Dictionary<long, int>();
                jsonData.Fakes = new List<long>();
                jsonData.Nukes = new List<long>();
                jsonData.Nobles = new List<long>();

                jsonData.Players = commandsToVillage.Select(c => c.SourcePlayerId).Distinct().ToList();

                foreach (var command in commandsToVillage.Where(c => c.Army != null))
                {
                    var army = ArmyConvert.ArmyToJson(command.Army);
                    var offensivePop = ArmyStats.CalculateTotalPopulation(army.OfType(JSON.UnitBuild.Offensive));
                    var defensivePop = ArmyStats.CalculateTotalPopulation(army.OfType(JSON.UnitBuild.Defensive));
                    var isNoble = command.Army.Snob > 0 && command.IsAttack;

                    bool isFake = false;
                    bool isNuke = false;
                    if (!army.Values.Any(cnt => cnt > 1) && !isNoble)
                    {
                        isFake = true;
                    }
                    else if (command.IsAttack && offensivePop > 10000)
                    {
                        isNuke = true;
                    }

                    if (isFake)
                        jsonData.Fakes.Add(command.CommandId);
                    else if (isNuke)
                        jsonData.Nukes.Add(command.CommandId);
                    else if (defensivePop > 3000 && !command.IsAttack)
                        jsonData.DVs.Add(command.CommandId, defensivePop);

                    if (isNoble)
                        jsonData.Nobles.Add(command.CommandId);
                }
            });

            return Ok(jsonData);
        }