Example #1
0
        public static async Task <bool> ValidateTradeRequestAsync(ICommandContext context, SQLiteDatabase db, GotchiTradeRequest tradeRequest)
        {
            // The request is invalid if:
            // - Either user involved in the trade has gotten a new gotchi since the trade was initiated
            // - Either gotchi has died since the trade was initiated
            // - The request has expired

            if (tradeRequest.IsExpired || tradeRequest.OfferedGotchi is null || tradeRequest.ReceivedGotchi is null)
            {
                return(false);
            }

            IUser user1 = await context.Guild.GetUserAsync(tradeRequest.OfferedGotchi.OwnerId);

            Gotchi gotchi1 = user1 is null ? null : await db.GetGotchiAsync(user1.ToCreator());

            if (gotchi1 is null || !gotchi1.IsAlive || gotchi1.Id != tradeRequest.OfferedGotchi.Id)
            {
                return(false);
            }

            IUser user2 = await context.Guild.GetUserAsync(tradeRequest.ReceivedGotchi.OwnerId);

            Gotchi gotchi2 = user2 is null ? null : await db.GetGotchiAsync(user2.ToCreator());

            if (gotchi2 is null || !gotchi1.IsAlive || gotchi2.Id != tradeRequest.ReceivedGotchi.Id)
            {
                return(false);
            }

            return(true);
        }
        private static async Task _calculateDescriptionBasedBaseStats(Gotchi gotchi, GotchiStats stats)
        {
            Species species = await SpeciesUtils.GetSpeciesAsync(gotchi.SpeciesId);

            int weight = 20;

            if (Regex.IsMatch(species.Description, "photosynthesi(s|izes)", RegexOptions.IgnoreCase))
            {
                stats.MaxHp += weight;
            }

            if (Regex.IsMatch(species.Description, "spikes?|claws?|teeth|jaws|fangs", RegexOptions.IgnoreCase))
            {
                stats.Atk += weight;
            }

            if (Regex.IsMatch(species.Description, "shell|carapace|exoskeleton", RegexOptions.IgnoreCase))
            {
                stats.Def += weight;
            }

            foreach (Match m in Regex.Matches(species.Description, "flies|fly|quick|fast|agile|nimble", RegexOptions.IgnoreCase))
            {
                stats.Spd += weight;
            }

            foreach (Match m in Regex.Matches(species.Description, "slow|heavy", RegexOptions.IgnoreCase))
            {
                stats.Spd -= weight;
            }
        }
        public static async Task <Gotchi> GetGotchiAsync(IUser user)
        {
            GotchiUserInfo userData = await GetUserInfoAsync(user);

            // Get this user's primary Gotchi.

            Gotchi gotchi = await GetGotchiAsync(userData.PrimaryGotchiId);

            // If this user's primary gotchi doesn't exist (either it was never set or no longer exists), pick a primary gotchi from their current gotchis.

            if (gotchi is null)
            {
                Gotchi[] gotchis = await GetGotchisAsync(userData.UserId);

                if (gotchis.Count() > 0)
                {
                    gotchi = gotchis[0];

                    userData.PrimaryGotchiId = gotchi.Id;

                    await UpdateUserInfoAsync(userData);
                }
            }

            return(gotchi);
        }
Example #4
0
        public GotchiStats GetGotchiStats(Gotchi gotchi)
        {
            if (gotchi.Id == player1.Gotchi.Gotchi.Id)
            {
                return(player1.Gotchi.Stats);
            }
            else if (gotchi.Id == player2.Gotchi.Gotchi.Id)
            {
                return(player2.Gotchi.Stats);
            }

            return(null);
        }
Example #5
0
        public GotchiMoveSet GetGotchiMoveset(Gotchi gotchi)
        {
            if (gotchi.Id == player1.Gotchi.Gotchi.Id)
            {
                return(player1.Gotchi.Moves);
            }
            else if (gotchi.Id == player2.Gotchi.Gotchi.Id)
            {
                return(player2.Gotchi.Moves);
            }

            return(null);
        }
Example #6
0
        private double _getExpEarned(Gotchi gotchi, Gotchi opponent, bool won)
        {
            double exp = 0.0;

            exp = (opponent.Id == player1.Gotchi.Gotchi.Id ? player1.Gotchi.Stats.Level : player2.Gotchi.Stats.Level) * 10.0;

            if (!won)
            {
                exp *= .5;
            }

            return(exp);
        }
Example #7
0
        public static GotchiTradeRequest GetTradeRequest(Gotchi recievedGotchi)
        {
            // Returns the trade request that this user is a partner in.
            // If the partner has changed gotchis since the request was initiated, the request is invalid and thus not returned.

            foreach (GotchiTradeRequest request in _trade_requests)
            {
                if (request.ReceivedGotchi.OwnerId == recievedGotchi.OwnerId && request.ReceivedGotchi.Id == recievedGotchi.Id)
                {
                    return(request);
                }
            }

            return(null);
        }
Example #8
0
        public async Task <GotchiMoveSet> GetMoveSetAsync(SQLiteDatabase database, Gotchi gotchi)
        {
            IEnumerable <GotchiMove> learnSet = await GetLearnSetAsync(database, gotchi);

            GotchiMoveSet set = new GotchiMoveSet();

            Random rng = new Random((int)gotchi.SpeciesId);

            set.AddRange(learnSet
                         .Skip(Math.Max(0, learnSet.Count() - GotchiMoveSet.MoveLimit))
                         .OrderBy(x => rng.Next()));

            set.Moves.Sort((lhs, rhs) => lhs.Name.CompareTo(rhs.Name));

            return(set);
        }
        public async Task <GotchiType[]> GetTypesAsync(Gotchi gotchi)
        {
            List <GotchiType> types = new List <GotchiType>();

            foreach (GotchiType type in await GetTypesAsync())
            {
                if (await new GotchiRequirementsChecker {
                    Requires = type.Requires
                }.CheckAsync(gotchi))
                {
                    types.Add(type);
                }
            }

            return(types.ToArray());
        }
        private async Task <bool> _checkRolesAsync(Gotchi gotchi, GotchiRequirements requirements)
        {
            try {
                IEnumerable <IRole> roles = await database.GetRolesAsync(gotchi.SpeciesId);

                foreach (Role role in roles)
                {
                    if (Regex.IsMatch(role.Name, requirements.RolePattern, RegexOptions.IgnoreCase))
                    {
                        return(true);
                    }
                }
            }
            catch (Exception) { }

            return(false);
        }
Example #11
0
        public static async Task ExecuteTradeRequestAsync(ICommandContext context, SQLiteDatabase db, GotchiTradeRequest tradeRequest)
        {
            // Get both users and their gotchis.

            IUser user1 = await context.Guild.GetUserAsync(tradeRequest.OfferedGotchi.OwnerId);

            Gotchi gotchi1 = await db.GetGotchiAsync(user1.ToCreator());

            GotchiUserInfo userInfo1 = await db.GetUserInfoAsync(user1.ToCreator());

            IUser user2 = await context.Guild.GetUserAsync(tradeRequest.ReceivedGotchi.OwnerId);

            Gotchi gotchi2 = await db.GetGotchiAsync(user2.ToCreator());

            GotchiUserInfo userInfo2 = await db.GetUserInfoAsync(user2.ToCreator());

            // Swap the owners of the gotchis.

            using (SQLiteCommand cmd = new SQLiteCommand("UPDATE Gotchi SET owner_id = $owner_id WHERE id = $id")) {
                cmd.Parameters.AddWithValue("$owner_id", user1.Id);
                cmd.Parameters.AddWithValue("$id", gotchi2.Id);

                await db.ExecuteNonQueryAsync(cmd);
            }

            userInfo1.PrimaryGotchiId = gotchi2.Id;

            await db.UpdateUserInfoAsync(userInfo1);

            using (SQLiteCommand cmd = new SQLiteCommand("UPDATE Gotchi SET owner_id = $owner_id WHERE id = $id")) {
                cmd.Parameters.AddWithValue("$owner_id", user2.Id);
                cmd.Parameters.AddWithValue("$id", gotchi1.Id);

                await db.ExecuteNonQueryAsync(cmd);
            }

            userInfo2.PrimaryGotchiId = gotchi1.Id;

            await db.UpdateUserInfoAsync(userInfo2);

            // Remove all existing trade requests involving either user.
            _trade_requests.RemoveAll(x => x.OfferedGotchi.OwnerId == user1.Id || x.ReceivedGotchi.OwnerId == user2.Id);
        }
        public async Task <GotchiStats> GetStatsAsync(Gotchi gotchi)
        {
            GotchiStats result = await GetBaseStatsAsync(gotchi);

            result.Experience = gotchi.Experience;

            // Calculate final stats based on level and base stats.
            // #todo Implement IVs/EVs

            int level = result.Level;

            result.MaxHp = _calculateHp(result.MaxHp, 0, 0, level);
            result.Atk   = _calculateStat(result.Atk, 0, 0, level);
            result.Def   = _calculateStat(result.Def, 0, 0, level);
            result.Spd   = _calculateStat(result.Spd, 0, 0, level);

            result.Hp = result.MaxHp;

            return(await Task.FromResult(result));
        }
        public async Task <bool> CheckAsync(Gotchi gotchi)
        {
            List <GotchiRequirements> requirements = new List <GotchiRequirements> {
                Requires
            };

            if (Requires != null)
            {
                requirements.AddRange(Requires.OrValue);
            }

            foreach (GotchiRequirements requirement in requirements)
            {
                if (!await CheckAsync(gotchi, requirement))
                {
                    return(false);
                }
            }

            return(true);
        }
        private async Task <bool> _checkTypesAsync(Gotchi gotchi, GotchiRequirements requirements)
        {
            try {
                // Get the types assigned to this gotchi.
                GotchiType[] types = await Global.GotchiContext.TypeRegistry.GetTypesAsync(database, gotchi);

                // Compare each type using the type pattern provided.
                // #todo Types can also have aliases (AliasPattern). For now, we'll just try to match against the type pattern as well.

                foreach (GotchiType type in types)
                {
                    if (Regex.IsMatch(type.Name, requirements.TypePattern, RegexOptions.IgnoreCase) ||
                        Regex.IsMatch(type.AliasPattern, requirements.TypePattern, RegexOptions.IgnoreCase))
                    {
                        return(true);
                    }
                }
            }
            catch (Exception) { }

            return(false);
        }
        public async Task <GotchiMove[]> GetLearnSetAsync(Gotchi gotchi)
        {
            List <GotchiMove> moves = new List <GotchiMove>();

            //// all gotchis can use hit regardless of species

            //GotchiMove universalMove = await _getMoveAsync("hit");

            //if (universalMove != null)
            //    moves.Add(universalMove);

            foreach (GotchiMove move in Registry.Values)
            {
                if (await new GotchiRequirementsChecker {
                    Requires = move.Requires
                }.CheckAsync(gotchi))
                {
                    moves.Add(move.Clone());
                }
            }

            return(moves.ToArray());
        }
        public async Task <bool> CheckAsync(Gotchi gotchi, GotchiRequirements requirements)
        {
            if (requirements is null)
            {
                return(true);
            }

            if (requirements.AlwaysFailValue)
            {
                return(false);
            }

            if (!_checkLevels(gotchi, requirements))
            {
                return(false);
            }

            if (!string.IsNullOrEmpty(requirements.RolePattern) && !await _checkRolesAsync(gotchi, requirements))
            {
                return(false);
            }

            if (!string.IsNullOrEmpty(requirements.TypePattern) && !await _checkTypesAsync(gotchi, requirements))
            {
                return(false);
            }

            ISpecies species = await database.GetSpeciesAsync(gotchi.SpeciesId);

            if (!string.IsNullOrEmpty(requirements.DescriptionPattern) && !_checkDescription(species, requirements))
            {
                return(false);
            }

            return(true);
        }
        private bool _checkLevels(Gotchi gotchi, GotchiRequirements requirements)
        {
            int level = GotchiExperienceCalculator.GetLevel(ExperienceGroup.Default, gotchi.Experience);

            return(level >= requirements.MinimumLevelValue && level <= requirements.MaximumLevelValue);
        }
Example #18
0
 public bool IsCpuGotchi(Gotchi gotchi)
 {
     return(gotchi.OwnerId == WildGotchiUserId);
 }
 public static async Task <bool> EvolveAndUpdateGotchiAsync(Gotchi gotchi)
 {
     return(await EvolveAndUpdateGotchiAsync(gotchi, string.Empty));
 }
 public static int GetLevel(ExperienceGroup experienceGroup, Gotchi gotchi)
 {
     return(GetLevel(experienceGroup, gotchi.Experience));
 }
        public static async Task <bool> EvolveAndUpdateGotchiAsync(Gotchi gotchi, string desiredEvo)
        {
            bool evolved = false;

            if (string.IsNullOrEmpty(desiredEvo))
            {
                // Find all descendatants of this species.

                using (SQLiteCommand cmd = new SQLiteCommand("SELECT species_id FROM Ancestors WHERE ancestor_id=$ancestor_id;")) {
                    List <long> descendant_ids = new List <long>();

                    cmd.Parameters.AddWithValue("$ancestor_id", gotchi.SpeciesId);

                    using (DataTable rows = await Database.GetRowsAsync(cmd))
                        foreach (DataRow row in rows.Rows)
                        {
                            descendant_ids.Add(row.Field <long>("species_id"));
                        }

                    // Pick an ID at random.

                    if (descendant_ids.Count > 0)
                    {
                        gotchi.SpeciesId = descendant_ids[BotUtils.RandomInteger(descendant_ids.Count)];

                        evolved = true;
                    }
                }
            }
            else
            {
                // Get the desired evo.
                Species[] sp = await BotUtils.GetSpeciesFromDb("", desiredEvo);

                if (sp is null || sp.Length != 1)
                {
                    return(false);
                }

                // Ensure that the species evolves into the desired evo.

                using (SQLiteCommand cmd = new SQLiteCommand("SELECT COUNT(*) FROM Ancestors WHERE ancestor_id = $ancestor_id AND species_id = $species_id")) {
                    cmd.Parameters.AddWithValue("$ancestor_id", gotchi.SpeciesId);
                    cmd.Parameters.AddWithValue("$species_id", sp[0].Id);

                    if (await Database.GetScalar <long>(cmd) <= 0)
                    {
                        return(false);
                    }

                    gotchi.SpeciesId = sp[0].Id;

                    evolved = true;
                }
            }

            // Update the gotchi in the database.

            using (SQLiteCommand cmd = new SQLiteCommand("UPDATE Gotchi SET species_id=$species_id, evolved_ts=$evolved_ts WHERE id=$id;")) {
                cmd.Parameters.AddWithValue("$species_id", gotchi.SpeciesId);

                // The "last evolved" timestamp is now only updated in the event the gotchi evolves (in order to make the "IsEvolved" check work correctly).
                // Note that this means that the background service will attempt to evolve the gotchi at every iteration (unless it evolves by leveling).

                if (evolved)
                {
                    cmd.Parameters.AddWithValue("$evolved_ts", DateTimeOffset.UtcNow.ToUnixTimeSeconds());
                }

                cmd.Parameters.AddWithValue("$id", gotchi.Id);

                await Database.ExecuteNonQuery(cmd);
            }

            return(evolved);
        }
 public static async Task SetViewedTimestampAsync(Gotchi gotchi, long viewedTimestamp)
 {
     await SetViewedTimestampAsync(gotchi.Id, viewedTimestamp);
 }
Example #23
0
        public static async Task <GotchiTradeRequestResult> MakeTradeRequestAsync(ICommandContext context, SQLiteDatabase db, Gotchi offeredGotchi, Gotchi recievedGotchi)
        {
            // If either gotchi passed in is null, the request is invalid.

            if (offeredGotchi is null || recievedGotchi is null)
            {
                return(GotchiTradeRequestResult.Invalid);
            }

            // If the user has made previous trade requests, remove them.
            _trade_requests.RemoveAll(x => x.OfferedGotchi.OwnerId == offeredGotchi.OwnerId);

            // If their partner already has an open trade request that hasn't been accepted, don't allow a new trade request to be made.
            // This is so users cannot make a new trade request right before one is accepted and snipe the trade.

            GotchiTradeRequest request = GetTradeRequest(recievedGotchi);

            if (!(request is null))
            {
                if (request.IsExpired)
                {
                    _trade_requests.RemoveAll(x => x.ReceivedGotchi.OwnerId == recievedGotchi.OwnerId);
                }
                else
                {
                    return(GotchiTradeRequestResult.RequestPending);
                }
            }

            request = new GotchiTradeRequest {
                OfferedGotchi  = offeredGotchi,
                ReceivedGotchi = recievedGotchi
            };

            if (!await ValidateTradeRequestAsync(context, db, request))
            {
                return(GotchiTradeRequestResult.Invalid);
            }

            _trade_requests.Add(request);

            return(GotchiTradeRequestResult.Success);
        }
        public async Task <GotchiStats> GetBaseStatsAsync(Gotchi gotchi)
        {
            GotchiStats result = new GotchiStats();

            int denominator = 0;

            GotchiType[] gotchiTypes = await Context.TypeRegistry.GetTypesAsync(gotchi);

            if (gotchiTypes.Count() > 0)
            {
                // Include the average of all types of this species.

                result.MaxHp = gotchiTypes.Sum(x => x.BaseHp);
                result.Atk   = gotchiTypes.Sum(x => x.BaseAtk);
                result.Def   = gotchiTypes.Sum(x => x.BaseDef);
                result.Spd   = gotchiTypes.Sum(x => x.BaseSpd);

                denominator += gotchiTypes.Count();
            }

            long[] ancestor_ids = await SpeciesUtils.GetAncestorIdsAsync(gotchi.SpeciesId);

            // Factor in the base stats of this species' ancestor (which will, in turn, factor in all other ancestors).

            if (ancestor_ids.Count() > 0)
            {
                GotchiStats ancestor_stats = await GetBaseStatsAsync(new Gotchi { SpeciesId = ancestor_ids.Last() });

                result.MaxHp += ancestor_stats.MaxHp;
                result.Atk   += ancestor_stats.Atk;
                result.Def   += ancestor_stats.Def;
                result.Spd   += ancestor_stats.Spd;

                denominator += 1;
            }

            // Add 20 points if this species has an ancestor (this effect will be compounded by the previous loop).

            if (ancestor_ids.Count() > 0)
            {
                result.MaxHp += 20;
                result.Atk   += 20;
                result.Def   += 20;
                result.Spd   += 20;
            }

            // Get the average of each base stat.

            denominator = Math.Max(denominator, 1);

            result.MaxHp /= denominator;
            result.Atk   /= denominator;
            result.Def   /= denominator;
            result.Spd   /= denominator;

            // Add 0.5 points for every week the gotchi has been alive.

            int age_bonus = (int)(0.5 * (gotchi.Age / 7));

            result.MaxHp += age_bonus;
            result.Atk   += age_bonus;
            result.Def   += age_bonus;
            result.Spd   += age_bonus;

            // Add or remove stats based on the species' description.
            await _calculateDescriptionBasedBaseStats(gotchi, result);

            return(result);
        }
Example #25
0
        public static async Task RegisterBattleAsync(ICommandContext context, Gotchi gotchi1, Gotchi gotchi2)
        {
            // Initialize the battle state.

            GotchiBattleState state = new GotchiBattleState {
                // Initialize Player 1 (which must be a human player).

                player1 = new PlayerState {
                    Gotchi = new BattleGotchi {
                        Gotchi = gotchi1,
                        Moves  = await Global.GotchiContext.MoveRegistry.GetMoveSetAsync(gotchi1),
                        Stats  = await new GotchiStatsCalculator(Global.GotchiContext).GetStatsAsync(gotchi1),
                        Types  = await Global.GotchiContext.TypeRegistry.GetTypesAsync(gotchi1)
                    }
                }
            };

            if (gotchi2 != null)
            {
                // Initialize Player 2 (which may be a human player, or a CPU).

                state.player2 = new PlayerState {
                    Gotchi = new BattleGotchi {
                        Gotchi = gotchi2,
                        Moves  = await Global.GotchiContext.MoveRegistry.GetMoveSetAsync(gotchi2),
                        Stats  = await new GotchiStatsCalculator(Global.GotchiContext).GetStatsAsync(gotchi2),
                        Types  = await Global.GotchiContext.TypeRegistry.GetTypesAsync(gotchi2)
                    }
                };
            }
            else
            {
                // Otherwise, generate an opponent for the user.
                await state._generateOpponentAsync();

                // If the opponent is null (no species available as opponents), abort.

                if (state.player2.Gotchi.Gotchi is null)
                {
                    await BotUtils.ReplyAsync_Info(context, "There are no opponents available.");

                    return;
                }

                // Since the user is battling a CPU, accept the battle immediately.
                state.accepted = true;
            }

            state.player1.Gotchi.Context = Global.GotchiContext;
            state.player2.Gotchi.Context = Global.GotchiContext;

            // Register the battle state in the battle state collection.

            _battle_states[gotchi1.OwnerId] = state;

            if (state.player2.Gotchi.Gotchi.OwnerId != WildGotchiUserId)
            {
                _battle_states[state.player2.Gotchi.Gotchi.OwnerId] = state;
            }

            // Set the initial message displayed when the battle starts.

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("The battle has begun!");
            sb.AppendLine();
            sb.AppendLine(string.Format("Pick a move with `{0}gotchi move`.\nSee your gotchi's moveset with `{0}gotchi moveset`.",
                                        Bot.OurFoodChainBot.Instance.Config.Prefix));

            state.battleText = sb.ToString();

            // If the user is battling a CPU, show the battle state immediately.
            // Otherwise, it will be shown when the other user accepts the battle challenge.

            if (state.IsBattlingCpu())
            {
                await ShowBattleStateAsync(context, state);
            }
        }