Пример #1
0
        public void SaveToFile()
        {  //========================== WRITING TO A NEW FILE FOLLOWS ==========================
            if (filepath == null)
            {
                MessageBox.Show("You need to open a valid save file first!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            Byte[] checksumArea;
            uint   checksum;

            if (game == Game.EPF)   //============ ELITE PENGUIN FORCE ============
            {
                //WRITE INVENTORY

                for (int i = 0; i < saveFileEditor.inventoryBox.Items.Count; i++)
                {
                    if (saveFileEditor.inventoryBox.GetItemChecked(i))
                    {
                        filebytes[0xF650 + i] = 01;
                    }
                    else
                    {
                        filebytes[0xF650 + i] = 00;
                    }
                }

                //WRITE LIFETIME COINS
                WriteU32ToArray(filebytes, 0xF704, (uint)saveFileEditor.lifetimeCoins.Value); //lifetime coins

                //WRITE MINIGAME HIGH SCORES
                WriteU32ToArray(filebytes, 0xF708, (uint)saveFileEditor.highScore1.Value); //snowboarding
                WriteU32ToArray(filebytes, 0xF710, (uint)saveFileEditor.highScore2.Value); //cart surfer
                WriteU32ToArray(filebytes, 0xF70C, (uint)saveFileEditor.highScore3.Value); //ice fishing
                WriteU32ToArray(filebytes, 0xF714, (uint)saveFileEditor.highScore5.Value); //dance challenge
                WriteU32ToArray(filebytes, 0xF718, (uint)saveFileEditor.highScore4.Value); //jet pack adventure
                WriteU32ToArray(filebytes, 0xF71C, (uint)saveFileEditor.highScore6.Value); //snow trekker

                //ERASE OLD PENGUIN NAME (otherwise, if the new name is shorter, it won't overwrite the entire length old name)
                for (int i = 0; i < oldPenguinName.Length * 2; i++)
                {
                    filebytes[0xF720 + i] = 0x00;
                }

                //WRITE NEW PENGUIN NAME
                WriteU16StringToArray(filebytes, 0xF720, saveFileEditor.penguinNameTextBox.Text);
                oldPenguinName = saveFileEditor.penguinNameTextBox.Text;

                //ERASE OLD ONLINE NAMES (otherwise, if the new names are shorter, it won't overwrite the entire lengths of the old names)
                for (int i = 0; i < oldOnlineName1.Length * 2; i++)
                {
                    filebytes[0xF73A + i] = 0x00;
                }
                for (int i = 0; i < oldOnlineName2.Length * 2; i++)
                {
                    filebytes[0xF754 + i] = 0x00;
                }
                for (int i = 0; i < oldOnlineName3.Length * 2; i++)
                {
                    filebytes[0xF76E + i] = 0x00;
                }

                //WRITE NEW ONLINE NAMES
                WriteU16StringToArray(filebytes, 0xF73A, saveFileEditor.onlineName1.Text);
                oldOnlineName1 = saveFileEditor.onlineName1.Text;
                WriteU16StringToArray(filebytes, 0xF754, saveFileEditor.onlineName2.Text);
                oldOnlineName2 = saveFileEditor.onlineName1.Text;
                WriteU16StringToArray(filebytes, 0xF76E, saveFileEditor.onlineName3.Text);
                oldOnlineName3 = saveFileEditor.onlineName1.Text;

                //WRITE NEW COINS
                WriteU32ToArray(filebytes, 0xF7E4, (uint)saveFileEditor.coinsChooser.Value);

                //I get the feeling that 0xF7E8 could be a bitfield for which side missions you've completed (although it doesn't seem to control which ones are AVAILABLE)

                //WRITE CURRENT MISSION
                filebytes[0xF7EC] = (byte)saveFileEditor.currentMissionChooser.SelectedIndex;

                //WRITE NEW COLOUR
                filebytes[0xF7F0] = (byte)saveFileEditor.colourChooser.SelectedIndex;

                //WRITE CURRENT SIDEMISSION COMPLETEDNESS at 0xF7F4, and something else relevant might be at 0xF7F6?

                //When the relevant mask is set, the mission has been completed (and is no longer available).
                //However, the initial availability of the mission is somewhere else.
                //supposedly a bitfield, here are the bitmasks for now:


                //0x0001: A Wrench in the Works (ski village)
                //0x0002: Cart surfing mission (mine)
                //0x0004: Tour guide lost in forest mission (forest)
                //0x0008: Pizza ordering mission (pizza parlor)
                //0x0010: Wrong pizzas mission (pizza parlor)
                //0x0020: Finding sailboats mission (dock)
                //0x0040: Alien messages mission (forest)
                //0x0080: Lost scarf mission (ski hill)
                //0x0100: Rory fixing clock mission (snow forts)
                //0x0200: Hide and Seek (pet shop)

                //WRITE PUFFLES

                int puffles = 0x00;

                if (saveFileEditor.puffleBouncer.Checked)
                {
                    puffles = puffles | 0x01;
                }

                if (saveFileEditor.puffleBlast.Checked)
                {
                    puffles = puffles | 0x02;
                }

                if (saveFileEditor.puffleFlare.Checked)
                {
                    puffles = puffles | 0x04;
                }

                if (saveFileEditor.pufflePop.Checked)
                {
                    puffles = puffles | 0x08;
                }

                if (saveFileEditor.puffleLoop.Checked)
                {
                    puffles = puffles | 0x10;
                }

                if (saveFileEditor.puffleFlit.Checked)
                {
                    puffles = puffles | 0x20;
                }

                if (saveFileEditor.puffleChirp.Checked)
                {
                    puffles = puffles | 0x40;
                }

                if (saveFileEditor.puffleChill.Checked)
                {
                    puffles = puffles | 0x80;
                }

                filebytes[0xF7FB] = (byte)(puffles & 0xFF);

                //WRITE UNLOCKABLES (map, puffle whistle, etc)

                int unlocks = 0x00;

                if (saveFileEditor.mapUnlockable.Checked)
                {
                    unlocks = unlocks | 0x01;
                }

                if (saveFileEditor.HQteleportUnlockable.Checked)
                {
                    unlocks = unlocks | 0x02;
                }

                if (saveFileEditor.inventoryUnlockable.Checked)
                {
                    unlocks = unlocks | 0x04;
                }

                if (saveFileEditor.whistleUnlockable.Checked)
                {
                    unlocks = unlocks | 0x08;
                }

                filebytes[0xF7FC] = (byte)(unlocks & 0xFF);


                if (embeddedArc == null || (embeddedArc != null && embeddedArc.filebytes.Length < 0xC860))
                {
                    //if it's safe to write the newsletter, do so

                    //write the text

                    for (int i = 0; i < 0x96; i++)
                    {
                        if (i < saveFileEditor.topStoryBox.Text.Length)
                        {
                            filebytes[0xC960 + (i * 2)] = (byte)saveFileEditor.topStoryBox.Text[i];
                        }
                        else
                        {
                            filebytes[0xC960 + (i * 2)] = 0x00;
                        }
                        filebytes[0xC961 + (i * 2)] = 0x00;
                    }

                    for (int i = 0; i < 0x96; i++)
                    {
                        if (i < saveFileEditor.tipsAndSecretsTextBox.Text.Length)
                        {
                            filebytes[0xCA8C + (i * 2)] = (byte)saveFileEditor.tipsAndSecretsTextBox.Text[i];
                        }
                        else
                        {
                            filebytes[0xCA8C + (i * 2)] = 0x00;
                        }
                        filebytes[0xCA8D + (i * 2)] = 0x00;
                    }

                    for (int i = 0; i < 0x96; i++)
                    {
                        if (i < saveFileEditor.jokeTextBox.Text.Length)
                        {
                            filebytes[0xCBB8 + (i * 2)] = (byte)saveFileEditor.jokeTextBox.Text[i];
                        }
                        else
                        {
                            filebytes[0xCBB8 + (i * 2)] = 0x00;
                        }
                        filebytes[0xCBB9 + (i * 2)] = 0x00;
                    }

                    Array.Copy(newsletterImage, 0, filebytes, 0xCD10, 0x2940);  //copy newsletter image into save file

                    int colorindex = 0;
                    foreach (Color c in newsletterPalette)      //copy newsletter palette into save file
                    {
                        ushort ABGR1555Color = saveFileEditor.form1.ColorToABGR1555(c);
                        filebytes[0xCCF0 + (colorindex * 2)]     = (byte)(ABGR1555Color & 0x00FF);
                        filebytes[0xCCF0 + (colorindex * 2) + 1] = (byte)((ABGR1555Color & 0xFF00) >> 8);
                        colorindex++;
                    }
                }

                int endOfDownloadArc = 0;

                if (embeddedArc != null)
                {
                    //WRITE DOWNLOADABLE MISSION    (maybe you should also clear a space for it beforehand? in case the old mission was bigger)

                    Array.Copy(embeddedArc.filebytes, 0, filebytes, 0x100, embeddedArc.filebytes.Length);

                    //DOWNLOAD.ARC CHECKSUM CALCULATION
                    //redoing the checksum here just in case

                    endOfDownloadArc = (0x100 + embeddedArc.filebytes.Length) - 4; //minus 4, because the length includes the checksum, but that's what we want to write to

                    while (endOfDownloadArc % 4 != 0)                              //pad to multiple of 4
                    {
                        filebytes[endOfDownloadArc] = 0;
                        endOfDownloadArc++;
                    }

                    checksumArea = new Byte[endOfDownloadArc - 0x100];

                    Array.Copy(filebytes, 0x100, checksumArea, 0x0, endOfDownloadArc - 0x100);

                    checksum = Crc32.Compute(checksumArea);
                    WriteU32ToArray(filebytes, endOfDownloadArc, checksum);
                }

                //CHECKSUM CALCULATION EPF

                int checksumAreaSize = 0xF700;

                if (extendedSaveMode)
                {
                    checksumAreaSize = 0xFF00;
                }

                checksumArea = new Byte[checksumAreaSize];

                Array.Copy(filebytes, 0x100, checksumArea, 0x0, checksumAreaSize);

                checksum = Crc32.Compute(checksumArea);
                WriteU32ToArray(filebytes, 0x0C, checksum);
            }
            else if (game == Game.HR)   //============ HERBERT'S REVENGE ============
            {
                //WRITE NEW COINS
                WriteU32ToArray(filebytes, 0x28, (uint)saveFileEditor.coinsChooser.Value);

                //ERASE OLD PENGUIN NAME (otherwise, if the new name is shorter, it won't overwrite the entire length old name)
                for (int i = 0; i < oldPenguinName.Length * 2; i++)
                {
                    filebytes[0x58 + i] = 0x00;
                }

                //WRITE NEW PENGUIN NAME
                WriteU16StringToArray(filebytes, 0x58, saveFileEditor.penguinNameTextBox.Text);
                oldPenguinName = saveFileEditor.penguinNameTextBox.Text;


                //WRITE NEW COLOUR
                filebytes[0x24] = (byte)saveFileEditor.colourChooser.SelectedIndex;

                //WRITE NEW MISSION
                WriteU16ToArray(filebytes, 0xA6, GetNewHRMissionValue(saveFileEditor.currentMissionChooser.SelectedIndex));

                //WRITE INVENTORY

                for (int i = 0; i < saveFileEditor.inventoryBox.Items.Count; i++)
                {
                    if (saveFileEditor.inventoryBox.GetItemChecked(i))
                    {
                        filebytes[0x0124 + i] = 01;
                    }
                    else
                    {
                        filebytes[0x0124 + i] = 00;
                    }
                }

                //CHECKSUM CALCULATION HR

                checksumArea = new Byte[0x130];

                Array.Copy(filebytes, 0x20, checksumArea, 0x0, 0x130);

                checksum = Crc32.Compute(checksumArea);
                WriteU32ToArray(filebytes, 0x08, checksum);
            }

            File.WriteAllBytes(filepath, filebytes);
        }