Propongo los siguientes cambios para añadir soporte de mapas comprimidos. Son 4 cambios en total.
Cambio número 1. El archivo make.bat
En este caso habría que añadir la siguiente línea:
$this->bbcode_second_pass_code('', '
TmxCompress mapa.tmx mapa_comprimido.bin
')
Y en caso de trabajar con Mappy habría que hacer una previa conversión de .map a .tmx con algo así (adecuar los parámetros a tu juego):
$this->bbcode_second_pass_code('', '
Map2Tmx 5 4 15 10 99 mapa.tmx mapa.map
')
Las herramientas TmxCompress y Map2Tmx están aquí:
https://github.com/DSkywalk/fase/blob/m ... Compress.chttps://github.com/DSkywalk/fase/blob/m ... Compress.cTambién hay que tener en cuenta que el mapa original debe ser ocultado mediante directivas de compilación y la constante COMPRESSED_MAPS, para ello sería conveniente modificar la herramienta MapCnv para que genere un mapa.h como este:
$this->bbcode_second_pass_code('', '
...
#ifdef COMPRESSED_MAPS
unsigned char *mapa;
#else
unsigned char mapa [] = {
...
};
#endif
...
')
Como yo trabajo con Tiled, utilizo la herramienta TmxCnv que ya viene correctamente preparada para ocultar el mapa original:
https://github.com/DSkywalk/fase/blob/m ... s/TmxCnv.cTambién se puede modificar a mano mapa.h, pero es lo menos aconsejable.
Es muy importante tomar nota de los valores bitsym y bithlf que nos devuelve TmxCompress, puesto que tendremos que pasarlos a mano posteriormente a las directivas DMAP_BITSYMB y DMAP_BITHALF de config.h
Cambio número 2. El archivo config.h
Este archivo es el más sencillo de modificar, tan solo hay que añadir estas 4 líneas en cualquier parte del archivo:
$this->bbcode_second_pass_code('', '
#define COMPRESSED_MAPS
#define DMAP_BITSYMB 4
#define DMAP_BITHALF 0
#define DMAP_BUFFER 0x5b01
')
Evidentemente las constantes DMAP_BITSYMB y DMAP_BITHALF las debemos modificar con los valores que nos sugiera el compresor de mapas.
Cambio número 3. El archivo engine.h
Tenemos que cambiar este código:
$this->bbcode_second_pass_code('', '
...
void __FASTCALL__ draw_scr_background (void) {
#ifdef UNPACKED_MAP
map_pointer = mapa + (n_pant * 150);
#else
map_pointer = mapa + (n_pant * 75);
#endif
srand (n_pant);
gpx = gpy = 0;
// Draw 150 tiles
for (gpit = 0; gpit < 150; gpit ++) {
#ifdef UNPACKED_MAP
// Mapa tipo UNPACKED
gpd = *map_pointer ++;
map_attr [gpit] = comportamiento_tiles [gpd];
map_buff [gpit] = gpd;
#else
// Mapa tipo PACKED
if (!(gpit & 1)) {
gpc = *map_pointer ++;
gpd = gpc >> 4;
} else {
gpd = gpc & 15;
}
map_attr [gpit] = comportamiento_tiles [gpd];
if (gpd == 0 && (rand () & 15) == 1) gpd = 19;
map_buff [gpit] = gpd;
#endif
#ifdef BREAKABLE_WALLS
brk_buff [gpit] = 0;
#endif
draw_coloured_tile (VIEWPORT_X + gpx, VIEWPORT_Y + gpy, gpd);
...
')
Por este otro:
$this->bbcode_second_pass_code('', '
...
void __FASTCALL__ draw_scr_background (void) {
#ifdef COMPRESSED_MAPS
descomprimir_map( n_pant );
map_pointer = DMAP_BUFFER;
#else
#ifdef UNPACKED_MAP
map_pointer = mapa + (n_pant * 150);
#else
map_pointer = mapa + (n_pant * 75);
#endif
#endif
srand (n_pant);
gpx = gpy = 0;
// Draw 150 tiles
for (gpit = 0; gpit < 150; gpit ++) {
#ifdef UNPACKED_MAP
// Mapa tipo UNPACKED
gpd = *map_pointer ++;
map_attr [gpit] = comportamiento_tiles [gpd];
map_buff [gpit] = gpd;
#else
// Mapa tipo PACKED
#ifdef COMPRESSED_MAPS
gpd = *map_pointer ++;
#else
if (!(gpit & 1)) {
gpc = *map_pointer ++;
gpd = gpc >> 4;
} else {
gpd = gpc & 15;
}
#endif
map_attr [gpit] = comportamiento_tiles [gpd];
if (gpd == 0 && (rand () & 15) == 1) gpd = 19;
map_buff [gpit] = gpd;
#endif
#ifdef BREAKABLE_WALLS
brk_buff [gpit] = 0;
#endif
draw_coloured_tile (VIEWPORT_X + gpx, VIEWPORT_Y + gpy, gpd);
...
')
Cambio número 4. Añadir la función descomprimir_map, donde queramos.
En principio D_Skywalk sugirió meter dicha función en aplib.h, aunque yo más adelante creé un archivo nuevo llamado compress.h con su correspondiente include. La función a añadir sería la siguiente:
$this->bbcode_second_pass_code('', '
#ifndef SCR_W
#define SCR_W 15
#endif
#ifndef SCR_H
#define SCR_H 10
#endif
#ifdef COMPRESSED_MAPS
void __FASTCALL__ descomprimir_map ( unsigned char pantalla) {
#asm
ld a, l
and a
ld b, h
ld c, h
ld de, map
ld hl, fin-1
desc1: sbc hl, bc
ex de, hl
ld c, (hl)
ex de, hl
inc de
dec a
jp p, desc1
ld de, DMAP_BUFFER+SCR_W*SCR_H-1
ld b, $80 ; marker bit
desc2: ld a, 256 / 2^DMAP_BITSYMB
desc3: call gbit3 ; load DMAP_BITSYMB bits (literal)
jr nc, desc3
#if (DMAP_BITHALF==1)
#if (DMAP_BITSYMB==1)
rrca
jr nc, desc4
xor a
call gbit3
inc a
#else
rrca ; half bit implementation (ie 48 tiles)
call c, gbit1
#endif
#else
and a
#endif
desc4: ld (de), a ; write literal
desc5: dec e ; test end of file (map is always 150 bytes)
ret z
call gbit3 ; read one bit
rra
jr nc, desc2 ; test if literal or sequence
push de ; if sequence put de in stack
ld a, 1 ; determine number of bits used for length
desc6: call nc, gbit3 ; (Elias gamma coding)
and a
call gbit3
rra
jr nc, desc6 ; check end marker
inc a ; adjust length
ld c, a ; save lenth to c
xor a
ld de, SCR_W
call gbit3 ; get two bits
call gbit3
jr z, desc9 ; 00 = 1
dec a
call gbit3
jr z, descb ; 010 = 15
bit 2, a
jr nz, desc7
#if (SCR_W>15)
call gbit3 ; [011, 100, 101] xx = from 2 to 13
dec a
call gbit3
jr desca
desc7: call gbit3 ; [110, 111] xxxxxx = from 14-15, 17-142
jr nc, desc7
cp SCR_W-14
sbc a, -14
#else
#if (SCR_W==15)
add a, $7c ; [011, 100, 101] xx = from 2 to 13
dec e
desc7: dec e ; [110, 111] xxxxxx = 14 and from 16 to 142
desc8: call gbit3
jr nc, desc8
jr z, descb
add a, e
#else
call gbit3 ; [011, 100, 101] xx = from 2 to 11 and from 13 to 14
call gbit3
cp SCR_W+2
sbc a, 2
jr desc9
desc7: call gbit3 ; [110, 111] xxxxxx = from 15 to 142
jr nc, desc7
add a, 14
#endif
#endif
desc9: inc a
desca: ld e, a
descb: ld a, b ; save b (byte reading) on a
ld b, d ; b= 0 because lddr moves bc bytes
ex (sp), hl ; store source, restore destination
ex de, hl ; HL = destination + offset + 1
add hl, de ; DE = destination
lddr
pop hl ; restore source address (compressed data)
ld b, a ; restore b register
inc e ; prepare test of end of file
jr desc5 ; jump to main loop
#if (DMAP_BITHALF==1 && DMAP_BITSYMB>1)
gbit1: sub $80 - (2^(DMAP_BITSYMB-2))
defb $da ; second part of half bit implementation
#endif
gbit2: ld b, (hl) ; load another group of 8 bits
dec hl
gbit3: rl b ; get next bit
jr z, gbit2 ; no more bits left?
adc a, a ; put bit in a
ret
.map BINARY "mapa_comprimido.bin"
.fin
#endasm
}
#endif
')
Edito: Al final he preferido usar las constantes, los primeros ifndef están para definirlas en caso de que no existan. Así el código es definitivo y no hay que hacer futuros cambios.