Exemple #1
0
        private void RandomizeEnemiesNatively(TR2CombinedLevel level)
        {
            // For the assault course, nothing will be changed for the time being
            if (level.IsAssault)
            {
                return;
            }

            List <TR2Entities> availableEnemyTypes = TR2EntityUtilities.GetEnemyTypeDictionary()[level.Name];
            List <TR2Entities> droppableEnemies    = TR2EntityUtilities.DroppableEnemyTypes()[level.Name];
            List <TR2Entities> waterEnemies        = TR2EntityUtilities.FilterWaterEnemies(availableEnemyTypes);

            if (DocileBirdMonsters && level.Is(LevelNames.CHICKEN))
            {
                DisguiseEntity(level, TR2Entities.MaskedGoon1, TR2Entities.BirdMonster);
            }

            RandomizeEnemies(level, new EnemyRandomizationCollection
            {
                Available         = availableEnemyTypes,
                Droppable         = droppableEnemies,
                Water             = waterEnemies,
                BirdMonsterGuiser = TR2Entities.MaskedGoon1 // If randomizing natively, this will only apply to Ice Palace
            });
        }
Exemple #2
0
        public int Compare(TR2CombinedLevel lvl1, TR2CombinedLevel lvl2)
        {
            int enemyCount1 = TR2EntityUtilities.GetEnemyTypeDictionary()[lvl1.Name].Count;
            int enemyCount2 = TR2EntityUtilities.GetEnemyTypeDictionary()[lvl2.Name].Count;

            int freeTiles1 = 16 - (int)lvl1.Data.NumImages;
            int freeTiles2 = 16 - (int)lvl2.Data.NumImages;

            if (freeTiles1 == freeTiles2)
            {
                return(enemyCount2.CompareTo(enemyCount1));
            }

            return((enemyCount1 * freeTiles1).CompareTo(enemyCount2 * freeTiles2));
        }
Exemple #3
0
        private void RandomizeEnemyTypes(string lvl)
        {
            List <TR2Entities> EnemyTypes = TR2EntityUtilities.GetEnemyTypeDictionary()[lvl];

            for (int i = 0; i < _levelInstance.Entities.Count(); i++)
            {
                if (lvl == LevelNames.CHICKEN &&
                    _levelInstance.Entities[i].Room == 143 &&
                    _levelInstance.Entities[i].TypeID == (int)TR2Entities.BirdMonster)
                {
                    //#60 - Ice Palace - Room 143 chicken man must remain to avoid softlock.
                    continue;
                }
                else if (lvl == LevelNames.HOME && _levelInstance.Entities[i].TypeID == (int)TR2Entities.ShotgunGoon)
                {
                    //#62 - Avoid randomizing shotgun goon in HSH
                    continue;
                }

                //#45 - Check to see if any items are at the same location as the enemy.
                //If there are we need to ensure that the new random enemy type is one that can drop items.
                List <TR2Entity> SharedItems = new List <TR2Entity>(Array.FindAll(_levelInstance.Entities, e => ((e.X == _levelInstance.Entities[i].X) &&
                                                                                                                 (e.Y == _levelInstance.Entities[i].Y) && (e.Z == _levelInstance.Entities[i].Z))));

                List <TR2Entities> DroppableEnemies = TR2EntityUtilities.DroppableEnemyTypes()[lvl];

                //Is it an entity we are keen on replacing?
                if (EnemyTypes.Contains((TR2Entities)_levelInstance.Entities[i].TypeID))
                {
                    //Do multiple entities share one location?
                    if ((SharedItems.Count > 1) && (DroppableEnemies.Count != 0))
                    {
                        //Are any entities sharing a location a droppable pickup?
                        bool IsPickupItem = false;

                        foreach (TR2Entity ent in SharedItems)
                        {
                            TR2Entities EntType = (TR2Entities)ent.TypeID;

                            IsPickupItem = (TR2EntityUtilities.IsUtilityType(EntType)) ||
                                           (TR2EntityUtilities.IsGunType(EntType)) ||
                                           (TR2EntityUtilities.IsKeyItemType(EntType));

                            if (IsPickupItem)
                            {
                                break;
                            }
                        }

                        //Generate a location
                        _levelInstance.Entities[i].TypeID = (short)EnemyTypes[_generator.Next(0, EnemyTypes.Count)];

                        //Do we need to ensure the enemy can drop the item on the same tile?
                        if (!TR2EntityUtilities.CanDropPickups((TR2Entities)_levelInstance.Entities[i].TypeID, false) && IsPickupItem)
                        {
                            //Ensure the new random entity can drop pickups
                            _levelInstance.Entities[i].TypeID = (short)DroppableEnemies[_generator.Next(0, DroppableEnemies.Count)];
                        }
                    }
                    else
                    {
                        _levelInstance.Entities[i].TypeID = (short)EnemyTypes[_generator.Next(0, EnemyTypes.Count)];
                    }

                    short room = _levelInstance.Entities[i].Room;

                    if (!TR2EntityUtilities.IsWaterCreature((TR2Entities)_levelInstance.Entities[i].TypeID) &&
                        _levelInstance.Rooms[room].ContainsWater)
                    {
                        if (!PerformDraining(lvl, room))
                        {
                            //Draining cannot be performed so make the entity a water creature.
                            TR2Entities ent;

                            //Make sure water creature can appear on level
                            do
                            {
                                ent = TR2EntityUtilities.WaterCreatures()[_generator.Next(0, TR2EntityUtilities.WaterCreatures().Count)];
                            } while (!EnemyTypes.Contains(ent));

                            _levelInstance.Entities[i].TypeID = (short)ent;
                        }
                    }
                }
            }
        }
Exemple #4
0
        private void RandomizeEnemyTypes(string lvl)
        {
            List <TR2Entities> EnemyTypes = TR2EntityUtilities.GetEnemyTypeDictionary()[lvl];

            for (int i = 0; i < _levelInstance.Entities.Count(); i++)
            {
                //#60 - Ice Palace - Room 143 chicken man must remain to avoid softlock.
                if (lvl == LevelNames.CHICKEN &&
                    _levelInstance.Entities[i].Room == 143 &&
                    _levelInstance.Entities[i].TypeID == (int)TR2Entities.BirdMonster)
                {
                    continue;
                }

                //#45 - Check to see if any items are at the same location as the enemy.
                //If there are we need to ensure that the new random enemy type is one that can drop items.
                List <TR2Entity> SharedItems = new List <TR2Entity>(Array.FindAll(_levelInstance.Entities, e => ((e.X == _levelInstance.Entities[i].X) &&
                                                                                                                 (e.Y == _levelInstance.Entities[i].Y) && (e.Z == _levelInstance.Entities[i].Z))));

                List <TR2Entities> DroppableEnemies = TR2EntityUtilities.DroppableEnemyTypes()[lvl];

                //Is it an entity we are keen on replacing?
                if (EnemyTypes.Contains((TR2Entities)_levelInstance.Entities[i].TypeID))
                {
                    //Do multiple entities share one location?
                    if ((SharedItems.Count > 1) && (DroppableEnemies.Count != 0))
                    {
                        //Are any entities sharing a location a droppable pickup?
                        bool IsPickupItem = false;

                        foreach (TR2Entity ent in SharedItems)
                        {
                            TR2Entities EntType = (TR2Entities)ent.TypeID;

                            IsPickupItem = (TR2EntityUtilities.IsAmmoType(EntType)) ||
                                           (TR2EntityUtilities.IsGunType(EntType)) ||
                                           (TR2EntityUtilities.IsKeyItemType(EntType));

                            if (IsPickupItem)
                            {
                                break;
                            }
                        }

                        //Generate a location
                        _levelInstance.Entities[i].TypeID = (short)EnemyTypes[_generator.Next(0, EnemyTypes.Count)];

                        //Do we need to ensure the enemy can drop the item on the same tile?
                        if (!TR2EntityUtilities.CanDropPickups((TR2Entities)_levelInstance.Entities[i].TypeID) && IsPickupItem)
                        {
                            //Ensure the new random entity can drop pickups
                            _levelInstance.Entities[i].TypeID = (short)DroppableEnemies[_generator.Next(0, DroppableEnemies.Count)];
                        }
                    }
                    else
                    {
                        _levelInstance.Entities[i].TypeID = (short)EnemyTypes[_generator.Next(0, EnemyTypes.Count)];
                    }
                }
            }
        }
Exemple #5
0
        private EnemyTransportCollection SelectCrossLevelEnemies(TR2CombinedLevel level, int reduceEnemyCountBy = 0)
        {
            // For the assault course, nothing will be imported for the time being
            if (level.IsAssault)
            {
                return(null);
            }

            // Get the list of enemy types currently in the level
            List <TR2Entities> oldEntities = TR2EntityUtilities.GetEnemyTypeDictionary()[level.Name];

            // Work out how many we can support
            int enemyCount = oldEntities.Count - reduceEnemyCountBy + EnemyUtilities.GetEnemyAdjustmentCount(level.Name);
            List <TR2Entities> newEntities = new List <TR2Entities>(enemyCount);

            List <TR2Entities> chickenGuisers = EnemyUtilities.GetEnemyGuisers(TR2Entities.BirdMonster);
            TR2Entities        chickenGuiser  = TR2Entities.BirdMonster;

            // #148 For HSH, we lock the enemies that are required for the kill counter to work outside
            // the gate, which means the game still has the correct target kill count, while allowing
            // us to randomize the ones inside the gate (except the final shotgun goon).
            // If however, we are on the final packing attempt, we will just change the stick goon
            // alias and add docile bird monsters (if selected) as this is known to be supported.
            if (level.Is(LevelNames.HOME) && reduceEnemyCountBy > 0)
            {
                TR2Entities        newGoon = TR2Entities.StickWieldingGoon1BlackJacket;
                List <TR2Entities> goonies = TR2EntityUtilities.GetEntityFamily(newGoon);
                do
                {
                    newGoon = goonies[_generator.Next(0, goonies.Count)];
                }while (newGoon == TR2Entities.StickWieldingGoon1BlackJacket);

                newEntities.AddRange(oldEntities);
                newEntities.Remove(TR2Entities.StickWieldingGoon1);
                newEntities.Add(newGoon);

                if (DocileBirdMonsters)
                {
                    newEntities.Remove(TR2Entities.MaskedGoon1);
                    newEntities.Add(TR2Entities.BirdMonster);
                    chickenGuiser = TR2Entities.MaskedGoon1;
                }
            }
            else
            {
                // Do we need at least one water creature?
                bool waterEnemyRequired = EnemyUtilities.IsWaterEnemyRequired(level);
                // Do we need at least one enemy that can drop?
                bool droppableEnemyRequired = EnemyUtilities.IsDroppableEnemyRequired(level);

                // Let's try to populate the list. Start by adding one water enemy
                // and one droppable enemy if they are needed.
                if (waterEnemyRequired)
                {
                    List <TR2Entities> waterEnemies = TR2EntityUtilities.KillableWaterCreatures();
                    TR2Entities        entity;
                    do
                    {
                        entity = waterEnemies[_generator.Next(0, waterEnemies.Count)];
                    }while (!EnemyUtilities.IsEnemySupported(level.Name, entity));
                    newEntities.Add(entity);
                }

                if (droppableEnemyRequired)
                {
                    List <TR2Entities> droppableEnemies = TR2EntityUtilities.GetCrossLevelDroppableEnemies(!ProtectMonks);
                    TR2Entities        entity;
                    do
                    {
                        entity = droppableEnemies[_generator.Next(0, droppableEnemies.Count)];
                    }while (!EnemyUtilities.IsEnemySupported(level.Name, entity));
                    newEntities.Add(entity);
                }

                // Are there any other types we need to retain?
                foreach (TR2Entities entity in EnemyUtilities.GetRequiredEnemies(level.Name))
                {
                    if (!newEntities.Contains(entity))
                    {
                        newEntities.Add(entity);
                    }
                }

                // Get all other candidate enemies and fill the list
                List <TR2Entities> allEnemies = TR2EntityUtilities.GetCandidateCrossLevelEnemies();

                while (newEntities.Count < newEntities.Capacity)
                {
                    TR2Entities entity = allEnemies[_generator.Next(0, allEnemies.Count)];

                    // Make sure this isn't known to be unsupported in the level
                    if (!EnemyUtilities.IsEnemySupported(level.Name, entity))
                    {
                        continue;
                    }

                    // If it's the chicken in HSH but we're not using docile, we don't want it ending the level
                    if (!DocileBirdMonsters && entity == TR2Entities.BirdMonster && level.Is(LevelNames.HOME))
                    {
                        continue;
                    }

                    // If it's a docile chicken in Barkhang, it won't work because we can't disguise monks in this level.
                    if (DocileBirdMonsters && entity == TR2Entities.BirdMonster && level.Is(LevelNames.MONASTERY))
                    {
                        continue;
                    }

                    // If this is a tracked enemy throughout the game, we only allow it if the number
                    // of unique levels is within the limit. Bear in mind we are collecting more than
                    // one group of enemies per level.
                    if (_gameEnemyTracker.ContainsKey(entity) && !_gameEnemyTracker[entity].Contains(level.Name))
                    {
                        if (_gameEnemyTracker[entity].Count < _gameEnemyTracker[entity].Capacity)
                        {
                            // The entity is allowed, so store the fact that this level will have it
                            _gameEnemyTracker[entity].Add(level.Name);
                        }
                        else
                        {
                            // Otherwise, pick something else
                            continue;
                        }
                    }

                    // GetEntityFamily returns all aliases for the likes of the tigers, but if an entity
                    // doesn't have any, the returned list just contains the entity itself. This means
                    // we can avoid duplicating standard enemies as well as avoiding alias-clashing.
                    List <TR2Entities> family = TR2EntityUtilities.GetEntityFamily(entity);
                    if (!newEntities.Any(e1 => family.Any(e2 => e1 == e2)))
                    {
                        // #144 We can include docile chickens provided we aren't including everything
                        // that can be disguised as a chicken.
                        if (DocileBirdMonsters)
                        {
                            bool guisersAvailable = !chickenGuisers.All(g => newEntities.Contains(g));
                            // If the selected entity is the chicken, it can be added provided there are
                            // available guisers.
                            if (!guisersAvailable && entity == TR2Entities.BirdMonster)
                            {
                                continue;
                            }

                            // If the selected entity is a potential guiser, it can only be added if it's not
                            // the last available guiser. Otherwise, it will become the guiser.
                            if (chickenGuisers.Contains(entity) && newEntities.Contains(TR2Entities.BirdMonster))
                            {
                                if (newEntities.FindAll(e => chickenGuisers.Contains(e)).Count == chickenGuisers.Count - 1)
                                {
                                    continue;
                                }
                            }
                        }

                        newEntities.Add(entity);
                    }
                }
            }

            // #144 Decide at this point who will be guising unless it has already been decided above (e.g. HSH)
            if (DocileBirdMonsters && newEntities.Contains(TR2Entities.BirdMonster) && chickenGuiser == TR2Entities.BirdMonster)
            {
                int guiserIndex = chickenGuisers.FindIndex(g => !newEntities.Contains(g));
                if (guiserIndex != -1)
                {
                    chickenGuiser = chickenGuisers[guiserIndex];
                }
            }

            return(new EnemyTransportCollection
            {
                EntitiesToImport = newEntities,
                EntitiesToRemove = oldEntities,
                BirdMonsterGuiser = chickenGuiser
            });
        }