// args: left/right targetID public bool OnPerform(Character chr, string args) { if (args == null || args == "") { chr.WriteToDisplay("Who do you want to Battle Charge?"); return(false); } if (!MeetsRequirements(chr, null)) { return(false); } string[] sArgs = args.Split(" ".ToCharArray()); Character target = GameSystems.Targeting.TargetAquisition.AcquireTarget(chr, args, GameWorld.Cell.DEFAULT_VISIBLE_DISTANCE, 0); // safety net if (target == null) { return(false); } if (target.CurrentCell != chr.CurrentCell) { if (!PathTest.SuccessfulPathTest(PathTest.RESERVED_NAME_JUMPKICKCOMMAND, chr.CurrentCell, target.CurrentCell)) { chr.WriteToDisplay(GameSystems.Text.TextManager.PATH_IS_BLOCKED); return(false); } } if (GameWorld.Cell.GetCellDistance(chr.X, chr.Y, target.X, target.Y) < 1) { chr.WriteToDisplay("Your target is too close for you to charge into battle."); return(false); } chr.WriteToDisplay("You charge into battle!"); target.WriteToDisplay(chr.GetNameForActionResult() + " charges you!"); chr.CommandType = CommandTasker.CommandType.BattleCharge; chr.CurrentCell = target.CurrentCell; Combat.DoCombat(chr, target, chr.RightHand); // TODO: emit battle charge sound // Battle charge with a shield does an automatic bash. if (chr.HasTalent(GameTalent.TALENTS.Bash) && chr.LeftHand != null && chr.LeftHand.baseType == eItemBaseType.Shield) { GameTalent gtShieldBash = GameTalent.GameTalentDictionary[GameTalent.TALENTS.Bash.ToString().ToLower()]; if (gtShieldBash.MeetsPerformanceCost(chr) && gtShieldBash.Handler.OnPerform(chr, args)) { gtShieldBash.SuccessfulPerformance(chr); } } return(true); }
/// <summary> /// Interpret incoming command. To be moved to a Command Manager or GameCommand in the near future. /// </summary> /// <param name="command"></param> /// <param name="args"></param> /// <returns>False if invalid command. True if the command was completed.</returns> public bool InterpretCommand(string command, string args) { var i = 0; var sCmdAndArgs = command + " " + args; var newArgs = ""; // Dead characters can only rest or quit. if (_chr.IsDead && command.ToLower() != "rest" && command.ToLower() != "quit") { _chr.WriteToDisplay("You are dead, you can either wait to be resurrected or rest."); return(true); } #region If a command is being interpreted then the character is no longer resting or meditating. if (_chr.IsResting && !_chr.IsMeditating) { if (command.ToLower() != "rest" && !command.StartsWith(((char)27).ToString()) && !command.StartsWith("show")) { _chr.WriteToDisplay("You are no longer resting."); _chr.IsResting = false; } } if (_chr.IsMeditating) { // using the "meditate" command while meditating will cancel meditation if (command.ToLower() != "memorize" && !command.StartsWith(((char)27).ToString()) && // protocol command !command.StartsWith("show")) { _chr.WriteToDisplay("You are no longer meditating."); _chr.IsResting = false; _chr.IsMeditating = false; } } #endregion // Any command while peeking will be an automatic rest and break the character out of the trance. if (_chr.IsPeeking) { command = "rest"; args = ""; } #region If wizard eye // Only movement, look, rest and again are acceptable commands when in wizard eye. if (_chr.IsWizardEye) { command = command.ToLower(); switch (command.ToLower()) { case "n": case "north": case "s": case "south": case "e": case "east": case "w": case "west": case "ne": case "northeast": case "nw": case "northwest": case "se": case "southeast": case "sw": case "southwest": case "d": case "down": case "u": case "up": case "a": case "again": case "l": case "look": case "rest": break; default: _chr.WriteToDisplay("You cannot use that command while polymorphed."); return(true); } } #endregion if (_chr.protocol == DragonsSpineMain.Instance.Settings.DefaultProtocol) { if (ProtocolYuusha.CheckGameCommand(_chr, command, args)) { return(true); } } // catch some commands before they go through the parser #region If Speech. Command starts with a / or a " while in game. if (command.StartsWith("/") || command.StartsWith("\"")) { if (!_chr.IsImmortal && _chr.HasEffect(Effect.EffectTypes.Silence)) { _chr.WriteToDisplay("You have been silenced and are unable to speak."); return(true); } if (args.IndexOf("/!") != -1) { _chr.SendShout(_chr.Name + ": " + args.Substring(0, args.IndexOf("/!"))); if (_chr.IsPC) { _chr.WriteToDisplay("You shout: " + args.Substring(0, args.IndexOf("/!"))); Utils.Log(_chr.Name + ": " + args.Substring(0, args.IndexOf("/!")), Utils.LogType.PlayerChat); } return(true); } else if (args.IndexOf("\"!") != -1) { _chr.SendShout(_chr.Name + ": " + args.Substring(0, args.IndexOf("\"!"))); if (_chr.IsPC) { _chr.WriteToDisplay("You shout: " + args.Substring(0, args.IndexOf("\"!"))); Utils.Log(_chr.Name + ": " + args.Substring(0, args.IndexOf("\"!")), Utils.LogType.PlayerChat); } return(true); } else { _chr.SendToAllInSight(_chr.Name + ": " + args); if (_chr.IsPC) { _chr.WriteToDisplay("You say: " + args); Utils.Log(_chr.Name + ": " + args, Utils.LogType.PlayerChat); } return(true); } } #endregion #region NPC interaction. Command ends with a comma (,) else if (command.EndsWith(","))// && !command.ToLower().StartsWith("all")) { if (!_chr.IsImmortal && _chr.HasEffect(Effect.EffectTypes.Silence)) { _chr.WriteToDisplay("You have been silenced and are unable to speak."); return(true); } try { // djinn, take halberd // djinn, take 2 halberd // 2 djinn, take 2 halberd // all, follow me string targetName = command.Substring(0, command.IndexOf(",")); // definitely going to be a comma string[] targetArgs = targetName.Split(" ".ToCharArray()); // if this is longer than 1 in length probably using # args = args.Trim(); string[] sArgs = args.Split(" ".ToCharArray()); if (String.IsNullOrEmpty(sArgs[0]) || sArgs.Length == 0) { return(false); } string order = sArgs[0]; args = args.Replace(order, ""); args = args.Trim(); #region All, do something if (command.ToLower().StartsWith("all")) { if (_chr.Pets == null || _chr.Pets.Count == 0) { _chr.WriteToDisplay("There is nothing here to interact with."); return(true); } bool interactPositive = false; foreach (NPC pet in new List <NPC>(_chr.Pets)) { if (TargetAcquisition.FindTargetInView(_chr, pet) != null) { interactPositive = AI.Interact(_chr, pet, order, args); } } return(interactPositive); } #endregion Character target = null; var countTo = 0; // Not using ALL, try 2 <target>, do something. if (targetArgs.Length > 1 && Int32.TryParse(targetArgs[0], out countTo)) { target = TargetAcquisition.FindTargetInView(_chr, targetArgs[1].ToLower(), countTo); } // Not using ALL, try <target>, do something. if (target == null && targetArgs.Length == 1) { target = TargetAcquisition.FindTargetInView(_chr, targetArgs[0].ToLower(), 1); if (target == null) { target = TargetAcquisition.FindTargetInView(_chr, targetName, false, false); } } if (target == null) { _chr.WriteToDisplay("You do not see " + targetName + " here."); return(true); } else { return(AI.Interact(_chr, target, order, args)); } } catch (Exception e) { Utils.LogException(e); return(false); } } #endregion else { int andStrPos = 0; #region Check for command joining, split them then parse and int // If command has the word "and" for joining two commands. // 9/24/2019 We don't still need this. //if (_chr.PCState == Globals.ePlayerState.PLAYING && sCmdAndArgs.IndexOf(" and ") != -1 && command.ToLower() != "tell" && ) // sCmdAndArgs = sCmdAndArgs.Replace(" and ", ";"); andStrPos = sCmdAndArgs.IndexOf(";", 0, sCmdAndArgs.Length); if (andStrPos > 0) { //Break out the two commands string[] sCommands = sCmdAndArgs.Split(";".ToCharArray()); if (sCommands[0].Length > 0) { //get the command and the args sCommands[0] = sCommands[0].Trim();//.ToLower(); string[] sArgss = sCommands[0].Split(" ".ToCharArray()); for (i = 1; i <= sArgss.GetUpperBound(0); i++) { newArgs = newArgs + " " + sArgss[i]; } ParseCommand(_chr, sArgss[0].ToString().Trim(), newArgs.Trim()); //chr.FirstJoinedCommand = chr.CommandsProcessed[0]; //chr.FirstJoinedCommand = chr.CommandType; } if (sCommands[1].Length > 0) { //get the command and the args sCommands[1] = sCommands[1].Trim();//.ToLower(); string[] s2Argss = sCommands[1].Split(" ".ToCharArray()); newArgs = ""; for (i = 1; i <= s2Argss.GetUpperBound(0); i++) { if (s2Argss[i].ToLower() != "it") { newArgs = newArgs + " " + s2Argss[i]; } else { string[] sArgss = sCommands[0].Split(" ".ToCharArray()); newArgs = newArgs + " " + sArgss[1]; } } ParseCommand(_chr, s2Argss[0].ToString().Trim(), newArgs.Trim()); //chr.FirstJoinedCommand = CommandType.None; } return(true); } #endregion if (command.StartsWith("$")) { if (command.Contains("list")) { args = "list"; } else if (command.Length > 1 && command.Length < 4) { args = command.Substring(1, command.Length - 1) + " " + args; args.Trim(); } command = "macro"; } // lower case command = command.ToLower(); #region Check command aliases and change the command if an alias is found. if (GameCommand.GameCommandAliases.ContainsKey(command)) { command = GameCommand.GameCommandAliases[command]; } else if (GameCommand.GameCommandAliases.ContainsKey(command + " " + args)) { command = GameCommand.GameCommandAliases[command + " " + args]; } #endregion // check for the command in the dictionary if (GameCommand.GameCommandDictionary.ContainsKey(command)) { // non player characters make no checks to perform commands if (!(_chr is PC)) { return(GameCommand.GameCommandDictionary[command].Handler.OnCommand(_chr, args)); } GameCommand gc = GameCommand.GameCommandDictionary[command]; // check player ImpLevel and the command may be executed while playing the game if ((_chr as PC).ImpLevel >= (Globals.eImpLevel)gc.PrivLevel && Array.IndexOf(gc.States, _chr.PCState) > -1) { _chr.CommandWeight += gc.Weight; return(GameCommand.GameCommandDictionary[command].Handler.OnCommand(_chr, args)); } return(false); } else if (Talents.GameTalent.GameTalentDictionary.ContainsKey(command)) { Talents.GameTalent gameTalent = Talents.GameTalent.GameTalentDictionary[command]; // immortal flag added for testing purposes if ((_chr.IsImmortal || _chr.talentsDictionary.ContainsKey(command)) && !gameTalent.IsPassive) { if (_chr.IsImmortal || (DateTime.UtcNow - gameTalent.DownTime >= _chr.talentsDictionary[command])) { if (!gameTalent.MeetsPerformanceCost(_chr)) { _chr.WriteToDisplay("You do not have enough stamina to perform the " + gameTalent.Name + " talent."); return(true); } if (!Talents.GameTalent.GameTalentDictionary[command].Handler.OnPerform(_chr, args)) { _chr.WriteToDisplay("Talent not performed."); } else { gameTalent.SuccessfulPerformance(_chr); } } else { int roundsRemaining = Utils.TimeSpanToRounds(gameTalent.DownTime - (DateTime.UtcNow - _chr.talentsDictionary[command])); _chr.WriteToDisplay("Talent timer has not reset yet. It will be available " + (roundsRemaining > 0 ? "in " + roundsRemaining : "next") + " round" + (roundsRemaining > 1 ? "s" : "") + "."); } } else if (_chr.talentsDictionary.ContainsKey(command) && gameTalent.IsPassive) { _chr.WriteToDisplay(gameTalent.Name + " is a passive talent."); } else { _chr.WriteToDisplay("You do not know how to perform the " + gameTalent.Name + " talent."); } return(true); } else // command does not exist in the dictionary { MethodInfo[] methodInfo = typeof(CommandTasker).GetMethods(); try { foreach (MethodInfo m in methodInfo) { int length = m.Name.Length; if (m.Name.IndexOf("_") != -1) { length = m.Name.IndexOf("_"); } if (m.Name.ToLower().Substring(0, length) == command) { _chr.CommandWeight += 1; // add one to the command weight object[] obj = new object[1]; obj[0] = args; try { m.Invoke(this, obj); } catch (Exception e) { Utils.LogException(e); } return(true); } } } catch (Exception e) { _chr.WriteToDisplay("Error processing your command. Please report this."); Utils.Log("Failure at Command.interpretCommand(" + command + ", " + args + ")", Utils.LogType.SystemFailure); Utils.LogException(e); return(false); } } } #region Spell Chant Exists if (_chr.spellDictionary.ContainsValue(command.ToLower() + " " + args.ToLower())) { if (!_chr.IsImmortal && _chr.InUnderworld) { _chr.WriteToDisplay(TextManager.COMMAND_NOT_UNDERSTOOD); return(true); } if (!_chr.IsImmortal && _chr.HasEffect(Effect.EffectTypes.Silence)) { _chr.WriteToDisplay("You have been silenced and are unable to warm spells."); return(true); } if (_chr.preppedSpell != null) // TODO talent here to automatically clear prepped spell { _chr.WriteToDisplay("You already have a spell warmed. Either cast it or rest to clear your mind."); return(true); } else { _chr.CommandWeight += 3; if (_chr.CommandWeight == 3) { _chr.CommandType = CommandType.Chant; foreach (int spellID in _chr.spellDictionary.Keys) { if (_chr.spellDictionary[spellID] == (command.ToLower() + " " + args.ToLower())) { _chr.WarmSpell(spellID); break; } } //if(_chr is PC) // World.magicCordThisRound.Add(_chr.FacetID + "|" + _chr.LandID + "|" + _chr.MapID + "|" + _chr.X + "|" + _chr.Y + "|" + _chr.Z); _chr.PreppedRound = DragonsSpineMain.GameRound; int bitcount = 0; Cell curCell = null; // this is the same logic from chr.sendToAllInSight, however we add spell info in some situations // loop through all visible cells for (int ypos = -3; ypos <= 3; ypos += 1) { for (int xpos = -3; xpos <= 3; xpos += 1) { if (Cell.CellRequestInBounds(_chr.CurrentCell, xpos, ypos)) { if (_chr.CurrentCell.visCells[bitcount]) // check the PC list, and char list of the cell { curCell = Cell.GetCell(_chr.FacetID, _chr.LandID, _chr.MapID, _chr.X + xpos, _chr.Y + ypos, _chr.Z); if (curCell != null) { foreach (Character character in curCell.Characters.Values) // search for the character in the charlist of the cell { if (character != _chr && character is PC) // players sending messages to other players { if (Array.IndexOf((character as PC).ignoreList, _chr.UniqueID) == -1) // ignore list { if ((_chr.Group != null && _chr.preppedSpell != null && _chr.Group.GroupMemberIDList.Contains(character.UniqueID)) || (character as PC).ImpLevel >= Globals.eImpLevel.GM || character.HasEffect(Effect.EffectTypes.Gnostikos)) { character.WriteToDisplay(_chr.Name + ": " + command + " " + args + " <" + _chr.preppedSpell.Name + ">"); } else { character.WriteToDisplay(_chr.Name + ": " + command + " " + args); } } } else if (character != _chr && character.IsPC && !_chr.IsPC) // non players sending messages to other players { character.WriteToDisplay(_chr.Name + ": " + command + " " + args); } //TODO: else... detect spell casting by sensitive NPC } } } bitcount++; } } } } else { _chr.WriteToDisplay("Warming a spell requires your full concentration."); } } return(true); } #endregion Utils.Log(_chr.GetLogString() + " Invalid command: " + command + " args: " + args, Utils.LogType.CommandFailure); _chr.WriteToDisplay("I don't understand your command. For a full list of game commands visit the Dragon's Spine forums."); return(false); }