Exemple #1
0
        private async Task _removePrey(Species predatorSpecies, Species preySpecies)
        {
            if (predatorSpecies is null || preySpecies is null)
            {
                return;
            }

            // Remove the relationship.

            // Ensure that the user has necessary privileges to use this command.
            if (!await BotUtils.ReplyHasPrivilegeOrOwnershipAsync(Context, PrivilegeLevel.ServerModerator, predatorSpecies))
            {
                return;
            }

            PreyInfo[] existing_prey = await SpeciesUtils.GetPreyAsync(predatorSpecies);

            if (existing_prey.Any(x => x.Prey.Id == preySpecies.Id))
            {
                using (SQLiteCommand cmd = new SQLiteCommand("DELETE FROM Predates WHERE species_id = $species_id AND eats_id = $eats_id")) {
                    cmd.Parameters.AddWithValue("$species_id", predatorSpecies.Id);
                    cmd.Parameters.AddWithValue("$eats_id", preySpecies.Id);

                    await Database.ExecuteNonQuery(cmd);
                }

                await BotUtils.ReplyAsync_Success(Context, string.Format("**{0}** no longer preys upon **{1}**.",
                                                                         predatorSpecies.ShortName,
                                                                         preySpecies.ShortName));
            }
            else
            {
                await BotUtils.ReplyAsync_Warning(Context, string.Format("**{0}** does not prey upon **{1}**.",
                                                                         predatorSpecies.ShortName,
                                                                         preySpecies.ShortName));
            }
        }
Exemple #2
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();
        }