/// <summary> /// Informs all parties of the outcome of the combat round. /// </summary> /// <param name="player"></param> /// <param name="enemy"></param> /// <param name="room"></param> /// <param name="damage"></param> /// <param name="defense"></param> /// <param name="attack"></param> private static void SendRoundOutcomeMessage(User.User player, User.User enemy, Room room, double damage, double defense, double attack) { //TODO: Get the message based weapon type/special weapon (blunt, blade, axe, pole, etc.) //Get the weapon type and append it to the "Hit" or "Miss" type when getting the message //ex: HitSword, HitClub, MissAxe, MissUnarmed could even get really specific HitRustyShortSword, MissLegendaryDaggerOfBlindness //Make a method to figure out the type by having a lookup table in the DB that points to a weapon type string if (damage < 0) { player.MessageHandler(ParseMessage(GetMessage("Combat", "Hit", MessageType.Self), player, enemy, damage, defense, attack)); enemy.MessageHandler(ParseMessage(GetMessage("Combat", "Hit", MessageType.Target), player, enemy, damage, defense, attack)); string roomMessage = ParseMessage(GetMessage("Combat", "Hit", MessageType.Room), player, enemy, damage, defense, attack); room.InformPlayersInRoom(roomMessage, new List <string>(new string[] { player.UserID, enemy.UserID })); enemy.Player.ApplyEffectOnAttribute("Hitpoints", damage); Character.NPC npc = enemy.Player as Character.NPC; if (npc != null) { npc.IncreaseXPReward(player.UserID, (damage * -1.0)); } } else { player.MessageHandler(ParseMessage(GetMessage("Combat", "Miss", MessageType.Self), player, enemy, damage, defense, attack)); enemy.MessageHandler(ParseMessage(GetMessage("Combat", "Miss", MessageType.Target), player, enemy, damage, defense, attack)); string roomMessage = ParseMessage(GetMessage("Combat", "Miss", MessageType.Room), player, enemy, damage, defense, attack); room.InformPlayersInRoom(roomMessage, new List <string>(new string[] { player.UserID, enemy.UserID })); } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { if (actor.StanceState != CharacterEnums.CharacterStanceState.Decomposing) { Commands.CommandParser.ExecuteCommand(actor, "EMOTE", "carcass last bit of flesh has rotted away from its dead corpse."); actor.Description = "The only remains of " + actor.FirstName + " are just bones."; actor.SetStanceState(CharacterEnums.CharacterStanceState.Decomposing); actor.NextAiAction = DateTime.Now.AddMinutes(5).ToUniversalTime(); } else { Commands.CommandParser.ExecuteCommand(actor, "EMOTE", "carcass has its bones break down to dust and carried off by the wind."); MongoUtils.MongoData.ConnectToDatabase(); MongoDB.Driver.MongoDatabase db = MongoUtils.MongoData.GetDatabase("World"); MongoDB.Driver.MongoCollection npcs = db.GetCollection("NPCs"); MongoDB.Driver.IMongoQuery query = MongoDB.Driver.Builders.Query.EQ("_id", actor.MobTypeID); MongoDB.Bson.BsonDocument doc = npcs.FindOneAs <MongoDB.Bson.BsonDocument>(query); doc["Current"] = doc["Current"].AsInt32 - 1; npcs.Save(doc); db = MongoUtils.MongoData.GetDatabase("Characters"); npcs = db.GetCollection("NPCCharacters"); query = MongoDB.Driver.Builders.Query.EQ("_id", MongoDB.Bson.ObjectId.Parse(actor.ID)); npcs.Remove(query); } }
public void Loot(User.User looter, List <string> commands, Character.NPC npc) { //okay the group looting rule is not free for all thats why we arrived here. We now need to abide by the looting rule that governs the //group. //need to create the loot methods for each rule and also add master loot rule switch (GroupRuleForLooting) { case GroupLootRule.Leader_only: OnlyLeaderLoots(looter, commands, npc); break; case GroupLootRule.Next_player_loots: NextPlayerLoots(looter, commands, npc); break; case GroupLootRule.Chance_Loot: ChanceLoot(looter, commands, npc); break; case GroupLootRule.Chance_vote: break; case GroupLootRule.Master_Looter: MasterLooterLoots(looter, commands, npc); break; } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { Wander.GetState().Execute(actor); //let's go to another room actor.NextAiAction = DateTime.Now.AddSeconds(-2).ToUniversalTime(); //set next action back so we will immediately start searching for a target FindTarget.GetState().Execute(actor); //let's look for a target actor.NextAiAction = DateTime.Now.AddSeconds(Extensions.RandomNumber.GetRandomNumber().NextNumber(10, 31)).ToUniversalTime(); //we are actively looking so the wait time is not long to linger about }
public void Enter(Character.NPC actor) { //ok we were recently in combat and we are in hunt mode otherwise we passed the cool down period and will go back to wandering around if (actor.LastCombatTime != DateTime.MinValue.ToUniversalTime() && (DateTime.Now.ToUniversalTime() - actor.LastCombatTime).TotalMinutes >= 10) { actor.Fsm.ChangeState(Wander.GetState(), actor); } }
public void Enter(Character.NPC actor) { //ok when we enter this state we will first set the description to the NPC is sitting here rotting, //then decomposing and finally get rid of him on exit actor.Description = "The recently dead carcass of " + actor.FirstName + " is rotting as maggots feast on its entrails."; actor.NextAiAction = DateTime.Now.AddMinutes(10).ToUniversalTime(); actor.Save(); }
public void ChangeState(IState newState, Character.NPC Actor) { if (state != null && newState != null) { state.Exit(Actor); previousState = state; state = newState; state.Enter(Actor); Actor.Save(); } }
public void Update(Character.NPC Actor) { if (state != null) { state.Execute(Actor); } if (globalState != null) { globalState.Execute(Actor); } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { //first let's check to see if we got any messages telling us we are being attacked and use that //person attacking us as the target //if that gets us nowhere, we need to then just kill the first non npc we find in our same location Rooms.Room room = Rooms.Room.GetRoom(actor.Location); List <string> playersAtThisLocation = room.GetObjectsInRoom(Rooms.Room.RoomObjects.Players); double minutesSinceLastCombat = (DateTime.Now.ToUniversalTime() - actor.LastCombatTime).TotalMinutes; //let's start by seeing if we had a last target and the last combat time has been less than 5 minutes ago, if so and he's here, it's payback time if (actor.LastTarget != null && minutesSinceLastCombat < 5) { playersAtThisLocation.AddRange(room.GetObjectsInRoom(Rooms.Room.RoomObjects.Npcs)); //we may have been attacking an npc so let's add them in if (playersAtThisLocation.Contains(actor.LastTarget)) //yeah our previous target is here { actor.CurrentTarget = actor.LastTarget; } } //if we don't have a target and we have never been in combat yet, then we are going to find a target OR //we've lost interest in our previous target but still have a blooddlust for another 10 minutes //so a random person is going to get attacked unless it's been too long since we last attacked someone //at this point we should only have actual players in the list to attack (maybe add something so some NPCs can attack other NPCs) if ((actor.LastCombatTime == DateTime.MinValue.ToUniversalTime() && actor.CurrentTarget == null) || (actor.CurrentTarget == null && minutesSinceLastCombat >= 5 && minutesSinceLastCombat < 15)) { if (playersAtThisLocation.Count > 0) { actor.CurrentTarget = playersAtThisLocation[Extensions.RandomNumber.GetRandomNumber().NextNumber(0, playersAtThisLocation.Count)]; } } //we have a target let's attack if (actor.CurrentTarget != null) { if (playersAtThisLocation.Contains(actor.CurrentTarget)) { Commands.CommandParser.ExecuteCommand(actor, "EMOTE", "growls menancingly at " + MySockets.Server.GetAUser(actor.CurrentTarget).Player.FirstName.CamelCaseWord() + "!"); actor.NextAiAction = DateTime.Now.AddSeconds(10).ToUniversalTime(); //give player time to react, maybe even get the first hit actor.Fsm.ChangeState(Combat.GetState(), actor); } } else { //no targets in sight let's enter hunt mode until things cool down actor.Fsm.ChangeState(Hunt.GetState(), actor); } }
//the way this works is the current looter can either loot all or loot a specific item and then his turn is over and the next player gets a chance to loot. //the next player can choose to loot something from the current corpse private void NextPlayerLoots(User.User looter, List <string> commands, Character.NPC npc) { if (NextLooterList == null) { //create th elist of looters in no particular order NextLooterList = new Dictionary <int, string>(); int index = 0; foreach (string player in PlayerList) { NextLooterList.Add(index, player); index++; } } if (looter.UserID == NextLooterList[CurrentLooter]) { if (npc.Loot(looter, commands, true)) { //if the player actually loots something then we'll increment the counter CurrentLooter++; if (CurrentLooter > NextLooterList.Count) { CurrentLooter = 0; } } } else { int playerPosition = 0; foreach (var keyValue in NextLooterList) { if (keyValue.Value == looter.UserID) { break; } playerPosition++; } playerPosition -= CurrentLooter; if (playerPosition < 0) { playerPosition = playerPosition + NextLooterList.Count; } MySockets.Server.GetAUser(looter.UserID).MessageHandler(string.Format("You are not eligible to loot at this time, it will be your turn in {0} more lootings.", playerPosition)); } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { if (!actor.IsDead() && !actor.InCombat) { if (DateTime.Now.ToUniversalTime() > actor.NextAiAction) { //eventuall this literals will be gotten from the literals table for each different NPC Commands.CommandParser.ExecuteCommand(actor, "SAY", "brains..."); Commands.CommandParser.ExecuteCommand(actor, "EMOTE", "reaches out attempting to grab something"); actor.NextAiAction = DateTime.Now.AddSeconds(Extensions.RandomNumber.GetRandomNumber().NextNumber(15, 60)).ToUniversalTime(); if (!FSM.ContinueWithThisState()) { actor.Fsm.ChangeState(Wander.GetState(), actor); } } } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { //no target then switch to finding a target first if (actor.CurrentTarget == null) { actor.Fsm.ChangeState(FindTarget.GetState(), actor); } else //ok we have someone we can kill, let's do that //if this type of NPC may alert other NPC of the same type in the room to also join in on the fun /* * if (actor.AlertOthers){ * NPCUtils.AlertOtherMobs(actor.Location, actor.MobType, actor.CurrentTarget); * }*/ { Commands.CommandParser.ExecuteCommand(actor, "KILL", "target"); } }
/// <summary> /// This method sets a player state to unconcious or dead based /// </summary> /// <param name="player"></param> /// <param name="enemy"></param> private static void UpdatePlayerState(User.User player, User.User enemy) { if (enemy.Player.IsUnconcious()) { SendDeadOrUnconciousMessage(player, enemy); } if (enemy.Player.IsDead()) { SendDeadOrUnconciousMessage(player, enemy, true); Character.NPC npc = enemy.Player as Character.NPC; if (npc != null) { npc.CalculateXP(); npc.Fsm.ChangeState(AI.Rot.GetState(), npc); enemy.Player = npc; enemy.Player.Save(); } } }
//one player will randomly be chosen as the loot winner and can loot something. Once he loots something looting should be opne for all for //the corpse that was looted, otherwise another winner is randomly chosen again. //this has the drawback that only one corpse is remembered and not all the corpses that got looted not cool. private void ChanceLoot(User.User looter, List <string> commands, Character.NPC npc) { //we don't have a loot winner yet so let's roll the dice if (string.IsNullOrEmpty(MasterLooter)) { int highestRoll = 0; string winner = null; foreach (string player in PlayerList) { int currentRoll = Extensions.RandomNumber.GetRandomNumber().NextNumber(0, 20); if (currentRoll > highestRoll) { winner = player; } } } //so the looter was the winner or another player in the group is looting a corpse that was previously looted by a previous winner if (string.Equals(looter.UserID, MasterLooter) || LastLootedCorpse.Contains(npc.ID)) { if (npc.Loot(looter, commands, true)) { //if player actually looted something MasterLooter = null; if (!LastLootedCorpse.Contains(npc.ID)) { LastLootedCorpse.Add(npc.ID); } } //we don't need to keep any old ID's since they probably rotted away anyways. Seriously doubt the group looted 100 bodies and then wanted to go //back and re-loot one of the 50 first corpses. This number is subject to change once testing starts happening. if (LastLootedCorpse.Count > 100) { LastLootedCorpse.RemoveRange(0, 49); } } else { MySockets.Server.GetAUser(looter.UserID).MessageHandler("You did not win the loot draw and can not loot this corpse."); } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { if (actor.StanceState != CharacterEnums.CharacterStanceState.Laying_unconcious && actor.StanceState != CharacterEnums.CharacterStanceState.Laying_dead && actor.StanceState != CharacterEnums.CharacterStanceState.Decomposing) { if (DateTime.Now.ToUniversalTime() > actor.NextAiAction) //so it's time for this AI state to execute { string message = "Hey pal, you looking for trouble?"; if (trigger.MessageOverrideAsString.Count > 0) { message = trigger.MessageOverrideAsString[RandomNumber.GetRandomNumber().NextNumber(0, trigger.MessageOverrideAsString.Count)]; } Commands.CommandParser.ExecuteCommand(actor, "say", message); } } //either way we are not staying in this state, it's just a blip state actor.NextAiAction = DateTime.Now.AddSeconds(Extensions.RandomNumber.GetRandomNumber().NextNumber(60, 121)).ToUniversalTime(); //set when we want this action to execute next actor.Fsm.RevertState(); actor.Save(); }
public void InterpretMessage(string message, Character.Iactor actor) { Character.NPC npc = actor as Character.NPC; MessageParser parser = new MessageParser(message, actor, npc.Triggers); parser.FindTrigger(); //Here's the rub. This call is a sequential call up to this point, maybe we want to //kick off a separate thread so that then it won't hold up the players actions and //then we can even execute states that operate on a delay. if (parser.TriggerToExecute != null) { IState state = GetStateFromName(parser.TriggerToExecute.StateToExecute); if (state != null) { ChangeState(state, npc); npc.NextAiAction = DateTime.Now.ToUniversalTime().AddSeconds(-1); //this state will execute next now state.Execute(npc, parser.TriggerToExecute); } } }
public void Execute(Character.NPC actor, ITrigger trigger = null) { if (!actor.IsDead() && !actor.InCombat) { Rooms.Room room = Rooms.Room.GetRoom(actor.Location); room.GetRoomExits(); List <Rooms.Exits> availableExits = room.RoomExits; if (DateTime.Now.ToUniversalTime() > actor.NextAiAction) //so it's time for this AI state to execute { Commands.CommandParser.ExecuteCommand(actor, availableExits[Extensions.RandomNumber.GetRandomNumber().NextNumber(0, availableExits.Count)].Direction); actor.NextAiAction = DateTime.Now.AddSeconds(Extensions.RandomNumber.GetRandomNumber().NextNumber(60, 121)).ToUniversalTime(); //set when we want this action to execute next if (!FSM.ContinueWithThisState()) { actor.Fsm.ChangeState(Speak.GetState(), actor); } } } if (actor.InCombat) { actor.Fsm.ChangeState(Combat.GetState(), actor); } }
public void Exit(Character.NPC actor) { }
//finisher moves //these will actually be skill moves private static void Cleave(User.User player, List <string> commands) //this will need a check in the future to be used with only bladed weapons { User.User enemy = null; if (commands.Count > 2) { foreach (User.User foe in MySockets.Server.GetAUserByFirstName(commands[2])) { if (foe.Player.Location == player.Player.Location) { enemy = foe; } } } else //did not specify a name let's kill the first player we find unconcious in our same location { enemy = MySockets.Server.GetCurrentUserList().Where(u => u.Player.Location == player.Player.Location && String.Compare(u.Player.ActionState.ToString(), "unconcious", true) == 0).SingleOrDefault(); } if (enemy == null) { //ok it's not a player lets look through the NPC list foreach (Character.NPC npc in Character.NPCUtils.GetAnNPCByName(commands[2], player.Player.Location)) { if (npc.ActionState == CharacterEnums.CharacterActionState.Unconcious) { User.User foe = new User.User(true); foe.UserID = npc.ID; foe.Player = npc; enemy = foe; break; } } } if (enemy == null) { player.MessageHandler("You can't kill what you can't see!"); return; } Room room = Room.GetRoom(player.Player.Location); if (String.Compare(enemy.Player.ActionState.ToString(), "unconcious", true) == 0) { if (commands.Count > 3 && commands[3].ToLower() == "slowly") //a slow death for your opponent, bask in it. { player.MessageHandler(String.Format("You slowly drive your blade through {0}'s chest and twist it a few times as {1} lays on the ground unconcious.", enemy.Player.FirstName, enemy.Player.Gender == "Male" ? "he" : "she")); enemy.MessageHandler(String.Format("{0} slowly drives {1} blade through your chest and twists it a few times as you lay on the ground unconcious.", player.Player.FirstName, player.Player.Gender == "Male" ? "his" : "her")); string roomMessage = String.Format("{0} slowly drives {1} blade through {2}'s chest and twists it a few times as {3} lay on the ground unconcious.", player.Player.FirstName, player.Player.Gender == "Male" ? "his" : "her", enemy.Player.FirstName, enemy.Player.Gender == "Male" ? "he" : "she"); room.InformPlayersInRoom(roomMessage, new List <string>(new string[] { player.UserID, enemy.UserID })); ; } else { player.MessageHandler(String.Format("You cleave {0} as {1} lays on the ground unconcious.", enemy.Player.FirstName, enemy.Player.Gender == "Male" ? "he" : "she")); enemy.MessageHandler(String.Format("{0} cleaved you as you lay on the ground unconcious.", player.Player.FirstName)); string roomMessage = String.Format("{0} cleaved {1} as {2} lay on the ground unconcious.", player.Player.FirstName, enemy.Player.FirstName, enemy.Player.Gender == "Male" ? "he" : "she"); room.InformPlayersInRoom(roomMessage, new List <string>(new string[] { player.UserID, enemy.UserID })); } enemy.Player.SetAttributeValue("Hitpoints", -100); //SetDead(player, enemy); Character.NPC npc = enemy.Player as Character.NPC; if (npc != null) { if (npc.IsDead()) { npc.Fsm.ChangeState(AI.Rot.GetState(), npc); } } } else { player.MessageHandler(String.Format("You can't cleave {0}, {1} not unconcious.", enemy.Player.FirstName, enemy.Player.Gender == "Male" ? "he's" : "she's")); } }
public void Enter(Character.NPC actor) { Commands.CommandParser.ExecuteCommand(actor, "EMOTE", "starts looking around for something to attack"); actor.NextAiAction = DateTime.Now.AddSeconds(30).ToUniversalTime(); //this way players will have some time to react and/or run away }
public void Enter(Character.NPC actor) { actor.NextAiAction = DateTime.Now.AddSeconds(Extensions.RandomNumber.GetRandomNumber().NextNumber(60, 121)).ToUniversalTime(); }
public void Enter(Character.NPC actor) { //no target, no fighting }