SHOW:
|
|
- or go back to the newest paste.
| 1 | #!/usr/bin/perl | |
| 2 | use strict; | |
| 3 | use warnings; | |
| 4 | ||
| 5 | sub main {
| |
| 6 | my @buf = read_game_file("GAME1");
| |
| 7 | my @decrypt = decrypt_msq(\@buf, 0x253c5, 0x800); | |
| 8 | save_char("characters.orig", @decrypt);
| |
| 9 | #Modify Characters | |
| 10 | # See end of file for valid parameters | |
| 11 | my $skills = [ | |
| 12 | { #1
| |
| 13 | "Brawling" => 2, | |
| 14 | "Climb" => 1, | |
| 15 | "Swim" => 1, | |
| 16 | "Perception" => 1, | |
| 17 | "Assault Rifle" => 2, | |
| 18 | "AT Weapon" => 1, | |
| 19 | "Acrobat" => 1, | |
| 20 | ## | |
| 21 | "Picklock" => 1, | |
| 22 | "Silent Move" => 1, | |
| 23 | "Demolitions" => 1, | |
| 24 | "Safecrack" => 1, | |
| 25 | "Medic" => 1, | |
| 26 | }, | |
| 27 | { #2
| |
| 28 | "Brawling" => 2, | |
| 29 | "Climb" => 1, | |
| 30 | "Swim" => 1, | |
| 31 | "Perception" => 1, | |
| 32 | "Assault Rifle" => 2, | |
| 33 | "AT Weapon" => 1, | |
| 34 | "Acrobat" => 1, | |
| 35 | ## | |
| 36 | "Combat Shooting" => 1, | |
| 37 | "Bureaucracy" => 1, | |
| 38 | "Medic"=> 1, | |
| 39 | "Cryptology" => 1, | |
| 40 | }, | |
| 41 | { #3
| |
| 42 | "Brawling" => 2, | |
| 43 | "Climb" => 1, | |
| 44 | "Swim" => 1, | |
| 45 | "Perception" => 1, | |
| 46 | "Assault Rifle" => 2, | |
| 47 | "AT Weapon" => 1, | |
| 48 | "Acrobat" => 1, | |
| 49 | ## | |
| 50 | "Combat Shooting" => 1, | |
| 51 | "Bomb disarm" => 2, | |
| 52 | }, | |
| 53 | { #4
| |
| 54 | "Brawling" => 2, | |
| 55 | "Climb" => 1, | |
| 56 | "Swim" => 1, | |
| 57 | "Perception" => 1, | |
| 58 | "Assault Rifle" => 2, | |
| 59 | "AT Weapon" => 1, | |
| 60 | "Acrobat" => 1, | |
| 61 | ## | |
| 62 | "Combat Shooting" => 1, | |
| 63 | "Medic" => 1, | |
| 64 | "Metallurgy" => 1, | |
| 65 | } | |
| 66 | ]; | |
| 67 | my $attrs = [ | |
| 68 | { #1
| |
| 69 | - | lck => 17, |
| 69 | + | |
| 70 | }, | |
| 71 | { #2
| |
| 72 | skillpt => 1, | |
| 73 | }, | |
| 74 | { #3
| |
| 75 | skillpt => 0, | |
| 76 | }, | |
| 77 | { #4
| |
| 78 | skillpt => 2, | |
| 79 | - | dex => 16, |
| 79 | + | |
| 80 | ]; | |
| 81 | hack_characters(\@decrypt, $skills, $attrs); | |
| 82 | save_char("characters.new", @decrypt);
| |
| 83 | encrypt_msq(\@buf, 0x253c5, @decrypt); | |
| 84 | save_game_file("GAME1.new", \@buf);
| |
| 85 | } | |
| 86 | ||
| 87 | my %skills; | |
| 88 | my %attributes; | |
| 89 | sub read_game_file {
| |
| 90 | my($file) = @_; | |
| 91 | open my $fh, "<", $file or die "ERROR: Couldn't open $file\n"; | |
| 92 | my $buffer; | |
| 93 | read($fh, $buffer, 99999999); | |
| 94 | my @buf = map {ord($_)} split(//, $buffer);
| |
| 95 | return @buf; | |
| 96 | } | |
| 97 | ||
| 98 | #decrypt; | |
| 99 | sub decrypt_msq {
| |
| 100 | my($buf, $offset, $length) = @_; | |
| 101 | my $b1 = $buf->[$offset+4]; | |
| 102 | my $b2 = $buf->[$offset+5]; | |
| 103 | my $chksum= 0; | |
| 104 | my $enc = $b1 ^ $b2; | |
| 105 | #printf "%02x ^ %02x ==> %02x\n", $b1,$b2,$enc; | |
| 106 | my $pos = 6; | |
| 107 | my @encrypt; | |
| 108 | my @decrypt; | |
| 109 | while($pos < $length + 6) {
| |
| 110 | push @encrypt, $buf->[$offset+$pos]; | |
| 111 | my $newb = $buf->[$offset+$pos] ^ $enc; | |
| 112 | #printf("%04d %02x %04x %02x => %02x\n", $pos, $enc, $chksum, $buf->[$offset+$pos], $newb);
| |
| 113 | $chksum = ($chksum - $newb) & 0xffff; | |
| 114 | $enc = ($enc + 0x1f) & 0xff; | |
| 115 | $pos++; | |
| 116 | push @decrypt, $newb; | |
| 117 | #print chr($newb); | |
| 118 | } | |
| 119 | printf STDERR "Checksum: %04x <> %04x\n", ($b2 << 8) | $b1, $chksum; | |
| 120 | #for $i (0 .. 5) {
| |
| 121 | # print chr($buf->[$offset+$i]); | |
| 122 | #} | |
| 123 | #map {print chr($_)} @decrypt;
| |
| 124 | return @decrypt; | |
| 125 | } | |
| 126 | ||
| 127 | sub save_char {
| |
| 128 | my($file, @data) = @_; | |
| 129 | #Save decrypted character data | |
| 130 | open my $fh, ">", $file or die "ERROR: Couldn't write $file\n"; | |
| 131 | map {print $fh chr($_)} @data;
| |
| 132 | close $fh; | |
| 133 | } | |
| 134 | ||
| 135 | sub hack_characters {
| |
| 136 | my($data, $ch_skills, $ch_attrs) = @_; | |
| 137 | for my $ch (0 .. 3) {
| |
| 138 | my $pos = 0x100 * $ch + 0x100; | |
| 139 | my $ref = $ch_attrs->[$ch]; | |
| 140 | foreach (keys %$ref) {
| |
| 141 | die "ERROR: Couldn't find attr $_\n" if(! exists $attributes{$_});
| |
| 142 | $data->[$pos + $attributes{$_}] = $ref->{$_};
| |
| 143 | } | |
| 144 | ||
| 145 | my $skill_pos = 0x80; | |
| 146 | $ref = $ch_skills->[$ch]; | |
| 147 | foreach (keys %$ref) {
| |
| 148 | die "ERROR: Couldn't find skill $_\n" if(! exists $skills{$_});
| |
| 149 | $data->[$pos + $skill_pos++] = $skills{$_};
| |
| 150 | $data->[$pos + $skill_pos++] = $ref->{$_};
| |
| 151 | } | |
| 152 | while($skill_pos != 0xbc) {
| |
| 153 | $data->[$pos + $skill_pos++] = 0; | |
| 154 | } | |
| 155 | } | |
| 156 | } | |
| 157 | ||
| 158 | sub encrypt_msq {
| |
| 159 | my($buf, $offset, @decrypt) = @_; | |
| 160 | my $chksum = 0; | |
| 161 | for (@decrypt) {
| |
| 162 | $chksum = ($chksum - $_) & 0xffff; | |
| 163 | } | |
| 164 | my $b1 = $chksum & 0xff; | |
| 165 | my $b2 = $chksum >> 8; | |
| 166 | my $enc = $b1 ^ $b2; | |
| 167 | for (@decrypt) {
| |
| 168 | $_ = $_ ^ $enc; | |
| 169 | $enc = ($enc + 0x1f) & 0xff; | |
| 170 | } | |
| 171 | $buf->[$offset+4] = $b1; | |
| 172 | $buf->[$offset+5] = $b2; | |
| 173 | my $pos = 6; | |
| 174 | foreach (@decrypt) {
| |
| 175 | $buf->[$offset+$pos] = $_; | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 179 | sub save_game_file {
| |
| 180 | my($file, $buf) = @_; | |
| 181 | open my $fh, ">", $file or die "ERROR: Couldn't write $file\n"; | |
| 182 | map {print $fh chr($_)} @$buf;
| |
| 183 | close $fh; | |
| 184 | } | |
| 185 | ||
| 186 | %attributes = ( | |
| 187 | str => 0x0e, | |
| 188 | iq => 0x0f, | |
| 189 | lck => 0x10, | |
| 190 | spd => 0x11, | |
| 191 | agl => 0x12, | |
| 192 | dex => 0x13, | |
| 193 | cha => 0x14, | |
| 194 | skillpt => 0x20, | |
| 195 | ); | |
| 196 | my %skill_id = ( | |
| 197 | 0x01 => "Brawling", | |
| 198 | 0x02 => "Climb", | |
| 199 | 0x03 => "Clip Pistol", | |
| 200 | 0x04 => "Knife Fight", | |
| 201 | 0x05 => "Pugilism", | |
| 202 | 0x06 => "Rifle", | |
| 203 | 0x07 => "Swim", | |
| 204 | 0x08 => "Knife Throw", | |
| 205 | 0x09 => "Perception", | |
| 206 | 0x0A => "Assault Rifle", | |
| 207 | 0x0B => "AT Weapon", | |
| 208 | 0x0C => "SMG", | |
| 209 | 0x0D => "Acrobat", | |
| 210 | 0x0E => "Gambling", | |
| 211 | 0x0F => "Picklock", | |
| 212 | 0x10 => "Silent Move", | |
| 213 | 0x11 => "Combat Shooting", | |
| 214 | 0x12 => "Confidence", | |
| 215 | 0x13 => "Sleight of Hand", | |
| 216 | 0x14 => "Demolitions", | |
| 217 | 0x15 => "Forgery", | |
| 218 | 0x16 => "Alarm Disarm", | |
| 219 | 0x17 => "Bureaucracy", | |
| 220 | 0x18 => "Bomb disarm", | |
| 221 | 0x19 => "Medic", | |
| 222 | 0x1A => "Safecrack", | |
| 223 | 0x1B => "Cryptology", | |
| 224 | 0x1C => "Metallurgy", | |
| 225 | 0x1D => "Helicopter pilot", | |
| 226 | 0x1E => "Electronics", | |
| 227 | 0x1F => "Toaster repair", | |
| 228 | 0x20 => "Doctor", | |
| 229 | 0x21 => "Clone tech", | |
| 230 | 0x22 => "Energy weapon", | |
| 231 | 0x23 => "Cyborg tech", | |
| 232 | ); | |
| 233 | foreach (keys %skill_id) {
| |
| 234 | $skills{$skill_id{$_}} = $_;
| |
| 235 | } | |
| 236 | ||
| 237 | main(); |