Fix demo compatibility (#494)
* Fix demo compatibility
Regression introduced in 81116169cf
* Decode gDecode_string (use macro's to show its definition)
* Fix IWANTTOFIDDLE cheat for demo
* Add demo support to tools/decode_datatxt.py
This commit is contained in:
parent
9c82a405bd
commit
12a48ffddf
|
|
@ -140,8 +140,25 @@ int gAllow_open_to_fail = 1;
|
|||
// GLOBAL: CARM95 0x0050a5c8
|
||||
int gDecode_thing = '@';
|
||||
|
||||
#define DECODE_STRING_SECRET 50
|
||||
|
||||
// GLOBAL: CARM95 0x0050a5d0
|
||||
char gDecode_string[] = { 0x9B, 0x52, 0x93, 0x9F, 0x52, 0x98, 0x9B, 0x96, 0x96, 0x9E, 0x9B, 0xA0, 0x99, 0x0 };
|
||||
char gDecode_string[] = {
|
||||
'i' + DECODE_STRING_SECRET,
|
||||
' ' + DECODE_STRING_SECRET,
|
||||
'a' + DECODE_STRING_SECRET,
|
||||
'm' + DECODE_STRING_SECRET,
|
||||
' ' + DECODE_STRING_SECRET,
|
||||
'f' + DECODE_STRING_SECRET,
|
||||
'i' + DECODE_STRING_SECRET,
|
||||
'd' + DECODE_STRING_SECRET,
|
||||
'd' + DECODE_STRING_SECRET,
|
||||
'l' + DECODE_STRING_SECRET,
|
||||
'i' + DECODE_STRING_SECRET,
|
||||
'n' + DECODE_STRING_SECRET,
|
||||
'g' + DECODE_STRING_SECRET,
|
||||
'\0'
|
||||
};
|
||||
|
||||
// GLOBAL: CARM95 0x00531f00
|
||||
int gFunk_groove_flags[30];
|
||||
|
|
@ -400,7 +417,7 @@ void LoadGeneralParameters(void) {
|
|||
fgets(s, sizeof(s) - 1, f);
|
||||
fclose(f);
|
||||
for (i = 0; i < strlen(gDecode_string); i++) {
|
||||
gDecode_string[i] -= 50;
|
||||
gDecode_string[i] -= DECODE_STRING_SECRET;
|
||||
}
|
||||
|
||||
// trim trailing CRLF etc
|
||||
|
|
@ -413,7 +430,7 @@ void LoadGeneralParameters(void) {
|
|||
}
|
||||
|
||||
for (i = 0; i < strlen(gDecode_string); i++) {
|
||||
gDecode_string[i] += 50;
|
||||
gDecode_string[i] += DECODE_STRING_SECRET;
|
||||
}
|
||||
}
|
||||
PathCat(the_path, gApplication_path, "GENERAL.TXT");
|
||||
|
|
|
|||
|
|
@ -1595,7 +1595,7 @@ void SelectRaceDraw(int pCurrent_choice, int pCurrent_mode) {
|
|||
fputs("*************", f);
|
||||
}
|
||||
}
|
||||
gDecode_thing ^= 0x40u;
|
||||
gDecode_thing ^= '@';
|
||||
fclose(f);
|
||||
EncodeAllFilesInDirectory("");
|
||||
EncodeAllFilesInDirectory("CARS");
|
||||
|
|
|
|||
|
|
@ -98,6 +98,14 @@ void EncodeLine(char* pS) {
|
|||
FILE* test;
|
||||
unsigned char c;
|
||||
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
// Demo has its own decryption key + behavior
|
||||
if (harness_game_info.mode == eGame_carmageddon_demo) {
|
||||
EncodeLine_DEMO(pS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
key = (char*)gLong_key;
|
||||
if (gEncryption_method == 0) {
|
||||
|
|
@ -1441,6 +1449,14 @@ void DecodeLine2(char* pS) {
|
|||
unsigned char c;
|
||||
char* key;
|
||||
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
// Demo has its own decryption key + behavior
|
||||
if (harness_game_info.mode == eGame_carmageddon_demo) {
|
||||
DecodeLine2_DEMO(pS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
key = (char*)gLong_key;
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
|
|
@ -1494,6 +1510,14 @@ void EncodeLine2(char* pS) {
|
|||
unsigned char c;
|
||||
char* key;
|
||||
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
// Demo has its own decryption key + behavior
|
||||
if (harness_game_info.mode == eGame_carmageddon_demo) {
|
||||
EncodeLine2_DEMO(pS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
count = 0;
|
||||
key = (char*)gLong_key;
|
||||
|
|
@ -1913,3 +1937,48 @@ void EncodeLine_DEMO(char* pS) {
|
|||
pS[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeLine2_DEMO(char* pS) {
|
||||
int len;
|
||||
int seed;
|
||||
int i;
|
||||
const char* key;
|
||||
unsigned char c;
|
||||
#if BR_ENDIAN_BIG
|
||||
const tU32 gLong_key_DEMO[] = { 0x58503A76, 0xCBB68565, 0x15CD5B07, 0xB168DE3A };
|
||||
#else
|
||||
const tU32 gLong_key_DEMO[] = { 0x763A5058, 0x6585B6CB, 0x75BCD15, 0x3ADE68B1 };
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
key = (char*)gLong_key_DEMO;
|
||||
|
||||
while (len != 0 && (pS[len - 1] == '\r' || pS[len - 1] == '\n')) {
|
||||
pS[len - 1] = 0;
|
||||
len--;
|
||||
}
|
||||
seed = len % 16;
|
||||
for (i = 0; i < len; i++) {
|
||||
c = pS[i];
|
||||
if (c == '\t') {
|
||||
c = 0x9F;
|
||||
}
|
||||
|
||||
c -= 32;
|
||||
c ^= key[seed];
|
||||
c &= 0x7f;
|
||||
c += 32;
|
||||
if (c == 0x9F) {
|
||||
c = '\t';
|
||||
}
|
||||
if (c == '\n' || c == '\r') {
|
||||
c |= 0x80;
|
||||
}
|
||||
seed = (seed + 7) % 16;
|
||||
pS[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeLine2_DEMO(char* pS) {
|
||||
EncodeLine_DEMO(pS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,4 +186,10 @@ void BlendifyMaterialPrimitively(br_material* pMaterial, int pPercent);
|
|||
|
||||
void BlendifyMaterial(br_material* pMaterial, int pPercent);
|
||||
|
||||
void EncodeLine_DEMO(char* pS);
|
||||
|
||||
void EncodeLine2_DEMO(char* pS);
|
||||
|
||||
void DecodeLine2_DEMO(char* pS);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import enum
|
||||
import sys
|
||||
|
||||
LONG_KEY = (
|
||||
|
|
@ -11,7 +12,15 @@ OTHER_LONG_KEY = (
|
|||
0x67, 0xa8, 0xd6, 0x26, 0xb6, 0xdd, 0x45, 0x1b,
|
||||
0x32, 0x7e, 0x22, 0x13, 0x15, 0xc2, 0x94, 0x37,
|
||||
)
|
||||
DEMO_KEY = (
|
||||
0x58, 0x50, 0x3A, 0x76, 0xCB, 0xB6, 0x85, 0x65,
|
||||
0x15, 0xCD, 0x5B, 0x07, 0xB1, 0x68, 0xDE, 0x3A,
|
||||
)
|
||||
|
||||
class Method(enum.Enum):
|
||||
Method1 = "1"
|
||||
Method2 = "2"
|
||||
Demo = "demo"
|
||||
|
||||
class Byte:
|
||||
def __init__(self, v: int):
|
||||
|
|
@ -52,6 +61,13 @@ class Byte:
|
|||
self.v = (self.v & v) & 0xff
|
||||
return self
|
||||
|
||||
def __or__(self, v: int):
|
||||
return Byte(self.v | v)
|
||||
|
||||
def __ior__(self, v: int):
|
||||
self.v = (self.v | v) & 0xff
|
||||
return self
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Byte):
|
||||
return self.v == other.v
|
||||
|
|
@ -63,61 +79,20 @@ class Byte:
|
|||
return f"(byte 0x{self.v:02x})"
|
||||
|
||||
|
||||
def decode_line(line: bytes, method: int) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
if dline[i - 2:i] == b'//':
|
||||
key = OTHER_LONG_KEY
|
||||
if method == 1:
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord(b'\t'))
|
||||
else:
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x80)
|
||||
|
||||
b -= 0x20
|
||||
if (b & 0x80) == 0:
|
||||
b ^= key[seed] & 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x80:
|
||||
b = Byte(ord(b'\t'))
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
def encode_line(line: bytes, method: int) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
count = 0
|
||||
eline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
if count == 2:
|
||||
key = OTHER_LONG_KEY
|
||||
if c == ord('/'):
|
||||
count += 1
|
||||
else:
|
||||
count = 0
|
||||
if method == 1:
|
||||
class Codec1:
|
||||
def encode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
count = 0
|
||||
eline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
if count == 2:
|
||||
key = OTHER_LONG_KEY
|
||||
if c == ord('/'):
|
||||
count += 1
|
||||
else:
|
||||
count = 0
|
||||
if c == ord('\t'):
|
||||
c = 0x9f
|
||||
|
||||
|
|
@ -132,7 +107,51 @@ def encode_line(line: bytes, method: int) -> bytes:
|
|||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord('\t'))
|
||||
else:
|
||||
eline[i] = b.v
|
||||
return bytes(eline)
|
||||
|
||||
def decode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
if dline[i - 2:i] == b'//':
|
||||
key = OTHER_LONG_KEY
|
||||
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord(b'\t'))
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
class Codec2:
|
||||
def encode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
count = 0
|
||||
eline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
if count == 2:
|
||||
key = OTHER_LONG_KEY
|
||||
if c == ord('/'):
|
||||
count += 1
|
||||
else:
|
||||
count = 0
|
||||
|
||||
if c == ord('\t'):
|
||||
c = 0x80
|
||||
b = Byte(c - 0x20)
|
||||
|
|
@ -145,24 +164,116 @@ def encode_line(line: bytes, method: int) -> bytes:
|
|||
|
||||
if b == 0x80:
|
||||
b = Byte(ord('\t'))
|
||||
eline[i] = b.v
|
||||
return bytes(eline)
|
||||
eline[i] = b.v
|
||||
return bytes(eline)
|
||||
|
||||
def decode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
if dline[i - 2:i] == b'//':
|
||||
key = OTHER_LONG_KEY
|
||||
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x80)
|
||||
|
||||
b -= 0x20
|
||||
if (b & 0x80) == 0:
|
||||
b ^= key[seed] & 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x80:
|
||||
b = Byte(ord(b'\t'))
|
||||
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
class CodecDemo:
|
||||
def encode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = DEMO_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
|
||||
if b == ord('\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
if b == 0x9f:
|
||||
b = Byte(ord('\t'))
|
||||
if b == ord('\n') or b == ord('\r'):
|
||||
b |= 0x80
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
def decode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = DEMO_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
|
||||
if b == ord('\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord('\t'))
|
||||
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
CODECS = {
|
||||
Method.Method1: Codec1,
|
||||
Method.Method2: Codec2,
|
||||
Method.Demo: CodecDemo,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
method_choices = tuple(e.value for e in Method.__members__.values())
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False, description="Decode/encode a Carmageddon text file")
|
||||
parser.add_argument("file", metavar="FILE", nargs="?", help="input file (default=stdin)")
|
||||
parser.add_argument("--method", choices=[1, 2], type=int, default=2, help="encryption method to use (default=2)")
|
||||
parser.add_argument("--method", choices=method_choices, default=Method.Method2.value,
|
||||
help=f"encryption method to use (default={Method.Method2.value}, choices={','.join(method_choices)})")
|
||||
args = parser.parse_args()
|
||||
|
||||
method = Method(args.method)
|
||||
codec = CODECS[method]()
|
||||
|
||||
istream = open(args.file, "rb") if args.file else sys.stdin.buffer
|
||||
|
||||
for line in istream.readlines():
|
||||
if line[0] == ord(b'@'):
|
||||
dline = decode_line(line[1:], args.method)
|
||||
if line[0] == ord(b"@"):
|
||||
dline = codec.decode_line(line[1:])
|
||||
sys.stdout.buffer.write(dline)
|
||||
else:
|
||||
eline = b"@" + encode_line(line, args.method)
|
||||
eline = b"@" + codec.encode_line(line)
|
||||
sys.stdout.buffer.write(eline)
|
||||
sys.stdout.buffer.write(b'\n')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue