Пример #1
0
        public int Validate(ValidateErrorDelegate dgt)
        {
            int cError = 0;

            // Validate switch count

            int cSwitchesMax = 16;
            if (m_swm.Items.Count > cSwitchesMax) {
                dgt(this, ValidateError.Error, 0, 0, null, String.Format("Max switches is {0}, this mission has {1}", cSwitchesMax, m_swm.Items.Count));
                cError++;
            }

            // Validate area count

            int cAreas = 0;
            foreach (IMapItem mi in m_alsmi) {
                if (mi is Area)
                    cAreas++;
            }
            int cAreasMax = 32;
            if (cAreas > cAreasMax) {
                dgt(this, ValidateError.Error, 0, 0, null, String.Format("Max areas is {0}, this mission has {1}", cAreasMax, cAreas));
                cError++;
            }

            // Validate SideInfo

            int cHuman = 0;
            foreach (SideInfo sidi in m_alsidi) {
                if (sidi.Intelligence == Intelligence.Human)
                    cHuman++;

            #if false
                if (sidi.InitialCredits == 0)
                    dgt(this, ValidateError.Warning, 0, 0, sidi, String.Format("Side {0} starts with no credits", sidi.Side));
            #endif
            }

            #if false
            // Don't allow multi-player yet

            if (MaxPlayers != 1) {
                dgt(this, ValidateError.Error, 0, 0, null, "Multi-player not supported yet: MaxPlayers should be 1");
                cError++;
            }

            // Must have 1 human side

            if (cHuman != 1) {
                dgt(this, ValidateError.Error, 0, 0, null, "Must have 1 human side!");
                cError++;
            }
            #endif

            if (cHuman > MaxPlayers) {
                dgt(this, ValidateError.Error, 0, 0, null, String.Format("MaxPlayers is {0}, # of human sides is {1}", MaxPlayers, cHuman));
                cError++;
            }

            // Validate gob inside/outside of boundaries

            foreach (IMapItem mi in m_alsmi) {
                if (mi is Galaxite)
                    continue;
                if (mi is Wall)
                    continue;
                if (mi is Tile)
                    continue;

                // Gobs can be inside or outside of boundaries. If gobs are intersected by the boundaries
                // that is not ok and will send the game into fits

                Rectangle rcT = new Rectangle(Bounds.Location, Bounds.Size);
                if (!Bounds.Contains(new Rectangle((int)mi.tx, (int)mi.ty, mi.ctx, mi.cty))) {
                    if (mi is Area) {
                        Area area = (Area)mi;
                        dgt(this, ValidateError.Error, (int)mi.tx, (int)mi.ty, area, String.Format("Area '{0}' out of bounds", area.Name));
                        cError++;
                    } else {
                        // If we have a gob that is "partially" outside, and gets compiled into the game,
                        // errors will occur at runtime, so make this an error

                        dgt(this, ValidateError.Error, (int)mi.tx, (int)mi.ty, mi, mi.ToString() + " out of bounds");
                        cError++;
                    }
                }
            }

            // Collect placement information.

            // enum ItemMask { None = 0, Galaxite = 1, Wall = 2, Unreachable = 4, Scenery = 8, Structure = 16, MobileUnit = 32 };

            // Initialize with all "unreachable areas" appropriately

            TerrainTypes[,] aterMap = GetTerrainMap(m_tmpd.TileSize, m_tmpd, false);
            ItemMask[,] aimMap = new ItemMask[Bounds.Height, Bounds.Width];
            for (int ty = 0; ty < Bounds.Height; ty++) {
                for (int tx = 0; tx < Bounds.Width; tx++) {
                    switch (aterMap[ty, tx]) {
                    case TerrainTypes.Blocked:
                    case TerrainTypes.Wall:
                        aimMap[ty, tx] |= ItemMask.Unreachable;
                        break;
                    }
                }
            }

            // Validate placement

            foreach (IMapItem mi in m_alsmi) {
                ItemMask im = ItemMask.None;
                ItemMask imInvalid = ItemMask.None;
                if (mi is Galaxite) {
                    im = ItemMask.Galaxite;
                    imInvalid = ItemMask.Wall | ItemMask.Unreachable | ItemMask.Structure;
                } else if (mi is Wall) {
                    im = ItemMask.Wall;
                    imInvalid = ItemMask.Galaxite | ItemMask.Wall | ItemMask.Structure | ItemMask.MobileUnit;
                } else if (mi is Scenery) {
                    im = ItemMask.Scenery;
                    imInvalid = ItemMask.None;
                } else if (mi is Structure) {
                    im = ItemMask.Structure;
                    imInvalid = ItemMask.Galaxite | ItemMask.Wall | ItemMask.Unreachable | ItemMask.Structure | ItemMask.MobileUnit;
                } else if (mi is MobileUnit) {
                    im = ItemMask.MobileUnit;
                    imInvalid = ItemMask.Wall | ItemMask.Unreachable | ItemMask.Structure | ItemMask.MobileUnit;
                }
                if (im == ItemMask.None)
                    continue;

                // Check each tile occupied by this mi

                ItemMask imError = ItemMask.None;
                for (int ty = (int)mi.ty; ty < (int)mi.ty + mi.cty; ty++) {
                    for (int tx = (int)mi.tx; tx < (int)mi.tx + mi.ctx; tx++) {
                        int txT = tx - Bounds.Left;
                        int tyT = ty - Bounds.Top;
                        if (txT < 0 || tyT < 0)
                            continue;
                        if (txT >= Bounds.Width || tyT >= Bounds.Height)
                            continue;
                        ItemMask imInvalidOverlap = aimMap[tyT, txT] & imInvalid;
                        aimMap[tyT, txT] |= im;
                        ItemMask imErrorNew = (ItemMask)(imInvalidOverlap & ~imError);
                        if (imErrorNew != ItemMask.None) {
                            imError |= imErrorNew;

                            // Build up the error string

                            ItemMask[] aimValues = (ItemMask[])Enum.GetValues(typeof(ItemMask));
                            string strT = "";
                            for (int n = 0; n < aimValues.Length; n++) {
                                if ((aimValues[n] & imErrorNew) != 0)
                                    strT += aimValues[n].ToString() + ",";
                            }
                            if (strT != "")
                                strT = strT.Substring(0, strT.Length - 1);

                            dgt(this, ValidateError.Error, (int)mi.tx, (int)mi.ty, mi, mi.ToString() + " is on top of: " + strT);
                            cError++;
                        }
                    }
                }
            }

            // Validate that structures don't make terrain inaccessible
            // Everywhere there is a blocked section in aterMapStructs that isn't
            // blocked in aterMap and isn't a structure is now inaccessible because
            // of a structure block

            TerrainTypes[,] aterMapStructs = GetTerrainMap(m_tmpd.TileSize, m_tmpd, true);
            for (int ty = 0; ty < aterMap.GetLength(0); ty++) {
                for (int tx = 0; tx < aterMap.GetLength(1); tx++) {
                    // Check

                    bool fSrcOpen = (aimMap[ty, tx] & (ItemMask.Unreachable | ItemMask.Structure)) == 0;
                    if (fSrcOpen && aterMapStructs[ty, tx] == TerrainTypes.Blocked) {
                        dgt(this, ValidateError.Error, tx + Bounds.Left, ty + Bounds.Top, null, String.Format("Terrain at {0},{1} is inaccessible due to structure blockage", tx + Bounds.Left, ty + Bounds.Top));
                        cError++;
                    }
                }
            }

            // Validate areas in triggers exist

            StringCollection strc = CaTypeArea.GetAreaNames();
            foreach (Side side in Enum.GetValues(typeof(Side))) {
                Trigger[] atgr = m_tgrm.GetTriggerList(side);
                foreach (Trigger tgr in atgr) {
                    foreach (CaBase cab in tgr.Conditions) {
                        foreach (CaType cat in cab.GetTypes()) {
                            if (cat is CaTypeArea) {
                                CaTypeArea catArea = (CaTypeArea)cat;
                                if (strc.IndexOf(catArea.Area) < 0) {
                                    dgt(this, ValidateError.Error, 0, 0, null, "Area " + catArea.Area + " in trigger " + tgr.ToString() + " doesn't exist!");
                                    cError++;
                                }
                            }
                        }
                    }
                    foreach (CaBase cab in tgr.Actions) {
                        foreach (CaType cat in cab.GetTypes()) {
                            if (cat is CaTypeArea) {
                                CaTypeArea catArea = (CaTypeArea)cat;
                                if (strc.IndexOf(catArea.Area) < 0) {
                                    dgt(this, ValidateError.Error, 0, 0, null, "Area " + catArea.Area + " in trigger " + tgr.ToString() + " doesn't exist!");
                                    cError++;
                                }
                            }
                        }
                    }
                }
            }

            // Validate unit groups in triggers

            foreach (Side side in Enum.GetValues(typeof(Side))) {
                Trigger[] atgr = m_tgrm.GetTriggerList(side);
                foreach (Trigger tgr in atgr) {
                    foreach (CaBase cab in tgr.Conditions) {
                        foreach (CaType cat in cab.GetTypes()) {
                            if (cat is CaTypeUnitGroup) {
                                CaTypeUnitGroup catUg = (CaTypeUnitGroup)cat;
                                if (Array.IndexOf(atgr, tgr) < 0) {
                                    dgt(this, ValidateError.Error, 0, 0, null, "Orphaned UnitGroup in trigger " + tgr.ToString());
                                    cError++;
                                }
                            }
                        }
                    }
                    foreach (CaBase cab in tgr.Actions) {
                        foreach (CaType cat in cab.GetTypes()) {
                            if (cat is CaTypeArea) {
                                CaTypeArea catArea = (CaTypeArea)cat;
                                if (strc.IndexOf(catArea.Area) < 0) {
                                    dgt(this, ValidateError.Error, 0, 0, null, "Orphaned UnitGroup in trigger " + tgr.ToString());
                                    cError++;
                                }
                            }
                        }
                    }
                }
            }

            // Validate triggers per side limit

            int cTriggersPerSideMax = 128;
            foreach (Side side in Enum.GetValues(typeof(Side))) {
                Trigger[] atgr = m_tgrm.GetTriggerList(side);
                if (atgr == null)
                    continue;
                if (atgr.Length > cTriggersPerSideMax) {
                    string strT = String.Format("Triggers per side {0}. Side {1} has {2} triggers", cTriggersPerSideMax, side.ToString(), atgr.Length);
                    dgt(this, ValidateError.Error, 0, 0, null, strT);
                    cError++;
                }
            }

            // Validate gob limits

            int[] acStructures = new int[Enum.GetNames(typeof(Side)).Length];
            int[] acMunts = new int[Enum.GetNames(typeof(Side)).Length];
            int cScenery = 0;
            foreach (IMapItem mi in m_alsmi) {
                if (mi is Unit) {
                    Unit unit = (Unit)mi;
                    if (unit is Structure) {
                        acStructures[(int)unit.Side]++;
                    } else {
                        acMunts[(int)unit.Side]++;
                    }
                    continue;
                }
                if (mi is Scenery) {
                    cScenery++;
                    continue;
                }
            }

            // Scenery Limit

            int cSceneryMax = 100;
            if (cScenery > cSceneryMax) {
                string strT = String.Format("{0} scenery; {1} allowed", cScenery, cSceneryMax);
                dgt(this, ValidateError.Error, 0, 0, null, strT);
                cError++;
            }

            // Unit counts

            if (MaxPlayers == 1) {
                // Single player - asymmetric: one human count, shared computer counts
                // #define kcStructGobsHumanMin 39
                // #define kcStructGobsComputerMin 52
                // #define kcMuntGobsHumanMin 60
                // #define kcMuntGobsComputerMin 80

                int cStructsHumanMax = 39;
                int cMuntsHumanMax = 60;
                int cStructsComputerMax = 52;
                int cMuntsComputerMax = 80;

                int cStructsHuman = 0;
                int cMuntsHuman = 0;
                int cStructsComputer = 0;
                int cMuntsComputer = 0;

                foreach (SideInfo sidi in m_alsidi) {
                    if (sidi.Intelligence == Intelligence.Human) {
                        cStructsHuman += acStructures[(int)sidi.Side];
                        cMuntsHuman += acMunts[(int)sidi.Side];
                    } else {
                        cStructsComputer += acStructures[(int)sidi.Side];
                        cMuntsComputer += acMunts[(int)sidi.Side];
                    }
                }

                // HACK ALERT: Sometimes levels have more human structures than the human limit. In this
                // case, take some from the computer side if possible. Hack: Reserve 5 structs for computer building

                int cStructuresAvailable = cStructsComputerMax - cStructsComputer - 5;
                if (cStructuresAvailable < 0)
                    cStructuresAvailable = 0;
                cStructsHumanMax += cStructuresAvailable;
                cStructsComputerMax -= cStructuresAvailable;

                // Check

                if (cStructsHuman > cStructsHumanMax) {
                    string strT = String.Format("Human Side has {0} structures; {1} allowed", cStructsHuman, cStructsHumanMax);
                    dgt(this, ValidateError.Error, 0, 0, null, strT);
                    cError++;
                }
                if (cMuntsHuman > cMuntsHumanMax) {
                    string strT = String.Format("Human Side has {0} mobile units; {1} allowed", cMuntsHuman, cMuntsHumanMax);
                    dgt(this, ValidateError.Error, 0, 0, null, strT);
                    cError++;
                }
                if (cStructsComputer > cStructsComputerMax) {
                    string strT = String.Format("Computer Side has {0} structures; {1} allowed", cStructsComputer, cStructsComputerMax);
                    dgt(this, ValidateError.Error, 0, 0, null, strT);
                    cError++;
                }
                if (cMuntsComputer > cMuntsComputerMax) {
                    string strT = String.Format("Computer Side has {0} mobile units; {1} allowed", cMuntsComputer, cMuntsComputerMax);
                    dgt(this, ValidateError.Error, 0, 0, null, strT);
                    cError++;
                }
            } else {
                // Multi-player - symmetric: same counts for each side
                // #define kcStructGobsMax 55
                // #define kcMuntGobsMax 88

                int cStructsMax = 55;
                int cMuntsMax = 88;

                foreach (Side side in Enum.GetValues(typeof(Side))) {
                    if (acStructures[(int)side] > cStructsMax) {
                        string strT = String.Format("Side {0} has {1} structures; {2} allowed", side.ToString(), acStructures[(int)side], cStructsMax);
                        dgt(this, ValidateError.Error, 0, 0, null, strT);
                        cError++;
                    }
                    if (acMunts[(int)side] > cMuntsMax) {
                        string strT = String.Format("Side {0} has {1} mobile units; {2} allowed", side.ToString(), acMunts[(int)side], cMuntsMax);
                        dgt(this, ValidateError.Error, 0, 0, null, strT);
                        cError++;
                    }
                }
            }

            // UNDONE: Validate legal multiplayer triggers

            // UNDONE: Validate computer sides have enough power

            // UNDONE: Validate computer sides have a surveillance center if they have towers

            // UNDONE: info -- total credits value of on-map Galaxite

            // UNDONE: info -- power supply/demand for each side

            return cError;
        }
Пример #2
0
 public int Validate(ValidateErrorDelegate dgt)
 {
     return 0;
 }