mirror of
https://github.com/isledecomp/LEGOIslandRebuilder.git
synced 2024-11-23 15:48:03 -05:00
added music injector
This commit is contained in:
parent
7128233685
commit
4492c53cae
3 changed files with 1059 additions and 27 deletions
964
Rebuilder/MusicInjector.cs
Normal file
964
Rebuilder/MusicInjector.cs
Normal file
|
@ -0,0 +1,964 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using System.Media;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Rebuilder
|
||||
{
|
||||
class MusicInjector : Form
|
||||
{
|
||||
string jukebox_si_path = "";
|
||||
string temp_extract_path = "";
|
||||
|
||||
DataGridView table = new DataGridView();
|
||||
List<string> filenames = new List<string>();
|
||||
|
||||
SoundPlayer sound_player = new SoundPlayer();
|
||||
int last_played_row = -1;
|
||||
|
||||
public MusicInjector()
|
||||
{
|
||||
Text = "Music Injector";
|
||||
Icon = Icon.ExtractAssociatedIcon(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
Visible = false;
|
||||
Width = 720;
|
||||
Height = 540;
|
||||
|
||||
table.ReadOnly = true;
|
||||
table.RowHeadersVisible = false;
|
||||
table.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
table.AllowUserToResizeRows = false;
|
||||
|
||||
table.CellClick += new DataGridViewCellEventHandler(TableCellClicked);
|
||||
|
||||
table.Columns.Add("name", "Name");
|
||||
table.Columns.Add("filename", "Filename");
|
||||
|
||||
// Create Extract button column
|
||||
DataGridViewButtonColumn play_col = new DataGridViewButtonColumn();
|
||||
play_col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
|
||||
play_col.HeaderText = "Play";
|
||||
play_col.Text = "Play";
|
||||
play_col.Name = "play";
|
||||
play_col.UseColumnTextForButtonValue = true;
|
||||
table.Columns.Add(play_col);
|
||||
|
||||
// Create Extract button column
|
||||
DataGridViewButtonColumn extract_col = new DataGridViewButtonColumn();
|
||||
extract_col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
|
||||
extract_col.HeaderText = "Extract";
|
||||
extract_col.Text = "Extract";
|
||||
extract_col.Name = "extract";
|
||||
extract_col.UseColumnTextForButtonValue = true;
|
||||
table.Columns.Add(extract_col);
|
||||
|
||||
// Create Replace button column
|
||||
DataGridViewButtonColumn replace_col = new DataGridViewButtonColumn();
|
||||
replace_col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
|
||||
replace_col.HeaderText = "Replace";
|
||||
replace_col.Text = "Replace";
|
||||
replace_col.Name = "replace";
|
||||
replace_col.UseColumnTextForButtonValue = true;
|
||||
table.Columns.Add(replace_col);
|
||||
|
||||
foreach (DataGridViewColumn col in table.Columns)
|
||||
{
|
||||
col.SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
}
|
||||
|
||||
table.Dock = DockStyle.Fill;
|
||||
|
||||
Controls.Add(table);
|
||||
|
||||
Shown += new EventHandler(OnShow);
|
||||
FormClosing += new FormClosingEventHandler(OnClose);
|
||||
}
|
||||
|
||||
private void OnClose(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
sound_player.Stop();
|
||||
}
|
||||
|
||||
private void OnShow(object sender, EventArgs e)
|
||||
{
|
||||
CenterToScreen();
|
||||
|
||||
if (string.IsNullOrEmpty(jukebox_si_path))
|
||||
{
|
||||
FindJukeboxSI();
|
||||
|
||||
if (string.IsNullOrEmpty(jukebox_si_path))
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Rebuilder needs access to JUKEBOX.SI to inject music.",
|
||||
"Failed to find critical files",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error
|
||||
);
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
Extract();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FindJukeboxSI()
|
||||
{
|
||||
// Test standard directories
|
||||
List<string> test_dirs = new List<string>();
|
||||
|
||||
test_dirs.AddRange(Rebuilder.standard_hdd_dirs);
|
||||
|
||||
// Loop through drive letters
|
||||
for (int i=65;i<91;i++)
|
||||
{
|
||||
string drive_letter = ((char)i).ToString() + ":";
|
||||
test_dirs.Add(drive_letter);
|
||||
}
|
||||
|
||||
for (int i=0;i< test_dirs.Count;i++)
|
||||
{
|
||||
string test_fn = test_dirs[i] + "/LEGO/Scripts/ISLE/JUKEBOX.SI";
|
||||
if (File.Exists(test_fn))
|
||||
{
|
||||
jukebox_si_path = test_fn;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to asking
|
||||
using (OpenFileDialog ofd = new OpenFileDialog())
|
||||
{
|
||||
ofd.Filter = "JUKEBOX.SI|JUKEBOX.SI";
|
||||
ofd.Title = "Where is JUKEBOX.SI?";
|
||||
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
jukebox_si_path = ofd.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool SeekUntil(FileStream stream, string str, long limit = -1)
|
||||
{
|
||||
byte[] b = new byte[str.Length];
|
||||
|
||||
int read_byte;
|
||||
|
||||
// Read until
|
||||
while ((read_byte = stream.ReadByte()) != -1 && (limit == -1 || stream.Position < limit))
|
||||
{
|
||||
// Push bytes along
|
||||
for (int i = 1; i < b.Length; i++)
|
||||
{
|
||||
b[i - 1] = b[i];
|
||||
}
|
||||
|
||||
// Set last byte to the newest byte
|
||||
b[b.Length - 1] = (byte)read_byte;
|
||||
|
||||
// See if byte array matches string
|
||||
if (System.Text.Encoding.ASCII.GetString(b) == str)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string BacktrackToFindWAVFilename(FileStream stream)
|
||||
{
|
||||
string wav_fn = "";
|
||||
long current_pos = stream.Position;
|
||||
do
|
||||
{
|
||||
stream.Position -= 2;
|
||||
} while ((char)stream.ReadByte() != '\\');
|
||||
|
||||
int wav_fn_char;
|
||||
while ((wav_fn_char = stream.ReadByte()) != 0)
|
||||
{
|
||||
wav_fn += (char)wav_fn_char;
|
||||
}
|
||||
stream.Position = current_pos;
|
||||
return wav_fn;
|
||||
}
|
||||
|
||||
private void TableCellClicked(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.RowIndex < 0 || e.RowIndex >= filenames.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string fn = filenames[e.RowIndex];
|
||||
string full_path = temp_extract_path + "/" + fn;
|
||||
|
||||
switch (e.ColumnIndex)
|
||||
{
|
||||
case 2: // PLAY
|
||||
if (last_played_row == e.RowIndex)
|
||||
{
|
||||
sound_player.Stop();
|
||||
last_played_row = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_played_row = e.RowIndex;
|
||||
|
||||
string cell_fn = table.Rows[e.RowIndex].Cells[1].Value.ToString();
|
||||
string play_fn;
|
||||
if (cell_fn == fn)
|
||||
{
|
||||
play_fn = full_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
play_fn = cell_fn;
|
||||
}
|
||||
|
||||
sound_player.SoundLocation = play_fn;
|
||||
sound_player.Play();
|
||||
}
|
||||
break;
|
||||
case 3: // EXTRACT
|
||||
using (SaveFileDialog sfd = new SaveFileDialog())
|
||||
{
|
||||
sfd.Title = "Save \"" + fn + "\"";
|
||||
sfd.Filter = "WAVE Audio (*.wav)|*.wav";
|
||||
sfd.FileName = fn;
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Copy(full_path, sfd.FileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Failed to save file. You may not have permission to save to this location.",
|
||||
"Failed to save",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: // REPLACE
|
||||
|
||||
bool replace = (table.Rows[e.RowIndex].Cells[1].Value.ToString() == filenames[e.RowIndex]);
|
||||
|
||||
if (last_played_row == e.RowIndex)
|
||||
{
|
||||
sound_player.Stop();
|
||||
last_played_row = -1;
|
||||
}
|
||||
|
||||
if (!replace)
|
||||
{
|
||||
if (MessageBox.Show("This audio has already been replaced. Do you want to restore the original audio?",
|
||||
"Replace or Restore",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question) == DialogResult.No)
|
||||
{
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (replace)
|
||||
{
|
||||
using (OpenFileDialog ofd = new OpenFileDialog())
|
||||
{
|
||||
ofd.Title = "Replace \"" + fn + "\"";
|
||||
ofd.Filter = "WAVE Audio (*.wav)|*.wav";
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
Font f = new Font(table.Font, FontStyle.Bold);
|
||||
|
||||
table.Rows[e.RowIndex].Cells[0].Style.Font = f;
|
||||
table.Rows[e.RowIndex].Cells[1].Style.Font = f;
|
||||
|
||||
table.Rows[e.RowIndex].Cells[1].Value = ofd.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
table.Rows[e.RowIndex].Cells[0].Style.Font = table.Font;
|
||||
table.Rows[e.RowIndex].Cells[1].Style.Font = table.Font;
|
||||
|
||||
table.Rows[e.RowIndex].Cells[1].Value = filenames[e.RowIndex];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Extract()
|
||||
{
|
||||
int file_count = 0;
|
||||
temp_extract_path = Path.GetTempPath() + "lire/jukebox";
|
||||
Directory.CreateDirectory(temp_extract_path);
|
||||
|
||||
using (FileStream stream = new FileStream(jukebox_si_path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
byte[] b = new byte[4];
|
||||
|
||||
while (SeekUntil(stream, " WAV"))
|
||||
{
|
||||
|
||||
long pos_before_find_id = stream.Position;
|
||||
|
||||
// Backtrack to find the filename
|
||||
string wav_fn = BacktrackToFindWAVFilename(stream);
|
||||
|
||||
file_count++;
|
||||
|
||||
string wav_path = temp_extract_path + "/" + wav_fn;
|
||||
|
||||
// Find the ID of the WAV
|
||||
stream.Position = pos_before_find_id;
|
||||
|
||||
do
|
||||
{
|
||||
stream.Position -= (b.Length + 1);
|
||||
stream.Read(b, 0, b.Length);
|
||||
} while (System.Text.Encoding.ASCII.GetString(b) != "MxOb");
|
||||
stream.Position += 11;
|
||||
|
||||
List<byte> wav_name_bytes = new List<byte>();
|
||||
int wav_nbyte;
|
||||
while ((wav_nbyte = stream.ReadByte()) != 0x00) {
|
||||
wav_name_bytes.Add((byte) wav_nbyte);
|
||||
}
|
||||
string wav_name = System.Text.Encoding.ASCII.GetString(wav_name_bytes.ToArray());
|
||||
|
||||
stream.Read(b, 0, b.Length);
|
||||
Int32 id = BitConverter.ToInt32(b, 0);
|
||||
stream.Position = pos_before_find_id;
|
||||
|
||||
// Find first LIST which contains the size of this WAVE section
|
||||
SeekUntil(stream, "LIST");
|
||||
stream.Read(b, 0, b.Length);
|
||||
Int32 list_size = BitConverter.ToInt32(b, 0);
|
||||
long list_data_start = stream.Position;
|
||||
long list_end_pos = list_data_start + list_size;
|
||||
|
||||
// Get WAVE-compatible header position
|
||||
long wave_header_pos = -1;
|
||||
|
||||
pos_before_find_id = stream.Position;
|
||||
while (true)
|
||||
{
|
||||
// Find first MxCh which contains the WAVE header information
|
||||
SeekUntil(stream, "MxCh");
|
||||
|
||||
// Check ID
|
||||
stream.Position += 6;
|
||||
stream.Read(b, 0, b.Length);
|
||||
if (BitConverter.ToInt32(b, 0) == id)
|
||||
{
|
||||
wave_header_pos = stream.Position + 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream.Position = pos_before_find_id;
|
||||
|
||||
|
||||
|
||||
//Console.WriteLine("Extracting \"" + wav_fn + "\"");
|
||||
|
||||
// Get WAVE-compatible header
|
||||
stream.Position = wave_header_pos;
|
||||
byte[] copied_bytes = new byte[16];
|
||||
stream.Read(copied_bytes, 0, 16);
|
||||
|
||||
table.Rows.Add(wav_name, wav_fn);
|
||||
filenames.Add(wav_fn);
|
||||
|
||||
using (FileStream wav_out = new FileStream(wav_path, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
wav_out.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"), 0, 4);
|
||||
|
||||
// 4 bytes for file size
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
wav_out.WriteByte(0);
|
||||
}
|
||||
|
||||
wav_out.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt "), 0, 8);
|
||||
|
||||
// Subchunk size (always 16)
|
||||
wav_out.Write(BitConverter.GetBytes(16), 0, 4);
|
||||
|
||||
// Copy bytes from WAVE header
|
||||
wav_out.Write(copied_bytes, 0, 16);
|
||||
|
||||
// Data chunk header
|
||||
wav_out.Write(System.Text.Encoding.ASCII.GetBytes("data"), 0, 4);
|
||||
|
||||
// 4 bytes for data chunk size
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
wav_out.WriteByte(0);
|
||||
}
|
||||
|
||||
// Start reading chunks
|
||||
Int32 data_chunk_size = 0;
|
||||
|
||||
int chunk_counter = 0;
|
||||
|
||||
while (SeekUntil(stream, "MxCh", list_end_pos))
|
||||
{
|
||||
// Read chunk size
|
||||
stream.Read(b, 0, b.Length);
|
||||
|
||||
Int32 mxch_size = BitConverter.ToInt32(b, 0) - 14;
|
||||
|
||||
// Weird 16-bit thing
|
||||
stream.Read(b, 0, 2);
|
||||
Int16 v1 = BitConverter.ToInt16(b, 0);
|
||||
|
||||
// ID?
|
||||
stream.Read(b, 0, 4);
|
||||
Int32 v2 = BitConverter.ToInt32(b, 0);
|
||||
|
||||
// Millis
|
||||
stream.Read(b, 0, 4);
|
||||
Int32 millis = BitConverter.ToInt32(b, 0);
|
||||
|
||||
// Bytes
|
||||
stream.Read(b, 0, 4);
|
||||
Int32 bytes = BitConverter.ToInt32(b, 0);
|
||||
|
||||
if (mxch_size > 0 && v2 == id)
|
||||
{
|
||||
byte[] chunk_data = new byte[mxch_size];
|
||||
stream.Read(chunk_data, 0, mxch_size);
|
||||
wav_out.Write(chunk_data, 0, mxch_size);
|
||||
|
||||
chunk_counter++;
|
||||
|
||||
data_chunk_size += mxch_size;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in file size
|
||||
wav_out.Position = 4;
|
||||
wav_out.Write(BitConverter.GetBytes(wav_out.Length - 8), 0, 4);
|
||||
|
||||
// Fill in data chunk size
|
||||
wav_out.Position = 40;
|
||||
wav_out.Write(BitConverter.GetBytes(data_chunk_size), 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Console.WriteLine("\nDone! Extracted " + file_count + " files\n");
|
||||
}
|
||||
|
||||
static void WriteString(FileStream stream, string text)
|
||||
{
|
||||
byte[] b = System.Text.Encoding.ASCII.GetBytes(text);
|
||||
stream.Write(b, 0, b.Length);
|
||||
}
|
||||
|
||||
static void WriteZeroes(FileStream stream, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
stream.WriteByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteMxChHeader(FileStream stream, Int32 chunk_size, Int16 flags, Int32 id, Int32 millis, Int32 actual_data_size)
|
||||
{
|
||||
// MxChs have to fall on even numbers
|
||||
if (stream.Position % 2 == 1)
|
||||
{
|
||||
stream.WriteByte(0);
|
||||
}
|
||||
|
||||
// Write chunk header
|
||||
WriteString(stream, "MxCh");
|
||||
|
||||
// Chunk total size
|
||||
byte[] write_bytes = BitConverter.GetBytes(chunk_size);
|
||||
stream.Write(write_bytes, 0, write_bytes.Length);
|
||||
|
||||
// Write flags
|
||||
write_bytes = BitConverter.GetBytes(flags);
|
||||
stream.Write(write_bytes, 0, write_bytes.Length);
|
||||
|
||||
// Write ID
|
||||
write_bytes = BitConverter.GetBytes(id);
|
||||
stream.Write(write_bytes, 0, write_bytes.Length);
|
||||
|
||||
// Write milliseconds
|
||||
write_bytes = BitConverter.GetBytes(millis);
|
||||
stream.Write(write_bytes, 0, write_bytes.Length);
|
||||
|
||||
// Write total data size
|
||||
write_bytes = BitConverter.GetBytes(actual_data_size);
|
||||
stream.Write(write_bytes, 0, write_bytes.Length);
|
||||
}
|
||||
|
||||
public void Insert(string output_fn)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jukebox_si_path))
|
||||
{
|
||||
FindJukeboxSI();
|
||||
|
||||
if (string.IsNullOrEmpty(jukebox_si_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < filenames.Count; i++)
|
||||
{
|
||||
if (table.Rows[i].Cells[1].Value.ToString() != filenames[i])
|
||||
{
|
||||
File.Copy(table.Rows[i].Cells[1].Value.ToString(), temp_extract_path + "/" + filenames[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
Reconstruct(output_fn);
|
||||
}
|
||||
|
||||
private void Reconstruct(string output_fn)
|
||||
{
|
||||
// For inserting, we reconstruct the SI file from scratch
|
||||
|
||||
using (FileStream in_stream = new FileStream(jukebox_si_path, FileMode.Open, FileAccess.Read))
|
||||
using (FileStream out_stream = new FileStream(output_fn, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
// First we copy the SI header up until the first MxSt since that will be largely identical (though a lot of the variables will change)
|
||||
byte[] si_header = new byte[312];
|
||||
in_stream.Read(si_header, 0, si_header.Length);
|
||||
out_stream.Write(si_header, 0, si_header.Length);
|
||||
|
||||
byte[] b = new byte[4];
|
||||
|
||||
// Next we loop over the in_stream finding "MxSt"s til the end of the file
|
||||
while (SeekUntil(in_stream, "MxSt"))
|
||||
{
|
||||
// Find this MxSt's original offset location
|
||||
long in_mxst_loc = in_stream.Position - 4;
|
||||
in_stream.Position = 0x2C;
|
||||
long offset_index_loc = -1;
|
||||
while (in_stream.Position < 0x12C)
|
||||
{
|
||||
in_stream.Read(b, 0, b.Length);
|
||||
|
||||
if (BitConverter.ToInt32(b, 0) == in_mxst_loc)
|
||||
{
|
||||
offset_index_loc = in_stream.Position - 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
in_stream.Position = in_mxst_loc + 4;
|
||||
|
||||
// Ensure we got an MxOf index
|
||||
if (offset_index_loc == -1)
|
||||
{
|
||||
Console.WriteLine("FAILED TO FIND MXOF ENTRY for MxSt at " + in_mxst_loc);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the new offset
|
||||
long out_mxst_loc = out_stream.Position;
|
||||
out_stream.Position = offset_index_loc;
|
||||
byte[] new_offset_bytes = BitConverter.GetBytes((Int32)out_mxst_loc);
|
||||
out_stream.Write(new_offset_bytes, 0, new_offset_bytes.Length);
|
||||
out_stream.Position = out_mxst_loc;
|
||||
|
||||
// Write an MxSt in the output stream
|
||||
WriteString(out_stream, "MxSt");
|
||||
|
||||
// Write 4-bytes to fill in later for the stream length
|
||||
long mxst_length_position = out_stream.Position;
|
||||
WriteZeroes(out_stream, 4);
|
||||
|
||||
// We expect an MxOb here so we'll write that
|
||||
WriteString(out_stream, "MxOb");
|
||||
|
||||
// Skip original's MxSt length and MxOb since we don't need it
|
||||
in_stream.Position += 8;
|
||||
|
||||
// Read MxOb length since we'll be copying that verbatim and copy it to the file
|
||||
in_stream.Read(b, 0, b.Length);
|
||||
Int32 mxob_len = BitConverter.ToInt32(b, 0);
|
||||
out_stream.Write(b, 0, b.Length);
|
||||
|
||||
// Copy MxOb data
|
||||
byte[] mxob_data = new byte[mxob_len];
|
||||
in_stream.Read(mxob_data, 0, mxob_len);
|
||||
out_stream.Write(mxob_data, 0, mxob_len);
|
||||
|
||||
// Find ID in MxOb data
|
||||
List<string> types = new List<string>();
|
||||
List<Int32> ids = new List<Int32>();
|
||||
List<List<byte[]>> data = new List<List<byte[]>>();
|
||||
Int32 wav_id = -1;
|
||||
Int32 flc_id = -1;
|
||||
int flc_write_count = 1;
|
||||
|
||||
for (int i = 0; i < mxob_len - 4; i++)
|
||||
{
|
||||
// If this MxOb has sub MxObs, we need to find the WAV one
|
||||
if (System.Text.Encoding.ASCII.GetString(mxob_data, i, 4) == "MxOb" || i == 0)
|
||||
{
|
||||
string t = "";
|
||||
Int32 id = -1;
|
||||
|
||||
// Find ID
|
||||
for (i += 15; i < mxob_len; i++)
|
||||
{
|
||||
if (mxob_data[i] == 0)
|
||||
{
|
||||
id = BitConverter.ToInt32(mxob_data, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find type
|
||||
for (; i < mxob_len - 4; i++)
|
||||
{
|
||||
string here = System.Text.Encoding.ASCII.GetString(mxob_data, i, 4);
|
||||
if (here == "LIST" || here == " WAV" || here == " FLC")
|
||||
{
|
||||
if (here == " WAV")
|
||||
{
|
||||
wav_id = id;
|
||||
}
|
||||
else if (here == " FLC")
|
||||
{
|
||||
flc_id = id;
|
||||
}
|
||||
|
||||
t = here;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
types.Add(t);
|
||||
ids.Add(id);
|
||||
data.Add(new List<byte[]>());
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity checking that we found the ID
|
||||
if (ids.Count == 0 || wav_id == -1)
|
||||
{
|
||||
Console.WriteLine("Failed to find MxSt ID");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sometimes a header has an odd length, but the files are automatically aligned to 2-bytes so we'll write an extra byte here
|
||||
if (mxob_len % 2 == 1)
|
||||
{
|
||||
out_stream.WriteByte((byte)in_stream.ReadByte());
|
||||
}
|
||||
|
||||
// Find the WAVE specified in in_stream
|
||||
string wav_fn = BacktrackToFindWAVFilename(in_stream);
|
||||
|
||||
// Here we expect a "LIST" followed by the first "MxCh" which contains the wave header. The LIST contains a size that we'll need to modify
|
||||
WriteString(out_stream, "LIST");
|
||||
in_stream.Position += 4;
|
||||
|
||||
// LIST size
|
||||
long list_size_pos = out_stream.Position;
|
||||
WriteZeroes(out_stream, 4);
|
||||
|
||||
// Read file's LIST size so we can quickly skip over it later
|
||||
in_stream.Read(b, 0, b.Length);
|
||||
long end_list_pos = in_stream.Position + BitConverter.ToInt32(b, 0);
|
||||
|
||||
// Write leading MxDa
|
||||
in_stream.Position += 4;
|
||||
WriteString(out_stream, "MxDa");
|
||||
|
||||
long wave_header_pos = -1;
|
||||
|
||||
// Each sub-object will need a leading chunk
|
||||
for (int i = 0; i < ids.Count; i++)
|
||||
{
|
||||
// LIST's leading chunk was part of the MxOb header so we don't need to copy it
|
||||
if (types[i] != "LIST")
|
||||
{
|
||||
// Write "MxCh" header
|
||||
in_stream.Position += 4;
|
||||
WriteString(out_stream, "MxCh");
|
||||
|
||||
// Read MxCh size
|
||||
in_stream.Read(b, 0, b.Length);
|
||||
Int32 leading_mxch_size = BitConverter.ToInt32(b, 0);
|
||||
out_stream.Write(b, 0, b.Length);
|
||||
|
||||
// Copy MxCh data
|
||||
// The first MxCh contains 50 bytes of data that we'll just copy
|
||||
byte[] early_mxch_data = new byte[leading_mxch_size];
|
||||
in_stream.Read(early_mxch_data, 0, early_mxch_data.Length);
|
||||
out_stream.Write(early_mxch_data, 0, early_mxch_data.Length);
|
||||
|
||||
if (types[i] == " WAV")
|
||||
{
|
||||
wave_header_pos = out_stream.Position - 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int si_buffer_size = 0x20000;
|
||||
|
||||
// We don't support replacing the other data at this time, but we'll still need to interleave it
|
||||
if (ids.Count > 1)
|
||||
{
|
||||
//int chcounter = 0;
|
||||
while (SeekUntil(in_stream, "MxCh", end_list_pos))
|
||||
{
|
||||
long chunk_start = in_stream.Position - 4;
|
||||
|
||||
// Get chunk size just in case we need to copy it
|
||||
in_stream.Read(b, 0, b.Length);
|
||||
Int32 chunk_sz = BitConverter.ToInt32(b, 0);
|
||||
|
||||
// Find which MxOb this belongs to
|
||||
in_stream.Read(b, 0, 2);
|
||||
Int16 chunk_flags = BitConverter.ToInt16(b, 0);
|
||||
|
||||
in_stream.Read(b, 0, b.Length);
|
||||
Int32 chunk_id = BitConverter.ToInt32(b, 0);
|
||||
int chunk_index = ids.IndexOf(chunk_id);
|
||||
|
||||
//Console.WriteLine(" Found chunk with ID " + chunk_id + " " + types[chunk_index] + " " + chunk_sz);
|
||||
|
||||
if (types[chunk_index] != " WAV" && chunk_sz > 14)
|
||||
{
|
||||
in_stream.Position = chunk_start;
|
||||
|
||||
byte[] foreign_data = new byte[chunk_sz + 8];
|
||||
in_stream.Read(foreign_data, 0, foreign_data.Length);
|
||||
|
||||
data[chunk_index].Add(foreign_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Int32 millis = 0;
|
||||
|
||||
if (File.Exists(temp_extract_path + "/" + wav_fn))
|
||||
{
|
||||
using (FileStream wav_str = new FileStream(temp_extract_path + "/" + wav_fn, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
//Console.WriteLine("Inserting " + wav_fn);
|
||||
|
||||
// Ignore first part of the wav header
|
||||
if (!SeekUntil(wav_str, "WAVE") || !SeekUntil(wav_str, "fmt "))
|
||||
{
|
||||
Console.WriteLine("Invalid file at " + wav_fn);
|
||||
return;
|
||||
}
|
||||
wav_str.Position += 4;
|
||||
|
||||
long old_pos = out_stream.Position;
|
||||
out_stream.Position = wave_header_pos;
|
||||
|
||||
// Copy WAV header data
|
||||
byte[] wav_header = new byte[16];
|
||||
wav_str.Read(wav_header, 0, wav_header.Length);
|
||||
out_stream.Write(wav_header, 0, wav_header.Length);
|
||||
|
||||
// Total data size in MxCh is the WAV's data size + 4
|
||||
if (!SeekUntil(wav_str, "data"))
|
||||
{
|
||||
Console.WriteLine("Invalid file at " + wav_fn);
|
||||
return;
|
||||
}
|
||||
byte[] data_size_bytes = new byte[4];
|
||||
wav_str.Read(data_size_bytes, 0, data_size_bytes.Length);
|
||||
Int32 wav_data_size = (BitConverter.ToInt32(data_size_bytes, 0));
|
||||
data_size_bytes = BitConverter.GetBytes((Int32)(wav_data_size + 4));
|
||||
out_stream.Write(data_size_bytes, 0, data_size_bytes.Length);
|
||||
long wav_end = wav_str.Position + wav_data_size;
|
||||
|
||||
// Re-skip latter 4 bytes of MxCh header
|
||||
out_stream.Position = old_pos;
|
||||
|
||||
// Write first FLC chunk
|
||||
/*
|
||||
if (flc_id != -1)
|
||||
{
|
||||
int index = ids.IndexOf(flc_id);
|
||||
int remainder = (int)(si_buffer_size - (out_stream.Position % si_buffer_size));
|
||||
|
||||
if (data[index][0].Length > remainder)
|
||||
{
|
||||
WriteZeroes(out_stream, (int)remainder);
|
||||
}
|
||||
|
||||
out_stream.Write(data[index][0], 0, data[index][0].Length);
|
||||
}
|
||||
*/
|
||||
|
||||
// Loop over data in WAV
|
||||
// Write out WAV file chunking along the way
|
||||
int max_wav_data = BitConverter.ToInt32(wav_header, 8);
|
||||
int max_chunk_size = max_wav_data + 22;
|
||||
while (wav_str.Position < wav_end)
|
||||
{
|
||||
// SI files are also buffered at 20000h (or 131072 bytes), so we can only write that much at a time
|
||||
Int32 this_chunk_max = (Int32)Math.Min(max_chunk_size, si_buffer_size - (out_stream.Position % si_buffer_size));
|
||||
|
||||
if (this_chunk_max <= 22)
|
||||
{
|
||||
WriteZeroes(out_stream, this_chunk_max);
|
||||
}
|
||||
else
|
||||
{
|
||||
Int16 flags = 0;
|
||||
if (this_chunk_max < max_chunk_size)
|
||||
{
|
||||
flags = 16;
|
||||
}
|
||||
|
||||
this_chunk_max -= 8;
|
||||
|
||||
int actual_wav_chunk_size = this_chunk_max - 14;
|
||||
|
||||
int actual_data_chunk_size = max_wav_data;
|
||||
|
||||
if (wav_str.Position + actual_wav_chunk_size > wav_end)
|
||||
{
|
||||
flags = 0;
|
||||
actual_wav_chunk_size = (int)(wav_end - wav_str.Position);
|
||||
this_chunk_max = actual_wav_chunk_size + 14;
|
||||
actual_data_chunk_size = actual_wav_chunk_size;
|
||||
}
|
||||
|
||||
WriteMxChHeader(out_stream, this_chunk_max, flags, wav_id, millis, actual_data_chunk_size);
|
||||
|
||||
byte[] wav_bytes = new byte[actual_wav_chunk_size];
|
||||
wav_str.Read(wav_bytes, 0, actual_wav_chunk_size);
|
||||
out_stream.Write(wav_bytes, 0, actual_wav_chunk_size);
|
||||
|
||||
// If we had to split this chunk in half, write the second half now
|
||||
if (flags == 16)
|
||||
{
|
||||
int remaining_wav_data = max_wav_data - actual_wav_chunk_size;
|
||||
|
||||
while (remaining_wav_data > 0)
|
||||
{
|
||||
int true_max_chunk_size = Math.Min(remaining_wav_data + 22, si_buffer_size);
|
||||
int true_wav_data_size = true_max_chunk_size - 22;
|
||||
|
||||
WriteMxChHeader(out_stream, true_max_chunk_size - 8, flags, wav_id, millis, true_wav_data_size);
|
||||
|
||||
byte[] joining_wav_bytes = new byte[true_wav_data_size];
|
||||
wav_str.Read(joining_wav_bytes, 0, true_wav_data_size);
|
||||
out_stream.Write(joining_wav_bytes, 0, true_wav_data_size);
|
||||
|
||||
remaining_wav_data -= true_wav_data_size;
|
||||
}
|
||||
}
|
||||
|
||||
millis += 1000;
|
||||
|
||||
// If we have FLC chunks
|
||||
/*
|
||||
if (flc_id != -1 && wav_str.Position < wav_end)
|
||||
{
|
||||
// Write 10 FLC chunks
|
||||
for (int i=0;i<10;i++)
|
||||
{
|
||||
int flc_data_index = ids.IndexOf(flc_id);
|
||||
int flc_write_ind = (flc_write_count*2) % data[flc_data_index].Count;
|
||||
|
||||
//if (flc_write_ind >= data[flc_data_index].Count)
|
||||
//{
|
||||
//break;
|
||||
//}
|
||||
|
||||
long remainder = si_buffer_size - (out_stream.Position % si_buffer_size);
|
||||
|
||||
if (data[flc_data_index][flc_write_ind].Length > remainder)
|
||||
{
|
||||
WriteZeroes(out_stream, (int)remainder);
|
||||
}
|
||||
|
||||
out_stream.Write(data[flc_data_index][flc_write_ind], 0, data[flc_data_index][flc_write_ind].Length);
|
||||
|
||||
flc_write_count++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(wav_fn + " doesn't exist. Make sure you 'extract' all files from the SI file before trying to 'insert'.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write ending chunk
|
||||
for (int i = ids.Count - 1; i >= 0; i--)
|
||||
{
|
||||
WriteMxChHeader(out_stream, 14, 2, ids[i], millis, 0);
|
||||
}
|
||||
|
||||
// Write correct LIST and MxSt size
|
||||
Int32 list_size = (Int32)(out_stream.Position - list_size_pos - 4);
|
||||
Int32 mxst_size = (Int32)(out_stream.Position - mxst_length_position - 4);
|
||||
|
||||
out_stream.Position = list_size_pos;
|
||||
byte[] list_size_bytes = BitConverter.GetBytes(list_size);
|
||||
out_stream.Write(list_size_bytes, 0, list_size_bytes.Length);
|
||||
|
||||
out_stream.Position = mxst_length_position;
|
||||
list_size_bytes = BitConverter.GetBytes(mxst_size);
|
||||
out_stream.Write(list_size_bytes, 0, list_size_bytes.Length);
|
||||
|
||||
in_stream.Position = end_list_pos;
|
||||
out_stream.Position = out_stream.Length;
|
||||
}
|
||||
|
||||
// Correct RIFF size
|
||||
out_stream.Position = 4;
|
||||
byte[] size_bytes = BitConverter.GetBytes((Int32)(out_stream.Length - 8));
|
||||
out_stream.Write(size_bytes, 0, size_bytes.Length);
|
||||
|
||||
// Correct first LIST size
|
||||
out_stream.Position = 304;
|
||||
size_bytes = BitConverter.GetBytes((Int32)(out_stream.Length - 308));
|
||||
out_stream.Write(size_bytes, 0, size_bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public int ReplaceCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < filenames.Count; i++)
|
||||
{
|
||||
if (table.Rows[i].Cells[1].Value.ToString() != filenames[i])
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,13 +26,23 @@ namespace Rebuilder
|
|||
Button run_button;
|
||||
CheckBox advanced_button;
|
||||
|
||||
MusicInjector music_injector = new MusicInjector();
|
||||
Button music_replacement_btn = new Button();
|
||||
|
||||
Process p = null;
|
||||
|
||||
string run_button_run = "Run";
|
||||
string run_button_kill = "Kill";
|
||||
|
||||
public static string[] standard_hdd_dirs = {
|
||||
"C:/Program Files (x86)/LEGO Island",
|
||||
"C:/Program Files/LEGO Island",
|
||||
"/Program Files (x86)/LEGO Island",
|
||||
"/Program Files/LEGO Island"
|
||||
};
|
||||
|
||||
Rebuilder() {
|
||||
Text = "Lego Island Rebuilder";
|
||||
Text = "LEGO Island Rebuilder";
|
||||
MaximizeBox = false;
|
||||
Icon = Icon.ExtractAssociatedIcon(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
|
@ -55,7 +65,7 @@ namespace Rebuilder
|
|||
|
||||
Label title = new Label();
|
||||
title.Anchor = AnchorStyles.Left | AnchorStyles.Right;
|
||||
title.Text = "Lego Island Rebuilder";
|
||||
title.Text = "LEGO Island Rebuilder";
|
||||
title.Font = new Font(title.Font, FontStyle.Bold);
|
||||
title.TextAlign = ContentAlignment.MiddleCenter;
|
||||
grid.Controls.Add(title, 0, row);
|
||||
|
@ -67,7 +77,7 @@ namespace Rebuilder
|
|||
subtitle.Anchor = AnchorStyles.Left | AnchorStyles.Right;
|
||||
subtitle.Text = "by MattKC (itsmattkc.com)";
|
||||
subtitle.TextAlign = ContentAlignment.MiddleCenter;
|
||||
subtitle.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(AuthorLinkClick);
|
||||
subtitle.LinkClicked += new LinkLabelLinkClickedEventHandler(AuthorLinkClick);
|
||||
grid.Controls.Add(subtitle, 0, row);
|
||||
grid.SetColumnSpan(subtitle, 2);
|
||||
|
||||
|
@ -101,6 +111,18 @@ namespace Rebuilder
|
|||
|
||||
row++;
|
||||
|
||||
Label music_replacement_lbl = new Label();
|
||||
music_replacement_lbl.Text = "Music Injection:";
|
||||
music_replacement_lbl.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;
|
||||
grid.Controls.Add(music_replacement_lbl, 0, row);
|
||||
|
||||
music_replacement_btn.Anchor = AnchorStyles.Left | AnchorStyles.Right;
|
||||
UpdateMusicInjectorBtnText();
|
||||
music_replacement_btn.Click += new EventHandler(this.ShowMusicInjectorForm);
|
||||
grid.Controls.Add(music_replacement_btn, 1, row);
|
||||
|
||||
row++;
|
||||
|
||||
run_fullscreen = new CheckBox();
|
||||
run_fullscreen.Checked = true;
|
||||
run_fullscreen.Anchor = AnchorStyles.Left | AnchorStyles.Right;
|
||||
|
@ -212,19 +234,19 @@ namespace Rebuilder
|
|||
|
||||
// Set up tooltips
|
||||
ToolTip tip = new ToolTip();
|
||||
tip.SetToolTip(turn_speed_control, "Set the turn speed multiplier. Lego Island ties its turn speed to the frame rate which is too fast on modern PCs. Use this value to correct it.\n\n" +
|
||||
tip.SetToolTip(turn_speed_control, "Set the turn speed multiplier. LEGO Island ties its turn speed to the frame rate which is too fast on modern PCs. Use this value to correct it.\n\n" +
|
||||
"0.00 = No turning at all\n" +
|
||||
"0.35 = Recommended for modern PCs\n" +
|
||||
"1.00 = Lego Island's default");
|
||||
"1.00 = LEGO Island's default");
|
||||
tip.SetToolTip(movement_speed_control, "Set the movement speed multiplier. This value does not affect other racers so it can be used to cheat (or cripple) your chances in races.\n\n" +
|
||||
"0.00 = No movement at all\n" +
|
||||
"1.00 = Lego Island's default");
|
||||
tip.SetToolTip(run_fullscreen, "Override the registry check and run Lego Island either full screen or windowed. " +
|
||||
"1.00 = LEGO Island's default");
|
||||
tip.SetToolTip(run_fullscreen, "Override the registry check and run LEGO Island either full screen or windowed. " +
|
||||
"Allows you to change modes without administrator privileges and registry editing.");
|
||||
tip.SetToolTip(redirect_saves, "Redirect save data to a folder that's writable so games can be saved without administrator privileges.\n\n" +
|
||||
"Saves will be stored in: " + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\LEGO Island");
|
||||
tip.SetToolTip(stay_active_when_window_is_defocused, "Lego Island's default behavior is to pause all operations when defocused. " +
|
||||
"This setting overrides that behavior and keeps Lego Island active even when unfocused.\n\n" +
|
||||
tip.SetToolTip(stay_active_when_window_is_defocused, "LEGO Island's default behavior is to pause all operations when defocused. " +
|
||||
"This setting overrides that behavior and keeps LEGO Island active even when unfocused.\n\n" +
|
||||
"NOTE: This currently only works in windowed mode.");
|
||||
|
||||
Controls.Add(grid);
|
||||
|
@ -286,7 +308,7 @@ namespace Rebuilder
|
|||
return (MessageBox.Show("The following patches you've chosen are not compatible with this version of LEGO Island:\n\n" + incompatibilities + "\nContinue without them?", "Compatibility", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes);
|
||||
}
|
||||
|
||||
private bool Patch(string dir)
|
||||
private bool Patch(string source_dir, string dir)
|
||||
{
|
||||
string incompatibilities = "";
|
||||
|
||||
|
@ -320,6 +342,33 @@ namespace Rebuilder
|
|||
WriteByte(lego1dll, 0x80, aug_build ? 0xAD7D3 : 0xADD43);
|
||||
}
|
||||
|
||||
// Redirect JUKEBOX.SI if we're inserting music
|
||||
if (music_injector.ReplaceCount() > 0)
|
||||
{
|
||||
Uri uri1 = new Uri(dir + "/jukebox");
|
||||
Uri uri2 = new Uri(source_dir + "/ISLE.EXE");
|
||||
Uri relative = uri2.MakeRelativeUri(uri1);
|
||||
string jukebox_path = "\\" + relative.ToString().Replace("/", "\\");
|
||||
//Console.WriteLine(jukebox_path);
|
||||
|
||||
if (aug_build)
|
||||
{
|
||||
WriteByte(lego1dll, 0xF6, 0x51EF5);
|
||||
WriteByte(lego1dll, 0x34);
|
||||
WriteByte(lego1dll, 0x0D);
|
||||
WriteByte(lego1dll, 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteByte(lego1dll, 0x66, 0x52195);
|
||||
WriteByte(lego1dll, 0x3A);
|
||||
WriteByte(lego1dll, 0x0D);
|
||||
WriteByte(lego1dll, 0x10);
|
||||
}
|
||||
|
||||
WriteString(lego1dll, jukebox_path, aug_build ? 0xD28F6 : 0xD2E66);
|
||||
}
|
||||
|
||||
// INCOMPLETE: Resolution hack:
|
||||
if (override_resolution.Checked)
|
||||
{
|
||||
|
@ -364,6 +413,25 @@ namespace Rebuilder
|
|||
return (File.Exists(dir + "/ISLE.EXE") && File.Exists(dir + "/LEGO1.DLL"));
|
||||
}
|
||||
|
||||
private void ShowMusicInjectorForm(object sender, EventArgs e)
|
||||
{
|
||||
//music_changed = true;
|
||||
music_injector.ShowDialog();
|
||||
UpdateMusicInjectorBtnText();
|
||||
}
|
||||
|
||||
private void UpdateMusicInjectorBtnText()
|
||||
{
|
||||
int count = music_injector.ReplaceCount();
|
||||
string btn_text = count + " song";
|
||||
if (count != 1)
|
||||
{
|
||||
btn_text += "s";
|
||||
}
|
||||
btn_text += " replaced";
|
||||
music_replacement_btn.Text = btn_text;
|
||||
}
|
||||
|
||||
private void ToggleAdvanced(object sender, EventArgs e)
|
||||
{
|
||||
advanced_grid.Visible = advanced_button.Checked;
|
||||
|
@ -403,23 +471,15 @@ namespace Rebuilder
|
|||
return;
|
||||
}
|
||||
|
||||
string temp_path = Path.GetTempPath() + "lirebuild";
|
||||
|
||||
string temp_path = Path.GetTempPath() + "lire";
|
||||
Directory.CreateDirectory(temp_path);
|
||||
|
||||
string[] possible_dirs = {
|
||||
"C:/Program Files (x86)/Lego Island",
|
||||
"C:/Program Files/Lego Island",
|
||||
"/Program Files (x86)/Lego Island",
|
||||
"/Program Files/Lego Island"
|
||||
};
|
||||
|
||||
string dir = "";
|
||||
for (int i=0;i<possible_dirs.Length;i++)
|
||||
for (int i=0;i<standard_hdd_dirs.Length;i++)
|
||||
{
|
||||
if (IsValidDir(possible_dirs[i]))
|
||||
if (IsValidDir(standard_hdd_dirs[i]))
|
||||
{
|
||||
dir = possible_dirs[i];
|
||||
dir = standard_hdd_dirs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +489,7 @@ namespace Rebuilder
|
|||
using (OpenFileDialog ofd = new OpenFileDialog())
|
||||
{
|
||||
ofd.Filter = "ISLE.EXE|ISLE.EXE";
|
||||
ofd.Title = "Where is Lego Island installed?";
|
||||
ofd.Title = "Where is LEGO Island installed?";
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -479,13 +539,19 @@ namespace Rebuilder
|
|||
return;
|
||||
}
|
||||
|
||||
if (!Patch(temp_path)) return;
|
||||
if (!Patch(dir, temp_path)) return;
|
||||
|
||||
// Perform music insertion if necessary
|
||||
if (music_injector.ReplaceCount() > 0)
|
||||
{
|
||||
music_injector.Insert(temp_path + "/JUKEBOX.SI");
|
||||
}
|
||||
|
||||
// Set new EXE's compatibility mode to 256-colors
|
||||
using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", true))
|
||||
{
|
||||
key.CreateSubKey(temp_path + "\\ISLE.EXE");
|
||||
|
||||
|
||||
if (run_fullscreen.Checked)
|
||||
{
|
||||
key.SetValue(temp_path + "\\ISLE.EXE", "HIGHDPIAWARE DWM8And16BitMitigation");
|
||||
|
@ -520,9 +586,8 @@ namespace Rebuilder
|
|||
p = null;
|
||||
}
|
||||
|
||||
private void AuthorLinkClick(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
|
||||
private void AuthorLinkClick(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
((LinkLabel)sender).LinkVisited = true;
|
||||
Process.Start("http://www.itsmattkc.com/");
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MusicInjector.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Rebuilder.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
|
Loading…
Reference in a new issue