View difference between Paste ID: rEupJiAX and eSxBWXyc
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();