public void LoadIni(Ini ini)
 {
     for (int index = 0; true; index++) {
         Ini.Section sec = ini["UnitGroup " + index];
         if (sec == null) {
             break;
         }
         UnitGroup ug = UnitGroup.FromIniSection(sec);
         AddUnitGroup(ug);
     }
 }
        public void AddIniProperties(Ini.Section sec)
        {
            // Save conditions & actions

            foreach (CaBase cab in m_alsConditions) {
                if (!(cab is CommentCondition))
                    sec.Add(new Ini.Property("C", cab.ToSaveString()));
            }

            foreach (CaBase cab in m_alsActions) {
                if (!(cab is CommentTriggerAction))
                    sec.Add(new Ini.Property("A", cab.ToSaveString()));
            }
        }
        public void AddIniProperties(Ini.Section sec)
        {
            // Save Name

            sec.Add(new Ini.Property("Name", Name));

            // Save Side

            sec.Add(new Ini.Property("Side", "k" + m_side.ToString()));

            // Save Aggressiveness

            sec.Add(new Ini.Property("Aggressiveness", "knAggressiveness" + m_aggr.ToString()));

            // Save flags

            sec.Add(new Ini.Property("LoopForever", m_fLoopForever ? "1" : "0"));
            sec.Add(new Ini.Property("CreateAtLevelLoad", m_fCreateAtLevelLoad ? "1" : "0"));
            sec.Add(new Ini.Property("RandomGroup", m_fRandomGroup ? "1" : "0"));
            sec.Add(new Ini.Property("Spawn", m_fSpawn ? "1" : "0"));
            sec.Add(new Ini.Property("ReplaceGroup", m_fReplaceDestroyedGroup ? "1" : "0"));

            // Save SpawnArea

            int nSpawnArea = CaTypeArea.GetArea(m_strSpawnArea);
            if (nSpawnArea != -1)
                sec.Add(new Ini.Property("SpawnArea", nSpawnArea.ToString()));

            // Save Health

            sec.Add(new Ini.Property("Health", Health.ToString()));

            // Save unit list

            if (m_alsUnitTypeAndCounts.Count > 0) {

                // Write total # of units

                int cTotalUnits = 0;
                foreach (UnitTypeAndCount utc in m_alsUnitTypeAndCounts)
                    cTotalUnits += utc.c;
                string str = cTotalUnits.ToString();

                // Write unit/count pairs

                foreach (UnitTypeAndCount utc in m_alsUnitTypeAndCounts)
                    str += "," + utc.ToSaveString();

                sec.Add(new Ini.Property("Units", str));
            }

            // Save actions

            foreach (CaBase cab in m_alsActions) {
                if (!(cab is CommentUnitGroupAction))
                    sec.Add(new Ini.Property("A", cab.ToSaveString()));
            }
        }
        public static UnitGroup FromIniSection(Ini.Section sec)
        {
            UnitGroup ug = new UnitGroup(sec["Name"].Value);
            ug.Side = (Side)int.Parse(sec["Side"].Value);
            ug.Aggressiveness = (Aggressiveness)int.Parse(sec["Aggressiveness"].Value);
            ug.LoopForever = (int.Parse(sec["LoopForever"].Value) != 0);
            ug.CreateAtLevelLoad = (int.Parse(sec["CreateAtLevelLoad"].Value) != 0);
            ug.RandomGroup = (int.Parse(sec["RandomGroup"].Value) != 0);
            ug.Spawn = (int.Parse(sec["Spawn"].Value) != 0);
            ug.ReplaceDestroyedGroup = (int.Parse(sec["ReplaceGroup"].Value) != 0);
            if (sec["SpawnArea"] != null) {
                ug.SpawnArea = CaTypeArea.GetAreaNameFromIndex(int.Parse(sec["SpawnArea"].Value));
            }
            ug.Health = int.Parse(sec["Health"].Value);

            // Units

            string strUTC = null;
            if (sec["Units"] != null) {
                strUTC = sec["Units"].Value;
            }
            if (strUTC != null) {
                Regex re = new Regex(@"^(?<count>\d+),(?<end>.*)$");
                Match m = re.Match(strUTC);
                string strT = m.Groups["end"].Value;
                while (strT.Length != 0) {
                    UnitTypeAndCount utc = new UnitTypeAndCount();
                    strT = utc.FromSaveString(strT);
                    ug.UnitTypeAndCounts.Add(utc);
                    re = new Regex(@"^\s*,(?<end>.*)$");
                    m = re.Match(strT);
                    strT = m.Groups["end"].Value;
                }
            }

            // UnitGroup actions

            foreach (Ini.Property prop in sec.Properties) {
                if (prop.Name != "A") {
                    continue;
                }
                CaBase cab = UnitGroupActionLoader.LoadIni(prop.Value);
                ug.Actions.Add(cab);
            }
            return ug;
        }
 public static void InitKit()
 {
     try {
         Ini ini = new Ini(Application.ExecutablePath.Replace(".exe", ".ini"));
         Globals.SetKit(ini["General"]["Kit"].Value == bool.TrueString);
     } catch {
         Globals.SetKit(true);
     }
 }
 public Globals()
 {
     #if false
     // For the time being, we can execute without gob templates.
     // Fix this approach.
     OpenFileDialog frmOpen = new OpenFileDialog();
     frmOpen.Filter = "pp (*.*)|*.*";
     frmOpen.Title = "Templates File";
     if (frmOpen.ShowDialog() != DialogResult.Cancel)
         GobTemplatesIni = new Ini(frmOpen.FileName);
     #endif
     LabelFont = new Font("Arial", 8);
 }
 public void SaveIni(Ini ini)
 {
     for (int i = 0; i < m_alsUnitGroups.Count; i++) {
         Ini.Section sec = new Ini.Section("UnitGroup " + i);
         ((UnitGroup)m_alsUnitGroups[i]).AddIniProperties(sec);
         ini.Add(sec);
     }
 }
Beispiel #8
0
        void SaveSettings()
        {
            // Save settings in ini.

            Ini ini = new Ini();
            Ini.Section secGeneral = new Ini.Section("General");
            secGeneral.Add(new Ini.Property("SoundsDir", Path.GetFullPath(textBoxSoundsDir.Text)));
            secGeneral.Add(new Ini.Property("Sfx.h", m_strSfxH));
            ini.Add(secGeneral);

            // Place in directory where .exe resides

            ini.Save(Application.ExecutablePath.Replace(".exe", ".ini"));
        }
        public static string ImportExportMixMap(string strFile, LevelDoc lvld)
        {
            // Load ini
            Ini ini = new Ini(strFile);

            // Get name of level
            String strName = strFile;
            Ini.Section secBasic = ini["Basic"];
            if (secBasic != null) {
                Ini.Property propName = secBasic["Name"];
                if (propName != null) {
                    strName = propName.Value;
                } else {
                    Ini.Property propBrief = secBasic["Brief"];
                    if (propBrief != null)
                        strName = propBrief.Value;
                }
            }

            // Get theater
            Ini.Section secMap = ini["MAP"];
            if (secMap == null) {
                MessageBox.Show("Could not load " + strFile);
                return null;
            }
            Theater theater;
            switch (secMap["Theater"].Value) {
            case "DESERT":
                theater = Theater.Desert;
                break;

            case "TEMPERATE":
                theater = Theater.Temperate;
                break;

            case "WINTER":
                theater = Theater.Winter;
                break;

            default:
                MessageBox.Show("Could not load " + strFile);
                return null;
            }

            // Get bounds & invert
            int xLeft = Int32.Parse(secMap["X"].Value);
            int yTop = Int32.Parse(secMap["Y"].Value);
            int cxWidth = Int32.Parse(secMap["Width"].Value);
            int cyHeight = Int32.Parse(secMap["Height"].Value);
            Rectangle rcBounds = new Rectangle(64 - (xLeft + cxWidth), yTop, cxWidth, cyHeight);

            // We're ready to go
            lvld.Title = strName;
            //fixme
            //lvld.TileCollectionFileName = theater.ToString() + ".tc";
            lvld.Bounds = rcBounds;

            // Load up
            MixTemplate[] amixt = MixSuck.LoadTemplates(theater);
            MixSuck.ImportTemplates(amixt, lvld.GetTemplateDoc());
            Stream stm = (Stream)new FileStream(strFile.ToLower().Replace(".ini", ".bin"), FileMode.Open, FileAccess.Read, FileShare.Read);
            MixMap map = MixSuck.LoadMap(stm, amixt);
            stm.Close();
            map.ImportMap(lvld);
            //fixme
            //lvld.SetBackgroundTemplate(lvld.GetTemplateDoc()FindTemplate(0));

            // Save

            string strFileLvld = strName + "_" + Path.GetFileName(strFile).Replace(".ini", ".ld");
            lvld.SaveAs(strFileLvld);

            // Also save a scaled image for reference
            TemplateDoc tmpd = lvld.GetTemplateDoc();
            Bitmap bm = lvld.GetMapBitmap(tmpd.TileSize, tmpd, true);
            int cx;
            int cy;
            if (bm.Width > bm.Height) {
                cx = 128;
                cy = bm.Height * 128 / bm.Width;
            } else {
                cx = bm.Width * 128 / bm.Height;
                cy = 128;
            }
            bm = (Bitmap)bm.GetThumbnailImage(cx, cy, null, IntPtr.Zero);
            bm.Save(strFileLvld.Replace(".ld", ".png"), ImageFormat.Png);
            bm.Dispose();

            // Save a full 24x24 original map image for reference
            map.SaveMapBitmap("cc_" + strFileLvld.Replace(".ld", ".png"));

            return strFileLvld;
        }
Beispiel #10
0
 public SectionEnumerator(Ini ini)
 {
     m_ini = ini;
 }
Beispiel #11
0
        void LoadSettings()
        {
            // Settings

            m_strFileSettings = Application.ExecutablePath.Replace(".exe", ".ini");

            Ini ini;
            try {
                ini = new Ini(m_strFileSettings);
            } catch {
                ini = null;
            }

            if (ini == null)
                return;

            Ini.Section sec = ini["General"];
            if (sec == null)
                return;
            Ini.Property prop = sec["WindowState"];
            if (prop != null) {
                switch(prop.Value) {
                case "Maximized":
                    WindowState = FormWindowState.Maximized;
                    break;

                case "Minimized":
                    WindowState = FormWindowState.Minimized;
                    break;

                case "Normal":
                    WindowState = FormWindowState.Normal;
                    break;
                }

                if (WindowState == FormWindowState.Normal) {
                    Rectangle rc = new Rectangle();
                    rc.X = int.Parse(sec["X"].Value);
                    rc.Y = int.Parse(sec["Y"].Value);
                    rc.Width = int.Parse(sec["Width"].Value);
                    rc.Height = int.Parse(sec["Height"].Value);
                    Bounds = rc;
                }
            }

            prop = sec["AuthorKitPath"];
            if (prop != null)
                AuthorKitPath = prop.Value;
        }
Beispiel #12
0
        void SaveSettings()
        {
            // Save settings in ini.

            Ini ini = new Ini();
            Ini.Section secGeneral = new Ini.Section("General");
            secGeneral.Add(new Ini.Property("WindowState", WindowState.ToString()));
            secGeneral.Add(new Ini.Property("X", Bounds.X.ToString()));
            secGeneral.Add(new Ini.Property("Y", Bounds.Y.ToString()));
            secGeneral.Add(new Ini.Property("Width", Bounds.Width.ToString()));
            secGeneral.Add(new Ini.Property("Height", Bounds.Height.ToString()));
            secGeneral.Add(new Ini.Property("AuthorKitPath", AuthorKitPath));
            secGeneral.Add(new Ini.Property("Kit", Globals.IsKit().ToString()));
            secGeneral.Add(new Ini.Property("Eula", "1"));

            ini.Add(secGeneral);

            // Place in directory where .exe resides

            try {
                if (m_strFileSettings != null)
                    ini.Save(m_strFileSettings);
            } catch {
            }
        }
        public static void SaveExpansionPdb(string strFile, Document[] adoc, string strVersion)
        {
            // First save all level docs

            //annoying
            //DocManager.SaveAllModified(typeof(LevelDoc));

            // Remember active document

            LevelDoc lvldActive = (LevelDoc)DocManager.GetActiveDocument(typeof(LevelDoc));

            // Save documents adoc in an expansion .pdb. Expansion .pdbs need:
            // - .lvl, .tmap, .trmap, but not .tsets since these come from game .pdbs
            // - need a version.txt
            // - need an if demo trigger check "inserted" at save time
            // - .pdb needs WARI creator, ADD1 type
            // - data should be compressed for obfuscation purposes

            PdbPacker pdbp = new PdbPacker();

            // Add version.txt

            byte[] abT = new byte[strVersion.Length + 1];
            for (int n = 0; n < strVersion.Length; n++)
                abT[n] = (byte)strVersion[n];
            abT[abT.Length - 1] = 0;
            pdbp.Add(new PdbPacker.File("version.txt", abT));

            // Load res.h from embedded resource in prep for pre-process

            System.Reflection.Assembly ass = typeof(GobImage).Module.Assembly;
            Stream stmResDotH = ass.GetManifestResourceStream("m.EmbeddedResources." + "res.h");
            if (stmResDotH == null)
                throw new Exception("Cannot load res.h");

            // Compile levels

            Random rand = new Random();
            ArrayList alsTileSets = new ArrayList();
            foreach (LevelDoc lvld in adoc) {
                // Need to do this unfortunately; some of the "saving" code relies on what the "active" document
                // is!!

                DocManager.SetActiveDocument(typeof(LevelDoc), lvld);

                TemplateDoc tmpd = lvld.GetTemplateDoc();

                // Get appropriate TileSet, or make one if this map
                // uses a new tile collection

                TileSet tset = null;
                foreach (TileSet tsetT in alsTileSets) {
                    if (tsetT.TemplateDoc == tmpd) {
                        tset = tsetT;
                        break;
                    }
                }

                // Create new tile set if none found

                if (tset == null) {
                    tset = new TileSet(tmpd, tmpd.GetName() + ".tset");
                    alsTileSets.Add(tset);
                }

            #if false
                // Generate base file name for this level (this is never user-visible, but it should be
                // as unique as possible

                char[] achBase = new char[16];
                for (int n = 0; n < achBase.Length; n++) {
                    int nT = rand.Next() % (26 + 10);
                    if (nT < 26) {
                        achBase[n] = (char)(nT + 97);
                    } else {
                        achBase[n] = (char)(nT + 48 - 26);
                    }
                }
                if (lvld.MaxPlayers > 1) {
                    achBase[0] = 'm';
                    achBase[1] = '_';
                }
                string strBase = new String(achBase);
            #else
                // This isn't unique which can cause problems due to how packfiles work.
                // Could change packfile api to accept .pdb parameter.
                // Note1: set next mission action requires predictable filename
                // Note2: mission sorting is based on filename, not title
                // Could put lots of "support" in to fix these problems, or just ship
                // it like this.
                //
                // Hack: filename length 29
                // Maximum extension on filename: 7

                string strBase = lvld.Title;
                if (strBase.Length > 29 - 7)
                    strBase = strBase.Substring(0, 29 - 7);

                // If multiplayer, add "m_" to the name by losing the last two characters
                // so sort order is preserved

                if (lvld.MaxPlayers > 1)
                    strBase = "m_" + strBase.Substring(0, strBase.Length - 2);
            #endif

                // Get tile map file for this level

                MemoryStream stmTmap = new MemoryStream();
                TileMap tmap = TileMap.CreateFromImage(tset, lvld.GetMapBitmap(tmpd.TileSize, tmpd, true), tmpd.TileSize);
                tmap.Save(stmTmap);
                string strTmap = strBase + ".tmap";
                pdbp.Add(new PdbPacker.File(strTmap, stmTmap.ToArray()));
                stmTmap.Close();

                // Get the terrain map file for this level

                MemoryStream stmTRmap = new MemoryStream();
                TerrainMap trmap = new TerrainMap(lvld.GetTerrainMap(tmpd.TileSize, tmpd, false));
                trmap.Save(stmTRmap);
                string strTRmap = strBase + ".trmap";
                pdbp.Add(new PdbPacker.File(strTRmap, stmTRmap.ToArray()));
                stmTRmap.Close();

                // Save .ini file for this level doc

                MemoryStream stmLvld = new MemoryStream();
                lvld.SaveIni(stmLvld, -1, strTmap, strTRmap, tmpd.GetName() + ".palbin", true);

                // Pre-process

                stmLvld.Seek(0, SeekOrigin.Begin);
                MemoryStream stmPreprocessed = Misc.PreprocessStream(stmLvld, stmResDotH);
                stmPreprocessed.Seek(0, SeekOrigin.Begin);
                Ini iniPreProcessed = new Ini(stmPreprocessed);

                MemoryStream stmLvldPreProcessedBinary = new MemoryStream();
                iniPreProcessed.SaveBinary(stmLvldPreProcessedBinary);
                stmLvldPreProcessedBinary.Close();

                string strLvlName = lvld.OutputFilename;
                if (strLvlName == null) {
                    strLvlName = strBase + ".lvl";
                }
                pdbp.Add(new PdbPacker.File(strLvlName, stmLvldPreProcessedBinary.ToArray()));
                stmLvldPreProcessedBinary.Close();
            }
            stmResDotH.Close();

            // Restore active document

            if (lvldActive != null)
                DocManager.SetActiveDocument(typeof(LevelDoc), lvldActive);

            // Now save out pdb

            pdbp.Save(strFile, "WARI", "ADD2");
        }
Beispiel #14
0
 public SectionEnumerator(Ini ini)
 {
     m_ini = ini;
 }
Beispiel #15
0
        bool LoadSettings()
        {
            Ini ini;
            try {
                ini = new Ini(Application.ExecutablePath.Replace(".exe", ".ini"));
            } catch {
                ini = null;
            }

            // Sounds directory

            string strDirSounds = (ini != null) ? ini["General"]["SoundsDir"].Value : Directory.GetCurrentDirectory();
            SetSoundsDir(strDirSounds);

            // Sfx names

            string strSfxH = (ini != null && ini["General"]["Sfx.H"] != null) ? ini["General"]["Sfx.h"].Value : null;
            while (true) {
                if (strSfxH == null) {
                    // Get filename
                    OpenFileDialog frmOpen = new OpenFileDialog();
                    frmOpen.Filter = "Include Files (*.h)|*.h";
                    frmOpen.Title = "Open SoundEffects.h";
                    if (frmOpen.ShowDialog() == DialogResult.Cancel)
                        return false;
                    strSfxH = frmOpen.FileName;
                }
                if (ParseNames(strSfxH))
                    break;
                strSfxH = null;
            }
            m_strSfxH = strSfxH;

            return true;
        }
        public void LoadIni(Ini ini)
        {
            // General

            Ini.Section secGen = ini["General"];
            m_strTitle = secGen["Title"].Value;
            m_nPlayersMin = int.Parse(secGen["MinPlayers"].Value);
            m_nPlayersMax = int.Parse(secGen["MaxPlayers"].Value);

            // SideInfo

            for (Side side = Side.side1; side <= Side.side4; side++) {
                Ini.Section sec = ini[side.ToString()];
                if (sec == null) {
                    continue;
                }
                SideInfo sidi = new SideInfo(side);
                string s = sec["InitialView"].Value;
                Regex re = new Regex(@"^(?<tx>(-)?\d+),(?<ty>(-)?\d+)$");
                Match m = re.Match(s);
                int tx = int.Parse(m.Groups["tx"].Value);
                int ty = int.Parse(m.Groups["ty"].Value);
                Point ptInitialView = new Point(tx + Bounds.Left, ty + Bounds.Top);
                if (ptInitialView.X < Bounds.Left) {
                    ptInitialView.X = Bounds.Left;
                }
                if (ptInitialView.Y < Bounds.Top) {
                    ptInitialView.Y = Bounds.Top;
                }
                sidi.InitialView = ptInitialView;
                sidi.InitialCredits = int.Parse(sec["InitialCredits"].Value);
                sidi.Intelligence = (Intelligence)int.Parse(sec["Intelligence"].Value);
                m_alsidi.Add(sidi);
            }

            // Misc MapItems. Areas must come before GameObjects because GameObjects
            // can refer to Areas by index in UnitActions.

            string[] secNames = { "Galaxite", "Areas", "GameObjects" };
            foreach (string secName in secNames) {
                Ini.Section sec = ini[secName];
                ArrayList alsMapItems = new ArrayList();
                foreach (Ini.Property prop in sec) {
                    IMapItem mi = CreateGameObject(secName, prop.Name, prop.Value);
                    if (mi != null) {
                        alsMapItems.Add(mi);
                    }
                }
                // Sometimes Areas are given the same name. Then on export the sort order
                // doesn't match the original, which is a problem since in the game, area
                // creation order is important.

                if (secName == "Areas") {
                    for (int i = 0; i < alsMapItems.Count; i++) {
                        Area ar = (Area)alsMapItems[i];
                        ar.BonusSortKey = i;
                    }
                }
                AddMapItems((IMapItem[])alsMapItems.ToArray(typeof(IMapItem)));
            }

            // Switches (must be before triggers).

            foreach (Ini.Property prop in ini["Switches"]) {
                m_swm.AddSwitch(new Switch(prop.Name));
            }

            // UnitGroups (must be before triggers).

            m_ugm.LoadIni(ini);

            // Triggers

            m_tgrm.LoadIni(ini);

            // Clear out __cuaa UnitGroups now that triggers have been loaded
            // (CreateUnitAtAreaTrigger loads state from __cuaa triggers).

            ArrayList alsRemove = new ArrayList();
            for (int i = 0; i < m_ugm.Items.Count; i++) {
                UnitGroup ug = (UnitGroup)m_ugm.Items[i];
                if (ug.Name.StartsWith("__cuaa")) {
                    alsRemove.Add(ug);
                }
            }
            foreach (UnitGroup ug in alsRemove) {
                m_ugm.RemoveUnitGroup(ug);
            }

            // TODO: remove the demo check trigger
        }
        public void SaveIni(Stream stm, int nVersion, string strFileTmap, string strFileTrmap, string strFilePalette, bool fDemoCheckTrigger)
        {
            Ini ini = new Ini();
            Ini.Section sec;

            // [Intro]
            sec = new Ini.Section("Intro");
            sec.Add(new Ini.Property("String", "This is a test level!"));
            ini.Add(sec);

            // [Side1-n]
            int txOrigin = Bounds.X;
            int tyOrigin = Bounds.Y;

            // Hack - there should be a real "neutral" side
            ArrayList alsidiT = (ArrayList)m_alsidi.Clone();
            SideInfo sidiNeutral = new SideInfo(Side.sideNeutral);
            sidiNeutral.Intelligence = Intelligence.ComputerNeutral;
            sidiNeutral.InitialCredits = 0;
            sidiNeutral.InitialView = new Point(0, 0);
            alsidiT.Add(sidiNeutral);

            foreach (SideInfo sidi in alsidiT) {
                sec = new Ini.Section(sidi.Side.ToString());
                sec.Add(new Ini.Property("InitialView", String.Format("{0},{1}",
                    sidi.InitialView.X - txOrigin, sidi.InitialView.Y - tyOrigin)));
                sec.Add(new Ini.Property("InitialCredits", sidi.InitialCredits.ToString()));
                sec.Add(new Ini.Property("Intelligence", "knIntelligence" + sidi.Intelligence.ToString()));

                // How many units for this side?

                int cStructures = 0;
                int cMobileUnits = 0;
                foreach (IMapItem mi in m_alsmi) {
                    if (mi is Unit) {
                        Unit unt = (Unit)mi;
                        if (unt.Side == sidi.Side) {
                            if (mi is MobileUnit) {
                                cMobileUnits++;
                            }
                            if (mi is Structure) {
                                cStructures++;
                            }
                        }
                    }
                }
                sec.Add(new Ini.Property("InitialMobileUnitCount", cMobileUnits.ToString()));
                sec.Add(new Ini.Property("InitialStructureCount", cStructures.ToString()));
                ini.Add(sec);
            }

            // [GameObjects]
            sec = new Ini.Section("GameObjects");
            foreach (IMapItem mi in m_alsmi) {
                if (mi is Galaxite)
                    continue;
                if (mi is Area)
                    continue;
                if (mi is Wall)
                    continue;
                if (mi is Tile)
                    continue;

                Ini.Property prop = mi.GetIniProperty(txOrigin, tyOrigin);
                if (prop == null)
                    continue;

                // Skip Gobs that are out of bounds
                // UNDONE: can't do the right thing to make sure Gob's right/bottom
                // edges aren't out of bounds because M doesn't know the true
                // width and height of Gobs.

                if (!Bounds.Contains(new Rectangle((int)mi.tx, (int)mi.ty, mi.ctx, mi.cty))) {
                    Console.WriteLine("{0} out of bounds", mi);
                    continue;
                }
                sec.Add(prop);
            }
            ini.Add(sec);

            // [Galaxite]
            sec = new Ini.Section("Galaxite");
            foreach (IMapItem mi in m_alsmi) {
                if (!(mi is Galaxite))
                    continue;

                Ini.Property prop = mi.GetIniProperty(txOrigin, tyOrigin);
                if (prop == null)
                    continue;

                // Skip Galaxite that is out of bounds

                if (!Bounds.Contains((int)mi.tx, (int)mi.ty)) {
                    Console.WriteLine("{0} out of bounds", mi);
                    continue;
                }

                sec.Add(prop);
            }
            ini.Add(sec);

            #if false
            // In terrain now
            // [Walls]
            sec = new Ini.Section("Walls");
            foreach (IMapItem mi in m_alsmi) {
                if (!(mi is Wall))
                    continue;

                Ini.Property prop = mi.GetIniProperty(txOrigin, tyOrigin);
                if (prop == null)
                    continue;

                // Skip Walls that are out of bounds

                if (!Bounds.Contains((int)mi.tx, (int)mi.ty)) {
                    Console.WriteLine("{0} out of bounds", mi);
                    continue;
                }

                sec.Add(prop);
            }
            ini.Add(sec);
            #endif

            // [Areas]
            ArrayList alT = new ArrayList();
            foreach (IMapItem mi in m_alsmi) {
                if (!(mi is Area))
                    continue;
                alT.Add(mi);
            }
            alT.Sort();

            sec = new Ini.Section("Areas");
            foreach (IMapItem mi in alT) {
                Ini.Property prop = mi.GetIniProperty(txOrigin, tyOrigin);
                if (prop == null)
                    continue;

                Area area = (Area)mi;
                if (!Bounds.Contains(new Rectangle((int)mi.tx, (int)mi.ty, mi.ctx, mi.cty))) {
                    MessageBox.Show(String.Format("The area \"{0}\" lies outside of the map's bounds", area.Name), "Error Compiling Level");
                }

                sec.Add(prop);
            }
            ini.Add(sec);

            // [Triggers]
            // NOTE: Triggers must be written before UnitGroups because some trigger actions
            // e.g., CreateUnitAtArea will dynamically create UnitGroups and add them to the UnitGroup list
            ini.Add(m_tgrm.GetIniSection(fDemoCheckTrigger));

            // [UnitGroup 0-n]
            m_ugm.SaveIni(ini);

            // [Switches]
            sec = new Ini.Section("Switches");
            foreach (Switch sw in SwitchManager.Items)
                sec.Add(new Ini.Property(sw.Name, ""));
            ini.Add(sec);

            // [General]
            // This section is written last in case any of the values are modified by
            // the process of writing out the prior sections (e.g., CreateUnitAtArea actions add UnitGroups)
            sec = new Ini.Section("General", null);
            sec.Add(new Ini.Property("Title", Title));
            sec.Add(new Ini.Property("TileMap", strFileTmap));
            sec.Add(new Ini.Property("TerrainMap", strFileTrmap));
            sec.Add(new Ini.Property("Palette", strFilePalette));
            sec.Add(new Ini.Property("MinPlayers", m_nPlayersMin.ToString()));
            sec.Add(new Ini.Property("MaxPlayers", m_nPlayersMax.ToString()));
            sec.Add(new Ini.Property("UnitGroupCount", m_ugm.Items.Count.ToString()));

            // < 0 means use the current version, otherwise use the passed version
            // This is the "level file format" version

            if (nVersion < 0)
                nVersion = 1;
            sec.Add(new Ini.Property("Version", nVersion.ToString()));

            // Add a random number for the revision #. This # is used to determine if saved games are
            // based on older versions of a mission.

            if (nVersion > 0) {
                Random rand = new Random();
                uint dwRevision = (uint)rand.Next();
                sec.Add(new Ini.Property("Revision", dwRevision.ToString()));
            }

            ini.Add(sec);

            // Done

            ini.Save(stm);

            // Mostly Done.
            // Clean out the "__cuaa" unit groups created by CreateUnitAtAreaTriggerAction

            ArrayList alsRemove = new ArrayList();
            UnitGroup[] aug = (UnitGroup[])m_ugm.Items.ToArray(typeof(UnitGroup));
            for (int i = 0; i < m_ugm.Items.Count; i++) {
                if (((UnitGroup)m_ugm.Items[i]).Name.StartsWith("__cuaa")) {
                    alsRemove.Add(m_ugm.Items[i]);
                }
            }
            foreach (UnitGroup ug in alsRemove) {
                m_ugm.RemoveUnitGroup(ug);
            }
        }
        public void LoadIni(Ini ini)
        {
            Hashtable map = new Hashtable();
            Trigger tgrCurrent = null;
            Ini.Section sec = ini["Triggers"];
            foreach (Ini.Property prop in sec.Properties) {
                if (prop.Name == "Count") {
                    continue;
                }
                if (prop.Name == "T") {
                    tgrCurrent = new Trigger();
                    int nfSides = 0;
                    foreach (string key in prop.Value.Split(',')) {
                        Side side = (Side)int.Parse(key.Split(':')[0]);
                        nfSides |= SideToMask(side);
                        map.Add(key, tgrCurrent);
                    }
                    tgrCurrent.Sides = nfSides;
                    m_alsTriggers.Add(tgrCurrent);
                    continue;
                }
                if (prop.Name == "C") {
                    tgrCurrent.Conditions.Add(TriggerConditionLoader.LoadIni(prop.Value));
                    continue;
                }
                if (prop.Name == "A") {
                    tgrCurrent.Actions.Add(TriggerActionLoader.LoadIni(prop.Value));
                    continue;
                }
            }

            // Add the triggers for each side in proper order

            for (int side = 0; side < m_aalsSideTriggers.Length; side++) {
                int index = 0;
                while (true) {
                    bool fFound = false;
                    foreach (string key in map.Keys) {
                        int sideT = int.Parse(key.Split(':')[0]);
                        if (sideT != side) {
                            continue;
                        }
                        int indexT = int.Parse(key.Split(':')[1]);
                        if (indexT != index) {
                            continue;
                        }
                        fFound = true;
                        m_aalsSideTriggers[side].Add(map[key]);
                    }
                    if (!fFound) {
                        break;
                    }
                    index = index + 1;
                }
            }

            // Go through all the triggers and search for demo check trigger.
            // There should be only one, but check them all.

            ArrayList alsRemove = new ArrayList();
            foreach (Trigger tgr in m_alsTriggers) {
                foreach (CaBase cab in tgr.Conditions) {
                    if (cab.GetType() == typeof(TestPvarCondition)) {
                        TestPvarCondition cdn = (TestPvarCondition)cab;
                        if (cdn.GetVariableString() == "$demo") {
                            alsRemove.Add(tgr);
                            break;
                        }
                    }

                }
            }
            foreach (Trigger tgr in alsRemove) {
                RemoveTrigger(tgr);
            }

            // Triggers have been modified

            SetModified();
        }