Beispiel #1
0
        private List <EnemyType> GenerateEnemyCombinations(SpriteBankRoomGroup sbrg, Random r)
        {
            // Create a random enemy set
            List <EnemyType> NewEnemies       = new List <EnemyType>();
            List <EnemyType> PotentialEnemies = new List <EnemyType>();
            bool             done             = false;
            bool             hasActivator     = false;

            while (!done)
            {
                foreach (EnemyType en in EnemyTypes)
                {
                    // 1. Skip enemies that have exceeded the type's maximum
                    // 2. Reduce the overall chance of certain types appearing by randomly skipping them
                    // 3. Limit a room set to having at most one Activator enemy type
                    double chance = 0.0;
                    switch (en.ID)
                    {
                    case EEnemyID.Pipi_Activator:
                        if (numPipis >= MAX_PIPIS)
                        {
                            continue;
                        }
                        chance = r.NextDouble();
                        if (chance > CHANCE_PIPI)
                        {
                            continue;
                        }
                        break;

                    case EEnemyID.Mole_Activator:
                        if (numMoles >= MAX_MOLES)
                        {
                            continue;
                        }
                        chance = r.NextDouble();
                        if (chance > CHANCE_MOLE)
                        {
                            continue;
                        }
                        break;

                    case EEnemyID.M445_Activator:
                        if (numM445s > MAX_M445S)
                        {
                            continue;
                        }
                        chance = r.NextDouble();
                        if (chance > CHANCE_M445)
                        {
                            continue;
                        }
                        break;

                    case EEnemyID.Telly:
                        chance = r.NextDouble();
                        if (chance > CHANCE_TELLY)
                        {
                            continue;
                        }
                        break;

                    case EEnemyID.Springer:
                        chance = r.NextDouble();
                        if (chance > CHANCE_SPRINGER)
                        {
                            continue;
                        }
                        break;

                    default:
                        break;
                    }

                    // Skip any additional activator enemies
                    if (en.IsActivator && hasActivator)
                    {
                        continue;
                    }

                    // Reject certain enemy types for certain stages or rooms
                    switch (sbrg.Stage)
                    {
                    case EStageID.HeatW1:
                        // Moles don't display correctly in Heat or Wily 1. Also too annoying in Heat Yoku room.
                        if (en.ID == EEnemyID.Mole_Activator)
                        {
                            continue;
                        }
                        // Reject Pipis appearing in Yoku block room
                        if (en.ID == EEnemyID.Pipi_Activator && sbrg.ContainsRoom(2))
                        {
                            continue;
                        }
                        // Reject M445s appearing in Yoku block room
                        if (en.ID == EEnemyID.M445_Activator && sbrg.ContainsRoom(2))
                        {
                            continue;
                        }
                        // Press doesn't display correctly in Wily 1
                        if (en.ID == EEnemyID.Press && sbrg.Rooms.Last().RoomNum >= 7)
                        {
                            continue;
                        }
                        break;

                    case EStageID.AirW2:
                        // Moles don't display correctly in Heat
                        if (en.ID == EEnemyID.Mole_Activator && sbrg.Rooms[0].RoomNum < 7)
                        {
                            continue;
                        }
                        break;

                    case EStageID.WoodW3:
                        // Moles and Press don't display in Wood outside room
                        if (en.ID == EEnemyID.Mole_Activator && sbrg.ContainsRoom(7))
                        {
                            continue;
                        }
                        if (en.ID == EEnemyID.Press && sbrg.ContainsRoom(7))
                        {
                            continue;
                        }
                        // Don't spawn Springer, Blocky, or Press underwater
                        if (en.ID == EEnemyID.Springer && sbrg.ContainsRoom(0x11))
                        {
                            continue;
                        }
                        if (en.ID == EEnemyID.Blocky && sbrg.ContainsRoom(0x11))
                        {
                            continue;
                        }
                        if (en.ID == EEnemyID.Press && sbrg.ContainsRoom(0x11))
                        {
                            continue;
                        }
                        break;

                    case EStageID.BubbleW4:
                        // Moles don't display correctly in Bubble
                        if (en.ID == EEnemyID.Mole_Activator && sbrg.Rooms[0].RoomNum < 9)
                        {
                            continue;
                        }
                        // Press doesn't display correctly in Bubble
                        if (en.ID == EEnemyID.Press && sbrg.Rooms[0].RoomNum < 9)
                        {
                            continue;
                        }
                        // Don't spawn Springer or Blocky underwater
                        if (en.ID == EEnemyID.Springer && (sbrg.ContainsRoom(3) || sbrg.ContainsRoom(4)))
                        {
                            continue;
                        }
                        if (en.ID == EEnemyID.Blocky && (sbrg.ContainsRoom(3) || sbrg.ContainsRoom(4)))
                        {
                            continue;
                        }
                        break;

                    case EStageID.Clash:
                        // Mole bad GFX
                        if (en.ID == EEnemyID.Mole_Activator)
                        {
                            continue;
                        }
                        // Press bad GFX
                        if (en.ID == EEnemyID.Press)
                        {
                            continue;
                        }
                        break;

                    default:
                        break;
                    }

                    // If room has sprite restrictions, check if this enemy's sprite can be used
                    // (i.e. certain rooms must use certain rows on the sprite table to draw mandatory objects or effects
                    if (sbrg.IsSpriteRestricted)
                    {
                        // Check if this enemy uses the restricted row in the sprite bank
                        List <int> commonRows = en.SpriteBankRows.Intersect(sbrg.SpriteBankRowsRestriction).ToList();
                        if (commonRows.Count != 0)
                        {
                            bool reject = false;
                            for (int i = 0; i < en.SpriteBankRows.Count; i++)
                            {
                                int enemyRow   = en.SpriteBankRows[i];
                                int indexOfRow = sbrg.SpriteBankRowsRestriction.IndexOf(enemyRow);

                                // For a restricted sprite bank row, see if enemy uses the same sprite pattern
                                if (indexOfRow > -1)
                                {
                                    if (en.PatternTableAddresses[i * 2] == sbrg.PatternTableAddressesRestriction[indexOfRow * 2] &&
                                        en.PatternTableAddresses[i * 2 + 1] == sbrg.PatternTableAddressesRestriction[indexOfRow * 2 + 1])
                                    {
                                        // Enemy and the restricted sprite use the same pattern table, allow it
                                        // (do nothing)
                                    }
                                    else
                                    {
                                        // Enemy draws with this row, but using a different set of graphics. reject it.
                                        reject = true;
                                        break;
                                    }
                                }
                            }

                            if (reject)
                            {
                                continue;
                            }
                        }
                    }

                    // Check if this enemy would fit in the sprite bank, given other new enemies already added
                    if (CheckEnemySpriteFitInBank(NewEnemies, en))
                    {
                        // Add enemy to set of possible enemies to place in
                        PotentialEnemies.Add(en);
                    }
                }

                // Unable to add any more enemies, done
                if (PotentialEnemies.Count == 0)
                {
                    done = true;
                }
                else
                {
                    // Choose a new enemy to add to the set from all possible new enemies to add
                    EnemyType newEnemy = PotentialEnemies[r.Next(PotentialEnemies.Count)];
                    NewEnemies.Add(newEnemy);
                    PotentialEnemies.Clear();

                    // Increase total count of certain enemy types to limit their appearance later
                    switch (newEnemy.ID)
                    {
                    case EEnemyID.Pipi_Activator:
                        numPipis++;
                        break;

                    case EEnemyID.Mole_Activator:
                        numMoles++;
                        break;

                    case EEnemyID.M445_Activator:
                        numM445s++;
                        break;

                    default:
                        break;
                    }

                    // Flag the new enemy set as having an activator so that no more will be added
                    if (newEnemy.IsActivator)
                    {
                        hasActivator = true;
                    }
                }
            }

            return(NewEnemies);
        }
Beispiel #2
0
        private List<EnemyType> GenerateEnemyCombinations(SpriteBankRoomGroup sbrg, Random r)
        {
            // Create a random enemy set
            List<EnemyType> NewEnemies = new List<EnemyType>();
            List<EnemyType> PotentialEnemies = new List<EnemyType>();
            bool done = false;
            bool hasActivator = false;
            while (!done)
            {
                foreach (EnemyType en in EnemyTypes)
                {
                    // 1. Skip enemies that have exceeded the type's maximum
                    // 2. Reduce the overall chance of certain types appearing by randomly skipping them
                    // 3. Limit a room set to having at most one Activator enemy type
                    double chance = 0.0;
                    switch (en.ID)
                    {
                        case EEnemyID.Pipi_Activator:
                            if (numPipis >= MAX_PIPIS)
                                continue;
                            chance = r.NextDouble();
                            if (chance > CHANCE_PIPI)
                                continue;
                            break;
                        case EEnemyID.Mole_Activator:
                            if (numMoles >= MAX_MOLES)
                                continue;
                            chance = r.NextDouble();
                            if (chance > CHANCE_MOLE)
                                continue;
                            break;
                        case EEnemyID.Telly:
                            chance = r.NextDouble();
                            if (chance > CHANCE_TELLY)
                                continue;
                            break;
                        case EEnemyID.Springer:
                            chance = r.NextDouble();
                            if (chance > CHANCE_SPRINGER)
                                continue;
                            break;
                        default:
                            break;
                    }

                    // Skip any additional activator enemies
                    if (en.IsActivator && hasActivator)
                    {
                        continue;
                    }

                    // Reject certain enemy types for certain stages or rooms
                    switch (sbrg.Stage)
                    {
                        case EStageID.HeatW1:
                            // Moles don't display correctly in Heat or Wily 1. Also too annoying in Heat Yoku room.
                            if (en.ID == EEnemyID.Mole_Activator) continue;
                            // Reject Pipis appearing in Yoku block room
                            if (en.ID == EEnemyID.Pipi_Activator && sbrg.ContainsRoom(2)) continue;
                            // Press doesn't display correctly in Wily 1
                            if (en.ID == EEnemyID.Press && sbrg.Rooms.Last().RoomNum >= 7) continue;
                            break;
                        case EStageID.AirW2:
                            // Moles don't display correctly in Heat
                            if (en.ID == EEnemyID.Mole_Activator && sbrg.Rooms[0].RoomNum < 7) continue;
                            break;
                        case EStageID.WoodW3:
                            // Moles and Press don't display in Wood outside room
                            if (en.ID == EEnemyID.Mole_Activator && sbrg.ContainsRoom(7)) continue;
                            if (en.ID == EEnemyID.Press && sbrg.ContainsRoom(7)) continue;
                            // Don't spawn Springer, Blocky, or Press underwater
                            if (en.ID == EEnemyID.Springer && sbrg.ContainsRoom(11)) continue;
                            if (en.ID == EEnemyID.Blocky && sbrg.ContainsRoom(11)) continue;
                            if (en.ID == EEnemyID.Press && sbrg.ContainsRoom(11)) continue;
                            break;
                        case EStageID.BubbleW4:
                            // Moles don't display correctly in Bubble
                            if (en.ID == EEnemyID.Mole_Activator && sbrg.Rooms[0].RoomNum < 9) continue;
                            // Press doesn't display correctly in Bubble
                            if (en.ID == EEnemyID.Press && sbrg.Rooms[0].RoomNum < 9) continue;
                            // Don't spawn Springer or Blocky underwater
                            if (en.ID == EEnemyID.Springer && (sbrg.ContainsRoom(3) || sbrg.ContainsRoom(4))) continue;
                            if (en.ID == EEnemyID.Blocky && (sbrg.ContainsRoom(3) || sbrg.ContainsRoom(4))) continue;
                            break;
                        case EStageID.Clash:
                            // Mole bad GFX
                            if (en.ID == EEnemyID.Mole_Activator) continue;
                            // Press bad GFX
                            if (en.ID == EEnemyID.Press) continue;
                            break;
                        default:
                            break;
                    }

                    // If room has sprite restrictions, check if this enemy's sprite can be used
                    // (i.e. certain rooms must use certain rows on the sprite table to draw mandatory objects or effects
                    if (sbrg.IsSpriteRestricted)
                    {
                        // Check if this enemy uses the restricted row in the sprite bank
                        List<int> commonRows = en.SpriteBankRows.Intersect(sbrg.SpriteBankRowsRestriction).ToList();
                        if (commonRows.Count != 0)
                        {
                            bool reject = false;
                            for (int i = 0; i < en.SpriteBankRows.Count; i++)
                            {
                                int enemyRow = en.SpriteBankRows[i];
                                int indexOfRow = sbrg.SpriteBankRowsRestriction.IndexOf(enemyRow);

                                // For a restricted sprite bank row, see if enemy uses the same sprite pattern
                                if (indexOfRow > -1)
                                {
                                    if (en.PatternTableAddresses[i * 2] == sbrg.PatternTableAddressesRestriction[indexOfRow * 2] &&
                                        en.PatternTableAddresses[i * 2 + 1] == sbrg.PatternTableAddressesRestriction[indexOfRow * 2 + 1])
                                    {
                                        // Enemy and the restricted sprite use the same pattern table, allow it
                                        // (do nothing)
                                    }
                                    else
                                    {
                                        // Enemy draws with this row, but using a different set of graphics. reject it.
                                        reject = true;
                                        break;
                                    }
                                }
                            }

                            if (reject)
                            {
                                continue;
                            }
                        }

                    }

                    // Check if this enemy would fit in the sprite bank, given other new enemies already added
                    if (CheckEnemySpriteFitInBank(NewEnemies, en))
                    {
                        // Add enemy to set of possible enemies to place in
                        PotentialEnemies.Add(en);
                    }
                }

                // Unable to add any more enemies, done
                if (PotentialEnemies.Count == 0)
                {
                    done = true;
                }
                else
                {
                    // Choose a new enemy to add to the set from all possible new enemies to add
                    EnemyType newEnemy = PotentialEnemies[r.Next(PotentialEnemies.Count)];
                    NewEnemies.Add(newEnemy);
                    PotentialEnemies.Clear();

                    // Increase total count of certain enemy types to limit their appearance later
                    switch (newEnemy.ID)
                    {
                        case EEnemyID.Pipi_Activator:
                            numPipis++;
                            break;
                        case EEnemyID.Mole_Activator:
                            numMoles++;
                            break;
                        default:
                            break;
                    }

                    // Flag the new enemy set as having an activator so that no more will be added
                    if (newEnemy.IsActivator)
                    {
                        hasActivator = true;
                    }
                }
            }

            return NewEnemies;
        }