public UserTechnology GetCheckPendingResearch(string userId) { var pending = context.UserTechnologies.Include("Technology") .FirstOrDefault(x => x.UserId.Equals(userId) && x.StatusId == UserTechnologyStatusTypes.Pending); if (pending != null) { if ((DateTime.Now - pending.ResearchStartDate).TotalDays > pending.Technology.ResearchDays) { pending.StatusId = UserTechnologyStatusTypes.Researched; var tech = pending.Technology; // notify user var note = CommunicationService.CreateNotification( userId, "Your research is complete!", $"You finished researching {tech.Name} and gained {tech.BoostAmount:P1} {tech.BoostTypeId}"); context.Notes.Add(note); var qm = new QueueManager(); qm.QueueResearchCompleted(userId); return(null); } } return(pending); }
/// <summary> /// get player level accounting for any recent experience /// probably something like: 300x - 150 /// </summary> /// <param name="userId">user id</param> /// <param name="db">db context</param> /// <param name="commit">whether or not to commit this single change to the db</param> /// <returns>player level after updating for experience</returns> public static int GetLevel(string userId, ApplicationDbContext db, bool commit = true) { var user = db.Users.Single(x => x.Id == userId); var experienceNeeded = BaseExperience * Math.Pow(user.Level, ExperienceFactor); if (user.Experience >= experienceNeeded) { // todo: probably queue this message var note = CommunicationService.CreateNotification( user.Id, $"You leveled up to {user.Level + 1}!", $"You gained enough experience to level up to {user.Level + 1}. Higher levels means more perks--keep up the good work!"); db.Notes.Add(note); db.SaveChanges(); user.Level++; if (commit) { db.SaveChanges(); } } return(user.Level); }
public void ProcessEvents(ApplicationDbContext db, ApplicationUser user) { var territory = db.Territories .Include(x => x.Players) .FirstOrDefault(x => x.TerritoryId == user.TerritoryId); var now = DateTime.Now; if (territory != null) { // check resource updates if (territory.LastResourceCollection < DateTime.Now.AddHours(-1)) { // determine how many intervals var elapsed = DateTime.Now - territory.LastResourceCollection; var hoursElapsed = elapsed.Hours; // Get boosts from technology var techBoosts = db.UserTechnologies .Include(x => x.Technology) .Where(x => x.UserId.Equals(user.Id) && x.StatusId == UserTechnologyStatusTypes.Researched) .ToList(); var civPop = territory.CivilianPopulation; // todo: this sucks, refactor allocations into a table or something var resourceMeta = db.Items.Where(x => x.IsCore.Equals(true)) .Select(x => new ResourceMeta { ItemId = x.ItemId, // this will be filled out momentarily NewQuantity = 0, }) .ToList(); var userItems = user.Items .OrderByDescending(x => x.Item.MaxBoost) .ToList(); foreach (var resource in db.Items.Where(x => x.IsCore.Equals(true))) { var allocation = 0.0m; // todo: this sucks, refactor allocations into a table or something switch (resource.ItemId) { case 1: allocation = territory.WaterAllocation; break; case 2: allocation = territory.FoodAllocation; break; case 3: allocation = territory.WoodAllocation; break; case 4: allocation = territory.StoneAllocation; break; case 5: allocation = territory.OilAllocation; break; case 6: allocation = territory.IronAllocation; break; } // get the useritem record var resourceItem = user.Items.Single(x => x.ItemId == resource.ItemId); // start with the boost from technologies var boost = techBoosts .Where(x => x.Technology.BoostTypeId.Equals((BoostTypes)resource.ItemId)) .Sum(x => x.Technology.BoostAmount); // add any boost from items var boostItems = userItems .Where(x => x.Item.BoostType == (BoostTypes)resource.ItemId) .Select(x => new BoostItem { BoostType = x.Item.BoostType, MaxBoost = x.Item.MaxBoost, Quantity = x.Quantity, }); if (boostItems.Any()) { boost += GetItemBoost((BoostTypes)resource.ItemId, boostItems.ToList(), allocation, civPop); } // do resource collection resourceItem.Quantity += (int)((allocation + boost) * civPop * hoursElapsed); resourceMeta.Single(x => x.ItemId == resource.ItemId).NewQuantity = resourceItem.Quantity; } // reset update time to the most recent hour to account for partial intervals territory.LastResourceCollection = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0); // queue a message to check for badges var qm = new QueueManager(); qm.QueueResourceCollection(user.Id, resourceMeta.Single(x => x.ItemId == (int)ResourceTypes.Water).NewQuantity, resourceMeta.Single(x => x.ItemId == (int)ResourceTypes.Food).NewQuantity, resourceMeta.Single(x => x.ItemId == (int)ResourceTypes.Wood).NewQuantity, resourceMeta.Single(x => x.ItemId == (int)ResourceTypes.Stone).NewQuantity, resourceMeta.Single(x => x.ItemId == (int)ResourceTypes.Oil).NewQuantity, resourceMeta.Single(x => x.ItemId == (int)ResourceTypes.Iron).NewQuantity); } // check territory population growth if (territory.LastPopulationUpdate < DateTime.Now.AddHours(-24)) { var elapsed = DateTime.Now - territory.LastPopulationUpdate; var daysElapsed = elapsed.Days; var noteText = string.Empty; // Get boosts from technology var populationBoosts = db.UserTechnologies.Where(x => x.UserId.Equals(user.Id) && x.StatusId == UserTechnologyStatusTypes.Researched && x.Technology.BoostTypeId == BoostTypes.Population) .Select(x => x.Technology.BoostAmount).ToList(); var growth = (int)(territory.CivilianPopulation * (territory.PopulationGrowthRate + populationBoosts.Sum()) * daysElapsed); territory.CivilianPopulation += growth; // reset update time to account for partial intervals territory.LastPopulationUpdate = new DateTime(now.Year, now.Month, now.Day); // notify user var timeText = daysElapsed > 1 ? "recently" : "last night"; noteText = $"A few people from the outskirts found their way into your territory {timeText}. " + $"Your population grew by {growth} to {territory.CivilianPopulation}. " + "Your increased population will automatically help you gather more resources."; var note = CommunicationService.CreateNotification( user.Id, $"Your civilian population grew by {growth} last night!", noteText); db.Notes.Add(note); } // check nightly attacks if (territory.LastNightlyAttack < DateTime.Now.AddHours(-24)) { var elapsed = DateTime.Now - territory.LastNightlyAttack; var daysElapsed = elapsed.Days; var rand = new Random(); var log = new AttackLog { UserId = user.Id, }; var survivals = 0; var attacks = 0; var populationLoss = 0; var resourceLossText = string.Empty; // Calculate winPercentage var defenseBoosts = db.UserTechnologies.Where(x => x.UserId.Equals(user.Id) && x.StatusId == UserTechnologyStatusTypes.Researched && x.Technology.BoostTypeId == BoostTypes.Defense) .Select(x => x.Technology.BoostAmount).ToList(); var winPercentage = 67 + (defenseBoosts.Sum() * 100); for (var i = 0; i < daysElapsed; i++) { if (rand.Next(0, 100) > winPercentage) { attacks++; log.WasAttacked = true; // 1-2 nightly population loss for right now // todo: boosts populationLoss += rand.Next(0, 2) + 1; // lose random resources resourceLossText = ResourceService.RandomResource(user, false, false, 0.05); } else { survivals++; } } // total population loss since last calculation territory.CivilianPopulation -= populationLoss; // reset update time to account for partial intervals territory.LastNightlyAttack = new DateTime(now.Year, now.Month, now.Day); if (attacks > 1) { log.Message = string.Format( "Zombies have been pillaging your territory while you were away. You lost {0} {1}. {2}" + $"Zombie Attacks: {attacks}. Thwarted attempts: {survivals}" , populationLoss , populationLoss == 1 ? "person" : "people" , "You lost too many resources to count!"); } else if (attacks == 1) { log.Message = string.Format( "Zombies attacked your territory last night. You lost {0} {1}. {2}" , populationLoss , populationLoss == 1 ? "person" : "people" , resourceLossText); } else if (attacks == 0) { log.Message = "Your territory survived all recent zombie attacks."; } var note = CommunicationService.CreateNotification( user.Id, "Recent Zombie Activity", log.Message); db.Notes.Add(note); db.AttackLogs.Add(log); } } }