Esempio n. 1
0
        public async Task <bool> OnTurnEndAsync(GotchiMoveCallbackArgs args)
        {
            if (_script.Globals[OnTurnEnd] != null)
            {
                await _script.CallAsync(_script.Globals[OnTurnEnd], args);

                return(true);
            }

            return(false);
        }
Esempio n. 2
0
        private async Task _applyStatusProblemsAsync(PlayerState affectedUser, PlayerState otherUser)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat(battleText);

            if (affectedUser.Gotchi.HasStatus)
            {
                GotchiStatus           status = affectedUser.Gotchi.Status;
                GotchiStatusLuaScript  script = new GotchiStatusLuaScript(status.LuaScriptFilePath);
                GotchiMoveCallbackArgs args   = await _createCallbackArgsAsync(otherUser, affectedUser);

                // Call the "OnTurnEnd" callback.
                await script.OnTurnEndAsync(args);

                // Apply other properties.

                affectedUser.Gotchi.Stats.Hp -= status.SlipDamage;
                affectedUser.Gotchi.Stats.Hp -= (int)(status.SlipDamagePercent * affectedUser.Gotchi.Stats.MaxHp);

                // Show status text.

                if (!string.IsNullOrEmpty(args.Text))
                {
                    sb.Append(string.Format("\n⚡ **{0}** {1}!", affectedUser.Gotchi.Gotchi.Name, args.Text));
                }

                // Decrement the duration of the status, clearing it if the duration has been completed.

                if (!status.Permanent && --status.Duration <= 0)
                {
                    affectedUser.Gotchi.ClearStatus();
                }
            }

            battleText = sb.ToString();
        }
Esempio n. 3
0
        private async Task _useMoveOnAsync(ICommandContext context, PlayerState user, PlayerState target)
        {
            // Execute the selected move.

            StringBuilder battle_text = new StringBuilder();

            battle_text.AppendLine(battleText);

            if (!string.IsNullOrEmpty(user.SelectedMove.LuaScriptFilePath))
            {
                // Create, initialize, and execute the script associated with this move.

                GotchiMoveLuaScript moveScript = new GotchiMoveLuaScript(user.SelectedMove.LuaScriptFilePath);

                GotchiMoveCallbackArgs args = await _createCallbackArgsAsync(user, target);

                // Call the move's "OnInit" callback (only applicable for some moves).
                await moveScript.OnInitAsync(args);

                // It's possible for a move to be used more than once in a turn (e.g., multi-hit moves).
                // Each time will trigger the callback to be called and display a new message.

                for (int i = 0; i < Math.Max(1, args.Times); ++i)
                {
                    // Check if this was a critical hit, or if the move missed.

                    bool is_hit = user.SelectedMove.IgnoreAccuracy || (BotUtils.RandomInteger(0, 20 + 1) < 20 * user.SelectedMove.Accuracy * Math.Max(0.1, user.Gotchi.Stats.Acc - target.Gotchi.Stats.Eva));
                    args.IsCritical =
                        !user.SelectedMove.IgnoreCritical &&
                        (BotUtils.RandomInteger(0, (int)(10 / user.SelectedMove.CriticalRate)) == 0 ||
                         (await SpeciesUtils.GetPreyAsync(user.Gotchi.Gotchi.SpeciesId)).Any(x => x.Prey.Id == target.Gotchi.Gotchi.Id));

                    if (is_hit)
                    {
                        // Clone each user's stats before triggering the callback, so we can compare them before and after.

                        GotchiStats user_before   = user.Gotchi.Stats.Clone();
                        GotchiStats target_before = target.Gotchi.Stats.Clone();

                        // Invoke the callback.

                        try {
                            if (!await moveScript.OnMoveAsync(args))
                            {
                                args.DealDamage(user.SelectedMove.Power);
                            }
                        }
                        catch (Exception) {
                            args.Text = "but something went wrong";
                        }

                        // Apply the target's status if a new status was acquired.

                        if (target.Gotchi.StatusChanged && target.Gotchi.HasStatus)
                        {
                            await new GotchiStatusLuaScript(target.Gotchi.Status.LuaScriptFilePath).OnAcquireAsync(args);

                            target.Gotchi.StatusChanged = false;
                        }

                        // Prevent the target from fainting if they're able to endure the hit.

                        if (target.Gotchi.HasStatus && target.Gotchi.Status.Endure)
                        {
                            target.Gotchi.Stats.Hp = Math.Max(1, target.Gotchi.Stats.Hp);
                        }

                        // If the user is heal-blocked, prevent recovery by resetting the HP back to what it was before recovery.

                        if (user.Gotchi.HasStatus && !user.Gotchi.Status.AllowRecovery && user.Gotchi.Stats.Hp > user_before.Hp)
                        {
                            user.Gotchi.Stats.Hp = user_before.Hp;
                        }

                        // Show the battle text.
                        // If the move doesn't specify a text, choose one automatically (where possible).

                        string text = args.Text;

                        if (string.IsNullOrEmpty(text))
                        {
                            if (target.Gotchi.Stats.Hp < target_before.Hp)
                            {
                                text = "dealing {target:damage} damage";
                                //user.SelectedMove.info.Type = GotchiMoveType.Offensive;
                            }

                            else if (target.Gotchi.Stats.Atk < target_before.Atk)
                            {
                                text = "lowering its opponent's ATK by {target:atk%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (target.Gotchi.Stats.Def < target_before.Def)
                            {
                                text = "lowering its opponent's DEF by {target:def%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (target.Gotchi.Stats.Spd < target_before.Spd)
                            {
                                text = "lowering its opponent's SPD by {target:spd%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (target.Gotchi.Stats.Acc < target_before.Acc)
                            {
                                text = "lowering its opponent's accuracy by {target:acc%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (target.Gotchi.Stats.Eva < target_before.Eva)
                            {
                                text = "lowering its opponent's evasion by {target:eva%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }

                            else if (user.Gotchi.Stats.Hp > user_before.Hp)
                            {
                                text = "recovering {user:recovered} HP";
                                //user.SelectedMove.info.Type = GotchiMoveType.Recovery;
                            }
                            else if (user.Gotchi.Stats.Atk > user_before.Atk)
                            {
                                text = "boosting its ATK by {user:atk%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (user.Gotchi.Stats.Def > user_before.Def)
                            {
                                text = "boosting its DEF by {user:def%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (user.Gotchi.Stats.Spd > user_before.Spd)
                            {
                                text = "boosting its SPD by {user:spd%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (user.Gotchi.Stats.Acc > user_before.Acc)
                            {
                                text = "boosting its accuracy by {user:acc%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }
                            else if (user.Gotchi.Stats.Eva > user_before.Eva)
                            {
                                text = "boosting its evasion by {user:eva%}";
                                //user.SelectedMove.info.Type = GotchiMoveType.Buff;
                            }

                            else
                            {
                                text = "but nothing happened?";
                            }
                        }

                        // Various replacements are allowed, which the user can specify in the move's battle text.

                        text = Regex.Replace(text, @"\{([^\}]+)\}", m => {
                            switch (m.Groups[1].Value.ToLower())
                            {
                            case "damage":
                            case "target:damage":
                                return(string.Format("{0:0.#}", target_before.Hp - target.Gotchi.Stats.Hp));

                            case "target:atk%":
                                return(string.Format("{0:0.#}%", Math.Abs(target_before.Atk - target.Gotchi.Stats.Atk) / (double)target_before.Atk * 100.0));

                            case "target:def%":
                                return(string.Format("{0:0.#}%", Math.Abs(target_before.Def - target.Gotchi.Stats.Def) / (double)target_before.Def * 100.0));

                            case "target:spd%":
                                return(string.Format("{0:0.#}%", Math.Abs(target_before.Spd - target.Gotchi.Stats.Spd) / (double)target_before.Spd * 100.0));

                            case "target:acc%":
                                return(string.Format("{0:0.#}%", Math.Abs(target_before.Acc - target.Gotchi.Stats.Acc) / target_before.Acc * 100.0));

                            case "target:eva%":
                                return(string.Format("{0:0.#}%", Math.Abs(target_before.Eva - target.Gotchi.Stats.Eva) / target_before.Eva * 100.0));

                            case "user:atk%":
                                return(string.Format("{0:0.#}%", Math.Abs(user_before.Atk - user.Gotchi.Stats.Atk) / (double)user_before.Atk * 100.0));

                            case "user:def%":
                                return(string.Format("{0:0.#}%", Math.Abs(user_before.Def - user.Gotchi.Stats.Def) / (double)user_before.Def * 100.0));

                            case "user:spd%":
                                return(string.Format("{0:0.#}%", Math.Abs(user_before.Spd - user.Gotchi.Stats.Spd) / (double)user_before.Spd * 100.0));

                            case "user:acc%":
                                return(string.Format("{0:0.#}%", Math.Abs(user_before.Acc - user.Gotchi.Stats.Acc) / user_before.Acc * 100.0));

                            case "user:eva%":
                                return(string.Format("{0:0.#}%", (user_before.Eva == 0.0 ? user.Gotchi.Stats.Eva : (Math.Abs(user_before.Eva - user.Gotchi.Stats.Eva) / user_before.Eva)) * 100.0));

                            case "user:recovered":
                                return(string.Format("{0:0.#}", user.Gotchi.Stats.Hp - user_before.Hp));

                            default:
                                return("???");
                            }
                        });

                        battle_text.Append(string.Format("{0} **{1}** used **{2}**, {3}!",
                                                         "💥", //user.SelectedMove.info.Icon(),
                                                         user.Gotchi.Gotchi.Name,
                                                         user.SelectedMove.Name,
                                                         text));

                        if (args.IsCritical && target.Gotchi.Stats.Hp < target_before.Hp)
                        {
                            battle_text.Append(" Critical hit!");
                        }

                        if (args.MatchupMultiplier > 1.0)
                        {
                            battle_text.Append(" It's super effective!");
                        }
                        else if (args.MatchupMultiplier < 1.0)
                        {
                            battle_text.Append(" It's not very effective...");
                        }

                        battle_text.AppendLine();
                    }
                    else
                    {
                        // If the move missed, so display a failure message.
                        battle_text.AppendLine(string.Format("{0} **{1}** used **{2}**, but it missed!",
                                                             "💥", //user.SelectedMove.info.Icon(),
                                                             user.Gotchi.Gotchi.Name,
                                                             user.SelectedMove.Name));
                    }
                }

                if (args.Times > 1)
                {
                    battle_text.Append(string.Format(" Hit {0} times!", args.Times));
                }
            }
            else
            {
                // If there is no Lua script associated with the given move, display a failure message.
                battle_text.Append(string.Format("{0} **{1}** used **{2}**, but it forgot how!",
                                                 "💥", //user.SelectedMove.info.Icon(),
                                                 user.Gotchi.Gotchi.Name,
                                                 user.SelectedMove.Name));
            }

            battleText = battle_text.ToString();
        }