/// <summary> /// Does the action. /// </summary> public override void DoAction() { if (!this.SetNextActionDelay(NpcShipBase.DelayBeforeNextAction)) { return; } CosmoMongerDbDataContext db = CosmoManager.GetDbContext(); Ship npcShip = this.npcRow.Ship; // Check if we are still traveling npcShip.CheckIfTraveling(); // Check if we are currently in combat if (npcShip.InProgressCombat != null) { // In Combat! this.DoCombat(); } else if (this.npcRow.NextTravelTime < DateTime.UtcNow) { // Check if we need to give this pirate some credits if (npcShip.Credits < BaseCreditAmount) { // Poor pirate has no gold, give him some to start npcShip.Credits = BaseCreditAmount; } // Attack? if (this.rnd.SelectByProbablity(new bool[] { true, false }, new double[] { 0.50, 0.50 })) { this.DoAttack(); } else { this.DoTravel(); } this.SetNextTravelTime(); } else { /* * Dictionary<string, object> props = new Dictionary<string, object> * { * { "NpcId", this.npcRow.NpcId }, * { "NextTravelTime", this.npcRow.NextTravelTime }, * { "UtcNow", DateTime.UtcNow } * }; * Logger.Write("Waiting for NextTravelTime", "NPC", 200, 0, TraceEventType.Verbose, "Pirate Wait", props); */ } db.SaveChanges(); }
/// <summary> /// Sets the delay before the next action will be taken for this Npc again. /// </summary> /// <param name="delay">The delay before the next scheduled action.</param> /// <returns>true is time has been set, false if another thread has already ran (Npc should exit)</returns> protected bool SetNextActionDelay(TimeSpan delay) { CosmoMongerDbDataContext db = CosmoManager.GetDbContext(); // Mark the next time this NPC will need to do an action this.npcRow.NextActionTime = DateTime.UtcNow.Add(delay); db.SaveChanges(); return(true); }
/// <summary> /// Does the action. /// </summary> public override void DoAction() { if (!this.SetNextActionDelay(NpcShipBase.DelayBeforeNextAction)) { return; } CosmoMongerDbDataContext db = CosmoManager.GetDbContext(); Ship npcShip = this.npcRow.Ship; // Check if we are still traveling npcShip.CheckIfTraveling(); // Check if we are currently in combat if (npcShip.InProgressCombat != null) { // In Combat! this.DoCombat(); } else if (this.npcRow.NextTravelTime < DateTime.UtcNow) { // Search? if (this.rnd.SelectByProbablity(new bool[] { true, false }, new double[] { 0.50, 0.50 })) { this.DoSearch(); } else { this.DoTravel(); } this.SetNextTravelTime(); } db.SaveChanges(); }
/// <summary> /// Balances the number of NPCs vs Active Players to keep the galaxy alive. /// </summary> public override void DoAction() { // Set next run time to 1 hour if (!this.SetNextActionDelay(new TimeSpan(1, 0, 0))) { return; } // Balance Npcs CosmoMongerDbDataContext db = CosmoManager.GetDbContext(); // Find the number of players active in the last hour on the galaxy int activePlayerCount = (from p in db.Players where p.LastPlayed > DateTime.UtcNow.AddHours(-1) select p).Count(); // Calculate how many Npcs we need int neededNpcs = NpcBalancer.TargetActivePlayers - activePlayerCount; // Make sure we don't go below the min amount neededNpcs = Math.Max(neededNpcs, NpcBalancer.MinNpcs); // Grab the active NPCs we currently have IQueryable <Npc> activeNpcs = (from n in db.Npcs where n.NType == Npc.NpcType.Pirate || n.NType == Npc.NpcType.Police || n.NType == Npc.NpcType.Trader select n); // Calculate how many NPCs we need to create/delete int npcAdjustment = neededNpcs - activeNpcs.Count(); if (npcAdjustment > 0) { while (npcAdjustment-- > 0) { // Produce NPCs Npc newNpc = new Npc(); NpcBase npc = null; // Which type will we produce? Npc.NpcType[] npcTypes = { Npc.NpcType.Pirate, Npc.NpcType.Trader, Npc.NpcType.Police }; double[] npcProbablity = { NpcBalancer.PercentPirates, NpcBalancer.PercentTraders, NpcBalancer.PercentPolice }; newNpc.NType = this.rnd.SelectByProbablity(npcTypes, npcProbablity); switch (newNpc.NType) { case Npc.NpcType.Pirate: // Produce pirate npc = new NpcPirate(newNpc); break; case Npc.NpcType.Trader: // Produce trader npc = new NpcTrader(newNpc); break; case Npc.NpcType.Police: // Produce Police npc = new NpcPolice(newNpc); break; default: throw new InvalidOperationException("Unknown NpcType selected"); } // Give the NPC a good name string npcName = (from name in db.NpcNames where name.NType == newNpc.NType && !(from n in db.Npcs select n.Name) .Contains(name.Name) select name.Name).FirstOrDefault(); // Break out if we couldn't find a new name if (npcName == null) { Logger.Write(newNpc.NType.ToString(), "NPC", 1000, 0, TraceEventType.Critical, "Out of NPC Names"); break; } // Give the NPC the cool name newNpc.Name = npcName; // Add to the database db.Npcs.InsertOnSubmit(newNpc); // Setup the NPC npc.Setup(); db.SaveChanges(); } } else if (npcAdjustment < 0) { // TODO: Delete or inactive NPCs /* * // Query the NPCs to delete * IQueryable<Npc> npcsToDelete = activeNpcs.Take(Math.Abs(npcAdjustment)); * if (npcsToDelete.Any()) * { * // Remove the NPCs * db.Npcs.DeleteAllOnSubmit(npcsToDelete); * * IQueryable<Ship> npcShips = (from n in activeNpcs * select n.Ship); * if (npcShips.Any()) * { * IQueryable<ShipGood> npcShipGoods = (from g in db.ShipGoods * where npcShips.Contains(g.Ship) * select g); * if (npcShipGoods.Any()) * { * // Remove the ship goods * db.ShipGoods.DeleteAllOnSubmit(npcShipGoods); * } * * // Remove the ships * db.Ships.DeleteAllOnSubmit(npcShips); * } * } */ } db.SaveChanges(); }
/// <summary> /// Does the action. /// </summary> public override void DoAction() { if (!this.SetNextActionDelay(NpcTrader.DelayBeforeNextAction)) { return; } CosmoMongerDbDataContext db = CosmoManager.GetDbContext(); Ship npcShip = this.npcRow.Ship; // Check if we are still traveling npcShip.CheckIfTraveling(); // Check if we are currently in combat if (npcShip.InProgressCombat != null) { // In Combat! this.DoCombat(); } else if (this.npcRow.NextTravelTime < DateTime.UtcNow) { // Create an array of goods that the Trader has onboard ShipGood[] goods = npcShip.GetGoods().Where(g => g.Quantity > 0).ToArray(); // goodCount != 0, sell all the trader's goods foreach (ShipGood good in goods) { // Get the number of this good type onboard the Trader's ship int shipGoodQuantity = good.Quantity; // Find the price of the good int shipGoodPrice = 0; try { good.Sell(npcShip, shipGoodQuantity, shipGoodPrice); } catch (InvalidOperationException ex) { // Log this exception ExceptionPolicy.HandleException(ex, "NPC Policy"); } } // This is the minimum amount of money a trader should have before buying goods int baseCreditsSizeAdjusted = BaseCreditMultiplier * npcShip.CargoSpaceTotal; // Check if we need to give this trader some credits if (npcShip.Credits < baseCreditsSizeAdjusted) { // Poor trader has no credits, give him some to start npcShip.Credits = baseCreditsSizeAdjusted; } // Trader buys first good SystemGood good1 = (from g in npcShip.CosmoSystem.SystemGoods orderby(g.PriceMultiplier) ascending select g).FirstOrDefault(); // This is the maximum number a Trader can purchase double numberCanBuy = Math.Floor((double)npcShip.Credits / good1.Price); // This is the maximum number we want the Trader to purchase double numberToBuy = Math.Ceiling((double)npcShip.CargoSpaceFree / 2); // Make sure that the Trader buys as many of good1 as credits allow int numberBuying = (int)Math.Min(numberCanBuy, numberToBuy); // Insures that Traders attempt to buy the proper number of good1 int properNumber = (int)Math.Min(numberBuying, good1.Quantity); try { good1.Buy(npcShip, properNumber, good1.Price); } catch (InvalidOperationException ex) { // Log this exception ExceptionPolicy.HandleException(ex, "NPC Policy"); } // Find all the systems within range CosmoSystem[] inRangeSystems = npcShip.GetInRangeSystems(); // Finds the system with the highest PriceMultiplier CosmoSystem targetSystem = (from g in db.SystemGoods where inRangeSystems.Contains(g.CosmoSystem) && g.Good == good1.Good orderby(g.PriceMultiplier) descending select g.CosmoSystem).FirstOrDefault(); // Get references to the Good entities for all the SystemGoods sold in the target system IEnumerable <Good> goodsInTargetSystem = targetSystem.SystemGoods.Select(g => g.Good); // Get references to the Good entites for the all the SystemGoods sold in the current system IEnumerable <Good> goodsInCurrentSystem = npcShip.CosmoSystem.SystemGoods.Select(g => g.Good); // Do an intersetion of both, getting a list of goods sold in both systems IEnumerable <Good> goodsInBoth = goodsInTargetSystem.Intersect(goodsInCurrentSystem); // Look in the current system for goods sold in both, sorting by PriceMultiplier (lowest at top) // and taking the top good in the results SystemGood good2 = (from g in npcShip.CosmoSystem.SystemGoods where goodsInBoth.Contains(g.Good) && g != good1 orderby g.PriceMultiplier ascending select g).FirstOrDefault(); // This is the maximum number a Trader can purchase numberCanBuy = Math.Floor((double)npcShip.Credits / good2.Price); // This is the maximum number we want the Trader to purchase numberToBuy = Math.Ceiling((double)npcShip.CargoSpaceFree); // Make sure that the Trader buys as many of good1 as credits allow numberBuying = (int)Math.Min(numberCanBuy, numberToBuy); // Insures that Traders attempt to buy the proper number of good1 properNumber = (int)Math.Min(numberBuying, good2.Quantity); try { good2.Buy(npcShip, properNumber, good2.Price); } catch (InvalidOperationException ex) { // Log this exception ExceptionPolicy.HandleException(ex, "NPC Policy"); } this.DoTravel(targetSystem); // Set next travel time this.npcRow.NextTravelTime = DateTime.UtcNow.AddSeconds(this.rnd.Next(60, 120)); } else { Dictionary <string, object> props = new Dictionary <string, object> { { "NpcId", this.npcRow.NpcId }, { "NextTravelTime", this.npcRow.NextTravelTime }, { "UtcNow", DateTime.UtcNow } }; Logger.Write("Waiting for NextTravelTime", "NPC", 200, 0, TraceEventType.Verbose, "Trader Wait", props); } db.SaveChanges(); }