Итак,
все ресурсы, включая спрайты юнитов, извлечены из рома. Графика в основном сжатая.
Чтобы её изменять и вставлять в ром нужен нормальный запаковщик.
Анпакер Марата сжимает не все архивы.
Нужно сделать новый желательно с поддержкой массового анпака.
Покопавшись на форуме "Шедевра", нашёл исходники упаковки/распаковки:
В туториалке используется дважды упакованная карта тайлов. Сначала используется "свой" алгоритм, а потом общий.
После двух распаковок у тебя должен получиться набор "экранов".
Распаковка "обычная".
.386
.model flat
public unpack
public mod_name
.data
modstring db "Dune: The Battle for Arrakis",0
.data?
out_buf dd ?
in_buf dd ?
opt dd ?
read_len dd ?
.code
_start@12:
mov al,1
ret 12
;int unpack(char* pIn, char* pOut, int option, int* rLen);
unpack proc
pop eax
pop in_buf
pop out_buf
pop opt
pop read_len
push eax
push ebx
push ebp
push esi
push edi
mov ebx,in_buf
mov edi,out_buf
main_loop:
xor ecx,ecx
xor edx,edx
mov cl,byte ptr [ebx]
inc ebx
cmp cl,0
jns cl_positive
test cl,40h
jz sixth_bit_clear
cmp cl,-2
je cl_eq_FE
cmp cl,-1
je cl_eq_FF
and cl,3Fh
mov dx,word ptr [ebx]
add ebx,2
add cx,3
mov esi,out_buf
add esi,edx
jmp loc_0_C96
cl_eq_FF:
mov cx,word ptr [ebx]
mov dx,word ptr [ebx+2]
add ebx,4
mov esi,out_buf
add esi,edx
jmp loc_0_C96
cl_positive:
mov dh,cl
mov dl,byte ptr [ebx]
and dx,0FFFh
inc ebx
shr cx,4
add cx,3
mov esi,edi
sub esi,edx
loc_0_C96:
rep movsb
jmp main_loop
sixth_bit_clear:
cmp cl,80h
je exit_sub
and cl,3Fh
mov esi,ebx
add ebx,ecx
jmp loc_0_C96
cl_eq_FE:
mov cx,word ptr [ebx]
mov al,byte ptr [ebx+2]
add ebx,3
rep stosb
jmp main_loop
exit_sub:
sub ebx,in_buf
mov ebp,read_len
mov [ebp],ebx
mov eax,edi
sub eax,out_buf
pop edi
pop esi
pop ebp
pop ebx
ret
unpack endp
mod_name proc
mov eax,offset modstring
ret
mod_name endp
end _start@12
Распаковка для туториала
.386
.model flat
public unpack
public mod_name
.data
modstring db "Dune Tutorial Text",0
.data?
out_buf dd ?
in_buf dd ?
opt dd ?
read_len dd ?
out_buf2 dd ?
in_buf2 dd ?
opt2 dd ?
read_len2 dd ?
buf_temp dd 20000h dup(?)
.code
_start@12:
mov al,1
ret 12
;int unpack(char* pIn, char* pOut, int option, int* rLen);
unpack proc
pop eax
pop in_buf
pop out_buf
pop opt
pop read_len
push eax
push ebx
push ebp
push esi
push edi
;---------------------------------------
push read_len
push 0
push offset buf_temp
push in_buf
call preprocess
;---------------------------------------
mov esi,offset buf_temp
mov edi,out_buf
xor eax,eax
lodsw
begin:
cmp ax,-1
jz exit
xchg ah,al
mov bx,ax
mmain_loop:
xor ecx,ecx
mov cl,[esi]
inc esi
cmp cl,80h
jz cl_eq_80
jns cl_gt_80
sub bx,2
lodsw
rep stosw
jmp next_screen
cl_gt_80:
and cl,7Fh
sub bx,cx
sub bx,cx
rep movsw
jmp next_screen
cl_eq_80:
xor eax,eax
lodsb
shl ax,1
mov cx,ax
push esi
mov esi,edi
sub esi,8C0h
rep movsb
pop esi
dec bx
next_screen:
dec bx
jnz mmain_loop
lodsw
cmp ax,-1
jnz begin
exit:
mov eax,edi
sub eax,out_buf
pop edi
pop esi
pop ebp
pop ebx
ret
unpack endp
;int preprocess(char* pIn, char* pOut, int option, int* rLen);
preprocess proc
pop eax
pop in_buf2
pop out_buf2
pop opt2
pop read_len2
push eax
push ebx
push ebp
push esi
push edi
mov ebx,in_buf2
mov edi,out_buf2
main_loop:
xor ecx,ecx
xor edx,edx
mov cl,byte ptr [ebx]
inc ebx
cmp cl,0
jns cl_positive
test cl,40h
jz sixth_bit_clear
cmp cl,-2
je cl_eq_FE
cmp cl,-1
je cl_eq_FF
and cl,3Fh
mov dx,word ptr [ebx]
add ebx,2
add cx,3
mov esi,out_buf2
add esi,edx
jmp loc_0_C96
cl_eq_FF:
mov cx,word ptr [ebx]
mov dx,word ptr [ebx+2]
add ebx,4
mov esi,out_buf2
add esi,edx
jmp loc_0_C96
cl_positive:
mov dh,cl
mov dl,byte ptr [ebx]
and dx,0FFFh
inc ebx
shr cx,4
add cx,3
mov esi,edi
sub esi,edx
loc_0_C96:
rep movsb
jmp main_loop
sixth_bit_clear:
cmp cl,80h
je exit_sub
and cl,3Fh
mov esi,ebx
add ebx,ecx
jmp loc_0_C96
cl_eq_FE:
mov cx,word ptr [ebx]
mov al,byte ptr [ebx+2]
add ebx,3
rep stosb
jmp main_loop
exit_sub:
sub ebx,in_buf
mov ebp,read_len2
mov [ebp],ebx
mov eax,edi
sub eax,out_buf2
pop edi
pop esi
pop ebp
pop ebx
ret
preprocess endp
mod_name proc
mov eax,offset modstring
ret
mod_name endp
end _start@12
А это чисто посмеяцца. Упаковка "обычная".
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
char nun[0x3F];
int obytes;
int out;
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE, DWORD, LPVOID)
{
return true;
}
//---------------------------------------------------------------------------
char* __stdcall __export mod_name()
{
return "Dune: The Battle for Arrakis";
}
//---------------------------------------------------------------------------
void Flush(char* pO)
{
if(!obytes) return;
pO[out] = obytes | 0x80;
out++;
for(int j = 0; j < obytes; j++)
pO[out + j] = nun[j];
out += obytes;
obytes = 0;
}
//---------------------------------------------------------------------------
int __stdcall __export pack(char* pIn, char* pOut, int option, int* rLen)
{
int in = 0;
int n;
int n2;
int maxN;
int maxN2;
int maxIn;
int in2;
obytes = 0;
out = 0;
while(in < option)
{
maxN = 0;
maxN2 = 0;
maxIn = 0;
for(in2 = 0; in2 < in; in2++)
{
for(n = 0; pIn[in2 + n] == pIn[in + n] && in + n < option; n++);
if(in - in2 < 0x1000 && n < 0xB) n2 = n - 2;
else if(n < 0x43) n2 = n - 3;
else n2 = n - 5;
if(n2 > maxN2) { maxN2 = n2; maxN = n; maxIn = in2; }
}
for(n = 1; pIn[in + n - 1] == pIn[in + n] && in + n - 1 < option; n++);
n2 = n - 4;
if(n2 > maxN2) { maxN2 = n2; maxN = n; maxIn = in; }
if(maxN2 >= 0 && maxN > 2)
{
if(in == maxIn)
{
Flush(pOut);
pOut[out] = 0xFE;
*(WORD*)(pOut + out + 1) = maxN;
pOut[out + 3] = pIn[in];
out += 4;
in += maxN;
}
else if(in - maxIn < 0x1000 && maxN < 0xB)
{
Flush(pOut);
pOut[out] = (maxN - 3) << 4 | (in - maxIn) >> 8;
pOut[out + 1] = (BYTE)(in - maxIn);
out += 2;
in += maxN;
}
else if(maxN < 0x43)
{
Flush(pOut);
pOut[out] = 0xC0 | (maxN - 3);
*(WORD*)(pOut + out + 1) = maxIn;
out += 3;
in += maxN;
}
else
{
Flush(pOut);
pOut[out] = 0xFF;
*(WORD*)(pOut + out + 1) = maxN;
*(WORD*)(pOut + out + 3) = maxIn;
out += 5;
in += maxN;
}
}
else
{
nun[obytes] = pIn[in];
obytes++;
if(obytes == 0x3F) Flush(pOut);
in++;
}
}
Flush(pOut);
pOut[out] = 0x80;
out++;
*rLen = option;
return out;
}
//---------------------------------------------------------------------------
Упаковка для туториала. Файл первый.
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
USEUNIT("p_dttext2.cpp"); // Тут должно быть имя второго файла
//---------------------------------------------------------------------------
int i;
int n;
int n2;
int in;
int out;
int size;
WORD* locIn;
char* locOut;
WORD nun[0x7F];
int owords;
int final(char* pIn, char* pOut, int option, int* rLen);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE, DWORD, LPVOID)
{
return true;
}
//---------------------------------------------------------------------------
char* __stdcall __export mod_name()
{
return "Dune Tutorial Text";
}
//---------------------------------------------------------------------------
void Flush()
{
if(!owords) return;
locOut[out] = owords | 0x80;
out++;
for(int j = 0; j < owords; j++)
*(WORD*)(locOut + out + j * 2) = nun[j];
out += owords * 2;
owords = 0;
}
//---------------------------------------------------------------------------
int __stdcall __export pack(char* pIn, char* pOut, int option, int* rLen)
{
out = 0;
owords = 0;
locIn = (WORD*)pIn;
locOut = new char[0x10000];
for(i = 0; i < option / 0x8C0; i++)
{
size = out;
out += 2;
in = 0;
while(in < 0x460)
{
n2 = 0;
for(n = 1; (locIn[in + n - 1] == locIn[in + n]) && ((in + n) < 0x460); n++);
if(i) for(n2 = 0; locIn[in + n2] == locIn[in + n2 - 0x460] && in + n2 < 0x460; n2++);
if(n > 1 || n2 > 1)
{
if(n > 0x7F) n = 0x7F;
if(n2 > 0xFF) n2 = 0xFF;
if(n > n2)
{
Flush();
locOut[out] = n;
*(WORD*)(locOut + out + 1) = locIn[in];
out += 3;
in += n;
}
else
{
Flush();
locOut[out] = 0x80;
locOut[out + 1] = n2;
out += 2;
in += n2;
}
}
else
{
nun[owords] = locIn[in];
owords++;
if(owords == 0x7F) Flush();
in++;
}
}
Flush();
locIn += 0x460;
*(WORD*)(locOut + size) = (WORD)(out - size - 2) << 8 | (WORD)(out - size - 2) >> 8;
}
*(WORD*)(locOut + out) = -1;
out += 2;
out = final(locOut, pOut, out, rLen);
*rLen = option;
delete[] locOut;
return out;
}
//---------------------------------------------------------------------------
Файл второй (у меня назывался p_dttext2.cpp).
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
char nun2[0x3F];
int obytes;
int out2;
//---------------------------------------------------------------------------
void Flush(char* pO)
{
if(!obytes) return;
pO[out2] = obytes | 0x80;
out2++;
for(int j = 0; j < obytes; j++)
pO[out2 + j] = nun2[j];
out2 += obytes;
obytes = 0;
}
//---------------------------------------------------------------------------
int final(char* pIn, char* pOut, int option, int* rLen)
{
int in = 0;
int n;
int n2;
int maxN;
int maxN2;
int maxIn;
int in2;
obytes = 0;
out2 = 0;
while(in < option)
{
maxN = 0;
maxN2 = 0;
maxIn = 0;
for(in2 = 0; in2 < in; in2++)
{
for(n = 0; pIn[in2 + n] == pIn[in + n] && in + n < option; n++);
if(in - in2 < 0x1000 && n < 0xB) n2 = n - 2;
else if(n < 0x43) n2 = n - 3;
else n2 = n - 5;
if(n2 > maxN2) { maxN2 = n2; maxN = n; maxIn = in2; }
}
for(n = 1; pIn[in + n - 1] == pIn[in + n] && in + n - 1 < option; n++);
n2 = n - 4;
if(n2 > maxN2) { maxN2 = n2; maxN = n; maxIn = in; }
if(maxN2 >= 0 && maxN > 2)
{
if(in == maxIn)
{
Flush(pOut);
pOut[out2] = 0xFE;
*(WORD*)(pOut + out2 + 1) = maxN;
pOut[out2 + 3] = pIn[in];
out2 += 4;
in += maxN;
}
else if(in - maxIn < 0x1000 && maxN < 0xB)
{
Flush(pOut);
pOut[out2] = (maxN - 3) << 4 | (in - maxIn) >> 8;
pOut[out2 + 1] = (BYTE)(in - maxIn);
out2 += 2;
in += maxN;
}
else if(maxN < 0x43)
{
Flush(pOut);
pOut[out2] = 0xC0 | (maxN - 3);
*(WORD*)(pOut + out2 + 1) = maxIn;
out2 += 3;
in += maxN;
}
else
{
Flush(pOut);
pOut[out2] = 0xFF;
*(WORD*)(pOut + out2 + 1) = maxN;
*(WORD*)(pOut + out2 + 3) = maxIn;
out2 += 5;
in += maxN;
}
}
else
{
nun2[obytes] = pIn[in];
obytes++;
if(obytes == 0x3F) Flush(pOut);
in++;
}
}
Flush(pOut);
pOut[out2] = 0x80;
out2++;
*rLen = option;
return out2;
}
//---------------------------------------------------------------------------
Компилилось все это в виде дээлэльки-плагина к моей проге. Тебе это нафик не надо, переделаешь в экзешники.
Если, конечно, поймешь хоть что-нибудь в этой писанине. Особенно в сишной.
Есть желающие сделать полноценную прогу?