public static Item[] VisibleItems(MOB mob, Body vehicle) { Room startingRoom = vehicle.Position.ForRoom; //Massively TODO. //In the long term, I think MOBs should have some short term memory about this, knowing who went where, //which might also be used to cache what they can see. //No great ideas for the calculations themselves right now. I probably want to keep this very simple somehow instead //of doing lots of trig and angles and sizes for everything. //Related idea TODO eventually: //Have a setting for 'Item shortcuts'. Add something like {a} then {b} then {c} and so on (going to {aaa} and so on if needed) to items a user observes. //Let user refer to items/things by {a} and so on instead of the name. Require that shortcuts not be reused for x amount of time. //Want to maybe do something extra fancy with this, for similar things user could conceivably confuse together or things that change unnoticed; //"Mook in red shirt {a} leaves east. Mook in red shirt {b} enters from the west." <-- gives away two different mooks //"Mook in red shirt {a} leaves east. Mook in red shirt {a} enters from the west." <-- implies same mook but maybe they are actually different but unusually similar. //"Mook in red shirt {a} leaves east. Damsel in distress {a} enters from the east." <-- similarly gives away that mook is disguised as damsel. //Another Related idea TODO eventually: //Allow user to ASSIGN shortcuts to items. This needs to be fundamentally different then the other item shortcuts though, maybe with a user-selected option for each item. // - Can remember only the item, assume it's the same item if see something similar elsewhere. // - Remember the item and position, assume it's the same item if see something similar in the same place later. // - Track the item, similar as above? probably not make this an option. return(startingRoom.GetItems()); }
/// <summary> /// Try to parse the input as a command for this MOB to perform. If found, immediately executes the command. /// This method will probably end up being refactored in the future, some of this makes more sense in Command.cs and /// some of this will need to be smarter about context for commands before just running commands (e.g. 'order') /// </summary> /// <param name="input">Full input string to try to Execute.</param> /// <param name="currentMob">Current MOB to perform the action as, if there is a MOB associated with the input.</param> public void TryFindCommand(string input, MOB currentMob) { string[] words = input.Split(' '); string commandWord = words[0].ToLower(); Command command; if (Command.UniqueCommands.TryGetValue(commandWord, out command)) { if (!command.CanUse(this, currentMob)) { sendMessage("You cannot ever use \"" + command.OriginalCommandName + "\"."); return; } } else { List <CommandEntry> options = Command.SortedAllCommands; int index = options.BinarySearch(new CommandEntry(commandWord, null)); if (index < 0) { index = -index - 1; } while (index > 0 && options[index - 1].Trigger.StartsWith(commandWord)) //In case of exact commandWord matches, backtrack to the first Command with that word. { index--; } while (index < options.Count) { CommandEntry next = options[index]; if (!next.Trigger.StartsWith(commandWord)) { break; //No matches. command is default from TryGetValue } if (next.Command.CanUse(this, currentMob)) { command = next.Command; break; } } } if (command != null) { QueuedCommand userCommand = command.GetQueuedCommand(input); if (currentMob != null) { command.Execute(currentMob, userCommand); } else { command.Execute(this, userCommand); } } else { sendMessage("No command available for \"" + words[0] + "\"."); } }
public bool RemoveMOB(MOB mob) { if (!mobs.Remove(mob)) { return(false); } this.Save(); return(true); }
/// <summary> /// Permanently removes a character from this account. /// </summary> /// <param name="mob"></param> /// <returns></returns> public bool RemoveCharacter(MOB mob) { if (unloadedCharacters.Remove(mob)) { mob.OwningAccount = null; this.Save(); return(true); } return(false); }
//TODO: Race/genes, body data specific to race(s). Hybrids will probably have a HybridBodyData with //sub-BodyData objects for each race and sort things out that way... also need Race/Body data stuff for vehicles, //which won't have genes but do have bodies. Maybe a modifications section for bodies that vehicles use entirely. //Also need indications of what functionality the body has and how to execute those functionalities / what they //cost. //Side concern: What if a spell or something can make an Item a Body? Probably need to figure out that edge case //at some point. Most inclined to make a special Body class that wraps the Item, but that definitely has some //issues I don't like. //MOB Bodys may be a subclass of this later? Pretty certain yes. Those bodies will contain stat lines and maybe //other stuff I figure out later. At the moment I can't actually think of anything other than a statline, basically. public bool AddMOB(MOB mob) { if (mobs.Contains(mob)) { return(false); } mobs.Add(mob); this.Save(); return(true); }
public override void Execute(MOB mob, QueuedCommand command) { StringWords input = command.parsedCommand; int distance = -1; MovementUnit unit; if (input.Segments.Length > 1) { TextParsing.ParseAsDistance(input, out distance, out unit, 1); } //TODO: finish this }
public void AddMOBLock(MOB mob) { while (true) { Body body = mob.Body; Room startingRoom = body.Position.ForRoom; lockToDispose.AddResource(startingRoom); if (body == mob.Body && body.Position.ForRoom == startingRoom) { return; } } }
public static List <Item> FindKnownItems(StringWords input, MOB mob, int start, int end) { input.ValidateEndIndex(ref end); Item[] items = GeneralUtilities.VisibleItems(mob, mob.Body); List <Item> matchingItems = new List <Item>(); foreach (Item item in items) { if (mob.CanRecognize(item, input, start, end)) { matchingItems.Add(item); } } return(matchingItems); }
/// <summary> /// Find an item that the specified mob can sense and identify from the given text input. /// </summary> /// <param name="input"></param> /// <param name="mob"></param> /// <param name="start"></param> /// <param name="end"></param> /// <param name="onPrompt"></param> /// <param name="addToPrompt"></param> /// <returns></returns> public static Item FindKnownItem(StringWords input, MOB mob, int start, int end, SelectAction onPrompt = null, StandardHeldPrompt addToPrompt = null) //, out RoomLink viaExit { //viaExit = null; //TODO later: When finding items in other rooms, report what direction the item is in. List <Item> options = FindKnownItems(input, mob, start, end); if (options.Count == 1) { return(options[0]); } Client client = mob.Client; if (client == null) { //TODO: Have an NPC say they don't know what item they were told to find? return(null); } if (options.Count == 0) { client.sendMessage("You don't notice a '" + input.StringRange(start, end) + "'"); return(null); } if (onPrompt == null) { client.sendMessage("There are too many things that fit that description."); return(null); } //TODO: Consider an alternative function to move prompt stuff to and add an out bool for prompting instead, not //sure if there's a need for that bool right now though; leave this one without prompt stuff //TODO: Some way to check if the prompt is still valid would be nice too, but not sure how to do that well without // just requiring another function passed into here. Might do that anyways. SelectFromList <Item> itemSelectPrompt = new SelectFromList <Item>(onPrompt.Invoke); if (addToPrompt == null || !addToPrompt.TransitionTo(itemSelectPrompt, true)) { client.Prompt(itemSelectPrompt); } return(null); }
/// <summary> /// Simpler function to call instead of ThreadManager.StartEvent. Return value works the same way. /// </summary> /// <param name="mob"></param> /// <returns></returns> public IDisposable StartEventFor(MOB mob, int timeout = 1000, bool?ignorePause = null) { restart: Body body = mob.Body; Room startingRoom = body.Position.ForRoom; IDisposable disposable; using (disposable = ThreadManager.StartEvent(startingRoom, this, timeout, ignorePause)) { if (disposable == null) { return(null); //Notify caller that event entirely failed. } if (mob.Body != body || body.Position.ForRoom != startingRoom) { // Race condition, need to try again with new body/get lock for new room. goto restart; //This is probably fine but might make something smarter later. } disposable = null; //Have the caller dispose this instead. return(this); } }
/// <summary> /// Permanently adds a character to this account. /// </summary> /// <param name="mob"></param> public void AddCharacter(MOB mob) { this.unloadedCharacters.Add(mob); mob.OwningAccount = this; this.Save(); }
/// <summary> /// Runs this command with the given mob and arguments. /// </summary> /// <param name="mob">Mob to perform the command.</param> /// <param name="command">Performed command data</param> public abstract void Execute(MOB mob, QueuedCommand command);
/// <summary> /// TODO: Move to a more appropriate place? /// Should be called for a MOB's commands when a specific command is disabled on them. /// </summary> // Honestly this probably shouldn't be used. It probably still makes sense to generate things all at once. //public void removeCommands(MOB mob) //{ // foreach (CommandEntry entry in this.CommandEntries) // { // //listOfCommands.BinaryRemove(entry); // } //} /// <summary> /// Checks if the given user or mob has access to this command. Doesn't mean they can use it, /// e.g. they may know a spell but not have the mana to cast it. /// </summary> /// <param name="user"></param> /// <param name="mob"></param> /// <returns>True if this command should be found in the mob's list of commands</returns> public abstract bool CanUse(Client user, MOB mob);
public static Room GetRoom(MOB fromMob) { return(fromMob.Body?.Position?.ForRoom); }
public void SetMoveSource(MOB mob, Body vehicle) { movementSource = mob; eventSource = vehicle ?? mob.Body; originalPosition = eventSource.Position; }
public override bool CanUse(Client user, MOB mob) { return(mob != null); }
public override void Execute(MOB mob, QueuedCommand command) { /* * Form is always (optional direction/distance) (optional preposition) (optional target) * direction/distance can work alone (implies 'from here') * if direction/distance is missing, if preposition is not specific, 'in reach' is implied * preposition requires a target * target can work alone (depends on target. If target defaults to enterable, implies 'in'. Else 'near') * Search for prepositions, get a list of them. * Validate prepositions. Need to have nothing or a valid direction/distance before preposition. * How many can actually be possible? I think only zero or one preposition is really possible? * TODO: Special user input to specify a preposition instead of parser guessing. Mostly goes in StringWords but * matching prepositions/item names needs to respect that too (might work automatically). * Some system similar to quotes probably. Quotes may be useful though, like book titles or something. * If no prepositions, attempt to parse full string as direction/distance. If successful, do that * //Search whole string for item/target matches and associated strings. * In general, 'visible to MOB' items. * Must match to end of string? * Nevermind, this string will be identified but targets will not be searched for until a TryGoEvent is run. * //Find associated strings that line up with a preposition * Instead of above two major points: * Identify all valid strings (start after preposition, go to end of string) * TODO: Special user input to specify a string instead of parser guessing? * This is basically implied by a preposition. However it maybe makes more sense to specify the target instead of the preposition. * //Search all 'visible to MOB' items that exactly match any of the valid strings. * How to pick best match? * Maybe just not go if more than one match found, request more info. prompt? */ StringWords goToInput = command.parsedCommand; //See if there's a preposition int start = 1; //Skip command ("go") int prepValue; MovementPreposition prepEnum; MovementDirection direction = null; TryGoEvent moveEvent = new TryGoEvent(); int index = TextParsing.FindAPreposition(goToInput, typeof(MovementPreposition), out prepValue, start); if (index != -1) { //Is this a valid preposition? Check if it starts correctly. prepEnum = (MovementPreposition)prepValue; if (!prepEnum.AllowDirection() && !prepEnum.AllowDistance()) { if (index != start + 1) { //Invalid preposition for this location, needs to be at start of command. goto noPrepositionFound; } } else if ((prepEnum.RequireDirection() || prepEnum.RequireDistance()) && index == start + 1) { //Invalid preposition for this location, needs to come after a direction/distance. goto noPrepositionFound; } else { direction = TextParsing.ParseAsDirection(goToInput, start, ref index, prepEnum.RequireDirection(), prepEnum.RequireDistance(), prepEnum.AllowDirection(), prepEnum.AllowDistance()); if (direction == null) //Not a valid preposition. Ignore it. { goto noPrepositionFound; } else //Maybe valid preposition. { //Check if preposition matches direction more closely? I think the previous checks have finished that successfully at this point. //Valid preposition. Parse the REST of the sentence as an object. start = index; goto startEvent; } } } else { //Is the whole thing a direction? direction = TextParsing.ParseAsDirection(goToInput, start, ref index); if (direction != null) { if (direction.direction != Directions.NoDirection && index == goToInput.Segments.Length) { //Mark it as ONLY a direction, no destination (goToInput has been completely parsed/consumed) goToInput = null; //goto startEvent; } else { //Can't go only a distance with NoDirection. Cancel this parsing. direction = null; } } //Else try to parse the whole thing as an object to go to } //Text parsing has decided what words go to what (i.e. direction vs. target). //Text parsing has NOT identified objects yet. noPrepositionFound: moveEvent.targetDescription = goToInput; start = 1; prepEnum = MovementPreposition.To; // null; ? startEvent: //foundPreposition moveEvent.targetDescriptionStart = start; moveEvent.direction = direction; moveEvent.relation = prepEnum; moveEvent.SetMoveSource(mob, null); //Raw command parsing done, target parsing has not been done. //Run the event to try to find a path to the target. moveEvent.FullRunEvent(); }
/// <summary> /// Check if the specified MOB can see this event happening. /// </summary> /// <param name="mob">The MOB trying to observe this event.</param> /// <param name="focus">What the MOB is using to see this event (their own eyes, a scrying effect, etc.)</param> /// <returns></returns> public virtual bool CanObserveThis(MOB mob, object focus) { return(false); }