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(); |