Página 1 de 1

El hilo de las modificaciones a la Churrera

Publicado: Mié, 18 Sep 2013, 11:11
por na_th_an
Iré subiendo en este hilo modificaciones fáciles de hacer al motor de la Churrera que puedan servir de algo a gente que esté haciendo sus propios güegos. La Churrera es muy configurable, pero hay cosas que no se pueden hacer de entrada, pero que son fáciles de añadir y/o modificar.

Re: El hilo de las modificaciones a la Churrera

Publicado: Mié, 18 Sep 2013, 11:17
por na_th_an
fjpoyato pregunta por el siguiente cambio:
$this->bbcode_second_pass_quote('fjpoyato', 'H')ola, quería preguntar cómo se hace para aumentar las vidas o energía cuando te toca un enemigo (al revés, de 1 a 15) y para disminuir las vidas en lugar de recargarlas, es que tengo pensado un juego para esto, no es broma. Felicidades por este estupendo tutorial, un saludo :-)


En un principio había pensado en modificar toda la gestión de vidas de la Churrera (inicialización, decremento e incremento, condición de Game Over) cuando me he dado cuenta de que es mucho más fácil timar al jugador. En lugar de mostrarle el número de vidas, se le mostrará PLAYER_LIFE - numero de vidas, con lo que se empezará en 0 y se terminará en el máximo. Cuando se pierda una vida parecerá que se gana y cuando se coja una recarga parecerá que se pierde.

Para realizar esta modificación, no hay más que tocar mainloop.h, a partir de la linea 193 (puede que cambie la linea si actualizamos la versión, busca algo parecido a esto):

$this->bbcode_second_pass_code('', 'if (player.life != life_old) {
print_number2 (LIFE_X, LIFE_Y, player.life);
life_old = player.life;
}')

Debería quedar así:

$this->bbcode_second_pass_code('', 'if (player.life != life_old) {
print_number2 (LIFE_X, LIFE_Y, PLAYER_LIFE - player.life);
life_old = player.life;
}')

Con esto, se consigue el efecto que se quería.

Re: El hilo de las modificaciones a la Churrera

Publicado: Mié, 02 Oct 2013, 07:59
por na_th_an
D_Skywalk ha propuesto el siguiente cambio:

$this->bbcode_second_pass_quote('D_Skywalk', 'R')especto a las recargas, [...] en la documentación dice algo como que las recargas salen aleatoriamente si el jugador ha cogido el objeto, en el lugar donde se puso el hotspot. Mi pregunta era que sabiendo que sólo puedo poner un hotspot por pantalla hay alguna forma sencilla donde se pueda configurar (usando un tipo nuevo?) que un hotspot sea recarga o sea objeto (trozo de espada).


Vamos a invalidar el comportamiento normal y a establecer la recarga como tipo de hotspot número 3. Usaremos el colocador para poner las recargas de vida como los objetos o las llaves, pero con tipo = 3.

En el código del motor hay que cambiar dos cosas: primero tendremos que modificar el código que dibuja el hotspot al entrar en una nueva pantalla. Este código está en la función draw_scr, a partir de la linea 1159 del archivo engine.h. Este trozo distingue si hemos cogido o no el objeto/llave/balas de un hotspot activo para mostrar el item correspondiente o, al azar, una recarga:

$this->bbcode_second_pass_code('', ' if ((hotspots [n_pant].act == 1 && hotspots [n_pant].tipo) ||
(hotspots [n_pant].act == 0 && (rand () & 7) == 2)) {
hotspot_x = gpx << 4;
hotspot_y = gpy << 4;
orig_tile = map_buff [15 * gpy + gpx];
draw_coloured_tile (VIEWPORT_X + gpx + gpx, VIEWPORT_Y + gpy + gpy, 16 + (hotspots [n_pant].act ? hotspots [n_pant].tipo : 0));
}')

Tendremos que modificarlo para que quede así:

$this->bbcode_second_pass_code('', ' if (hotspots [n_pant].act == 1 && hotspots [n_pant].tipo) {
hotspot_x = gpx << 4;
hotspot_y = gpy << 4;
orig_tile = map_buff [15 * gpy + gpx];
draw_coloured_tile (VIEWPORT_X + gpx + gpx, VIEWPORT_Y + gpy + gpy, 16 + (hotspots [n_pant].tipo != 3 ? hotspots [n_pant].tipo : 0));
}')

Así, si el hotspot es de tipo 3 se dibujará el tile 16. Si vale 1, el 17 (objeto), si vale 2, el 18 (llave), y si vale 4, el 20 (munición). Ahora tenemos que cambiar la parte del código que se encarga de detectar cuando el jugador toca el hotspot. Este código se encuentra en el archivo mainloop.h, a partir de la linea 316. Se trata de mover el código que aparece en la primera rama del IF a un caso de la instrucción selectiva de más abajo. El código original es:

$this->bbcode_second_pass_code('', ' // Was it an object, key or life boost?
if (hotspots [n_pant].act == 0) {
player.life += PLAYER_REFILL;
if (player.life > PLAYER_LIFE)
player.life = PLAYER_LIFE;
hotspots [n_pant].act = 2;
peta_el_beeper (8);
} else {
switch (hotspots [n_pant].tipo) {
#ifndef DEACTIVATE_OBJECTS
case 1:
#ifdef ONLY_ONE_OBJECT
if (player.objs == 0) {
player.objs ++;
peta_el_beeper (9);
} else {
peta_el_beeper (4);
draw_coloured_tile (VIEWPORT_X + (hotspot_x >> 3), VIEWPORT_Y + (hotspot_y >> 3), 17);
gpit = 1;
}
#else
player.objs ++;
peta_el_beeper (9);
break;
#endif
#endif
#ifndef DEACTIVATE_KEYS
case 2:
player.keys ++;
peta_el_beeper (7);
break;
#endif
#ifdef MAX_AMMO
case 4:
if (MAX_AMMO - player.ammo > AMMO_REFILL)
player.ammo += AMMO_REFILL;
else
player.ammo = MAX_AMMO;
peta_el_beeper (9);
break;
#endif
}
hotspots [n_pant].act = gpit;
}
hotspot_x = hotspot_y = 240;
} ')

Y debe quedar así:

$this->bbcode_second_pass_code('', ' // Was it an object, key or life boost?
if (hotspots [n_pant].act) {
switch (hotspots [n_pant].tipo) {
#ifndef DEACTIVATE_OBJECTS
case 1:
#ifdef ONLY_ONE_OBJECT
if (player.objs == 0) {
player.objs ++;
peta_el_beeper (9);
} else {
peta_el_beeper (4);
draw_coloured_tile (VIEWPORT_X + (hotspot_x >> 3), VIEWPORT_Y + (hotspot_y >> 3), 17);
gpit = 1;
}
#else
player.objs ++;
peta_el_beeper (9);
#endif
break;
#endif
#ifndef DEACTIVATE_KEYS
case 2:
player.keys ++;
peta_el_beeper (7);
break;
#endif
case 3:
player.life += PLAYER_REFILL;
if (player.life > PLAYER_LIFE)
player.life = PLAYER_LIFE;
peta_el_beeper (8);
break;
#ifdef MAX_AMMO
case 4:
if (MAX_AMMO - player.ammo > AMMO_REFILL)
player.ammo += AMMO_REFILL;
else
player.ammo = MAX_AMMO;
peta_el_beeper (9);
break;
#endif
}
hotspots [n_pant].act = gpit;
}
hotspot_x = hotspot_y = 240;
}')

(las explicaciones se refieren a al versión actual 3.99.1, es posible que las lineas bailen un poco en otras versiones)

Re: El hilo de las modificaciones a la Churrera

Publicado: Lun, 27 Ene 2014, 11:20
por antoniovillena
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.c
https://github.com/DSkywalk/fase/blob/m ... Compress.c

Tambié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.c

Tambié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.

Re: El hilo de las modificaciones a la Churrera

Publicado: Lun, 31 Ago 2015, 12:10
por na_th_an
Desactivar el tile alternativo

Consiste en desactivar la funcionalidad que, al azar, sustituye el tile 0 por el tile 19 al dibujar la pantalla. Para ello, abrimos engine.h y buscamos este texto (alrededor de la linea 1368 en la 3.99.3d):

$this->bbcode_second_pass_code('', ' if (gpd == 0 && (rand () & 15) == 1) gpd = 19;')

Y lo comentamos:

$this->bbcode_second_pass_code('', ' //if (gpd == 0 && (rand () & 15) == 1) gpd = 19;')

Re: El hilo de las modificaciones a la Churrera

Publicado: Lun, 31 Ago 2015, 12:37
por na_th_an
Desactivar plataformas en vista lateral

Para desactivar las plataformas en vista lateral, obteniendo más espacio libre y la posibilidad de usar el último par de sprites como un cuarto enemigo, hay que comentar algunos bloques de código en engine.h.

En primer lugar habrá que comentar todo el bloque de código que detecta las plataformas para realizar el arrastre. Este bloque empieza en la linea 1844 con

$this->bbcode_second_pass_code('', '#ifndef PLAYER_MOGGY_STYLE
// Platforms
if (malotes [enoffsmasi].t == 4) {')

Y termina en la linea 1946:

$this->bbcode_second_pass_code('', ' } else if (!tocado && collide (gpx, gpy, gpen_cx, gpen_cy) && player.estado == EST_NORMAL) {
#else <---- aquí termina')

Tenemos que comentar todo ese código colocando /* antes de la linea 1844 y */ después de la 1946. También hay que comentar el "#endif" que hay justo después; que quede así:

$this->bbcode_second_pass_code('', '/*
#ifndef PLAYER_MOGGY_STYLE
// Platforms
if (malotes [enoffsmasi].t == 4) {

.
.
.
Un montón de cosas
.
.
.
} else if (!tocado && collide (gpx, gpy, gpen_cx, gpen_cy) && player.estado == EST_NORMAL) {
#else
*/
if (!tocado && collide (gpx, gpy, gpen_cx, gpen_cy) && player.estado == EST_NORMAL) {
//#endif ')

Más tarde, alrededor de 2063 vemos esto, que evita que las plataformas móviles "pierdan vida":

$this->bbcode_second_pass_code('', '#ifndef PLAYER_MOGGY_STYLE
if (malotes [enoffsmasi].t != 4) malotes [enoffsmasi].life --;
#else
malotes [enoffsmasi].life --;
#endif')

Eliminamos todo el bloque y lo dejamos para que cualquier enemigo pierda vida. Sustituimos TODO lo de arriba por un sencillo:

$this->bbcode_second_pass_code('', ' malotes [enoffsmasi].life --;')