Import blues from be69d5ea

This commit is contained in:
Gregory Montoir 2019-06-02 08:55:05 +08:00
parent 1592f7ef80
commit 2345fb7fe4
9 changed files with 1138 additions and 925 deletions

View File

@ -4,7 +4,7 @@ SDL_LIBS := `sdl2-config --libs`
BB := decode.c game.c level.c objects.c resource.c screen.c sound.c staticres.c tiles.c unpack.c
JA := game.c level.c resource.c screen.c sound.c staticres.c unpack.c
P2 := game.c level.c monsters.c resource.c screen.c sound.c staticres.c unpack.c
P2 := bosses.c game.c level.c monsters.c resource.c screen.c sound.c staticres.c unpack.c
BB_SRCS := $(foreach f,$(BB),bb/$f)
JA_SRCS := $(foreach f,$(JA),ja/$f)

View File

@ -5,7 +5,7 @@ This is a rewrite of the [Blues Brothers](https://www.mobygames.com/game/blues-b
![Screenshot1](blues1.png) ![Screenshot2](bbja2.png)
There is also some support for [Prehistorik 2](https://www.mobygames.com/game/prehistorik-2).
There is also support for [Prehistorik 2](https://www.mobygames.com/game/prehistorik-2).
## Requirements

846
p2/bosses.c Normal file
View File

@ -0,0 +1,846 @@
/* bosses logic : gorilla, tree, minotaur */
#include "game.h"
#include "resource.h"
#include "util.h"
static void level_update_objects_boss_energy(int count) {
if (count > 8) {
count = 8;
}
if (count != 0) {
play_music(13);
for (int i = 0; i < count; ++i) {
struct object_t *obj = &g_vars.objects_tbl[108 + i];
obj->spr_num = 0x135;
obj->x_pos = 8 + i * 5;
obj->y_pos = 170;
}
}
for (int i = count; i < 8; ++i) {
g_vars.objects_tbl[108 + i].spr_num = 0xFFFF;
}
}
static void level_update_objects_boss_hit_player() {
--g_vars.bonus_energy_counter;
if (g_vars.bonus_energy_counter < 0) {
g_vars.bonus_energy_counter = 5;
if ((g_options.cheats & CHEATS_UNLIMITED_ENERGY) == 0) {
--g_vars.player_energy;
if (g_vars.player_energy < 0) {
level_player_die();
}
}
}
g_vars.current_bonus.x_pos = g_vars.objects_tbl[1].x_pos;
g_vars.current_bonus.y_pos = g_vars.objects_tbl[1].y_pos - 48;
g_vars.current_bonus.spr_num = 0x2046; /* bones */
const int x_vel = (g_vars.bonus_energy_counter & 1) != 0 ? -48 : 48;
const int y_vel = -128;
level_add_object23_bonus(x_vel, y_vel, 1);
}
static void level_update_boss_gorilla_collide_proj(struct object_t *obj_player, struct object_t *obj) {
if (obj->spr_num == 0xFFFF || (obj->spr_num & 0x2000) == 0) {
return;
}
if (!level_objects_collide(obj_player, obj)) {
return;
}
const int count = 4 - g_res.level.boss_speed;
if (g_vars.boss.change_counter < count) {
g_vars.boss.change_counter = 0;
} else {
g_vars.boss.change_counter -= count;
}
if (g_options.cheats & CHEATS_NO_HIT) {
return;
}
level_update_objects_boss_hit_player();
obj_player->hit_counter = 44;
g_vars.player_anim_0x40_flag = 0;
obj_player->data.p.y_velocity = -128;
obj_player->x_friction = 3;
obj_player->x_velocity = (g_vars.objects_tbl[1].x_pos >= g_res.level.boss_x_pos) ? 128 : -128;
g_vars.player_gravity_flag = 0;
}
static void level_update_boss_gorilla_hit_player() {
if (g_vars.restart_level_flag != 0) {
return;
}
level_update_boss_gorilla_collide_proj(&g_vars.objects_tbl[1], g_vars.boss.obj2);
level_update_boss_gorilla_collide_proj(&g_vars.objects_tbl[1], g_vars.boss.obj1);
if (level_objects_collide(&g_vars.objects_tbl[1], g_vars.boss.obj3)) {
if (g_vars.player_jump_monster_flag != 0) {
g_vars.objects_tbl[1].data.p.y_velocity = (g_vars.input.key_up != 0) ? -128 : -64;
}
}
}
static void level_update_boss_gorilla_tick() {
if (g_vars.boss.change_counter < UCHAR_MAX) {
++g_vars.boss.change_counter;
}
}
static uint16_t level_update_boss_gorilla_find_pos(uint16_t num1, uint16_t num2) {
const uint16_t *p = boss_gorilla_spr_tbl;
const uint16_t *end = &boss_gorilla_spr_tbl[138];
while (p + 3 <= end) {
if (p[0] == num1 && p[1] == num2) {
return p[2]; /* dy,dx packed as a uint16_t */
}
p += 3;
}
print_warning("boss_gorilla spr range (%d,%d) not found", num1, num2);
return 0xFFFF;
}
static void level_update_boss_gorilla_init_objects(const uint16_t *p) {
g_vars.boss.parts[0].spr_num = *p++;
g_vars.boss.parts[1].spr_num = *p++;
uint16_t d;
int8_t dx, dy;
d = level_update_boss_gorilla_find_pos(g_vars.boss.parts[0].spr_num, g_vars.boss.parts[1].spr_num);
dx = d & 255;
if (g_vars.boss.hdir) {
dx = -dx;
}
g_vars.boss.parts[1].x_pos = dx + g_vars.boss.parts[0].x_pos;
dy = d >> 8;
g_vars.boss.parts[1].y_pos = dy + g_vars.boss.parts[0].y_pos;
for (int i = 2; i <= 4; ++i) {
g_vars.boss.parts[i].spr_num = *p++;
d = level_update_boss_gorilla_find_pos(g_vars.boss.parts[1].spr_num, g_vars.boss.parts[i].spr_num);
dx = d & 255;
if (g_vars.boss.hdir) {
dx = -dx;
}
g_vars.boss.parts[i].x_pos = dx + g_vars.boss.parts[1].x_pos;
dy = d >> 8;
g_vars.boss.parts[i].y_pos = dy + g_vars.boss.parts[1].y_pos;
}
if (g_vars.boss.anim_num & 0x40) {
g_vars.boss.parts[1].y_pos += 2;
++g_vars.boss.parts[2].y_pos;
++g_vars.boss.parts[4].y_pos;
++g_vars.boss.parts[3].y_pos;
}
if (g_vars.boss.hdir) {
g_vars.boss.parts[0].spr_num |= 0x8000;
g_vars.boss.parts[1].spr_num |= 0x8000;
g_vars.boss.parts[2].spr_num |= 0x8000;
g_vars.boss.parts[3].spr_num |= 0x8000;
g_vars.boss.parts[4].spr_num |= 0x8000;
}
for (int i = 0; i < 5; ++i) {
struct object_t *obj = &g_vars.objects_tbl[103 + i];
const uint16_t addr = *p++;
if (addr == 0xA609) {
g_vars.boss.obj1 = obj;
}
if (addr == 0xA60F) {
g_vars.boss.obj2 = obj;
}
if (addr == 0xA603) {
g_vars.boss.obj3 = obj;
}
assert(addr == 0xA5F7 || addr == 0xA5FD || addr == 0xA603 || addr == 0xA609 || addr == 0xA60F);
const int num = (addr - 0xA5F7) / 6;
obj->x_pos = g_vars.boss.parts[num].x_pos;
obj->y_pos = g_vars.boss.parts[num].y_pos;
obj->spr_num = g_vars.boss.parts[num].spr_num;
}
}
static bool level_update_boss_gorilla_collides_obj3(struct object_t *obj) {
if (obj->spr_num == 0xFFFF) {
return false;
}
const int spr_num = g_vars.boss.obj1->spr_num & 0x1FFF;
if ((spr_num == 0x196 || spr_num == 0x195) && level_objects_collide(obj, g_vars.boss.obj1)) {
obj->spr_num = 0xFFFF;
return false;
}
return level_objects_collide(obj, g_vars.boss.obj3);
}
static void level_update_boss_gorilla_helper2() {
for (int i = 0; i < 6; ++i) {
if (i == 1) {
continue;
}
struct object_t *obj = &g_vars.objects_tbl[i];
if (!level_update_boss_gorilla_collides_obj3(obj)) {
continue;
}
if (abs(g_vars.level_draw_counter - g_vars.boss.draw_counter) <= 22) {
break;
}
g_vars.boss.draw_counter = g_vars.level_draw_counter;
for (int j = 103; j <= 107; ++j) {
g_vars.objects_tbl[j].spr_num |= 0x4000;
}
g_vars.player_flying_flag = 0;
level_update_boss_gorilla_tick();
g_res.level.boss_energy -= g_vars.player_club_power;
if (g_res.level.boss_energy < 0) {
g_res.level.boss_state = 6;
g_vars.boss.y_velocity = -240;
break;
}
if (g_vars.player_club_power > 20) {
g_vars.boss.x_velocity = (g_res.level.boss_x_pos >= g_vars.objects_tbl[1].x_pos) ? 48 : -48;
g_vars.boss.y_velocity = (g_vars.boss.y_velocity > 0) ? -128 : -64;
g_res.level.boss_state = 5;
}
g_vars.boss.state_counter = 0;
obj->spr_num = 0xFFFF;
break;
}
}
static void level_update_boss_gorilla() {
if (g_vars.objects_tbl[103].spr_num == 0xFFFF || g_res.level.boss_state == 6 || (g_vars.objects_tbl[103].spr_num & 0x2000) == 0) {
level_update_objects_boss_energy(0);
} else {
level_update_objects_boss_energy(g_res.level.boss_energy >> 3);
}
const int x = (g_vars.boss.x_velocity >> 4) + g_res.level.boss_x_pos;
if (x >= 0) {
if (g_res.level.boss_xmin <= x && g_res.level.boss_xmax >= x) {
g_res.level.boss_x_pos = x;
}
}
g_res.level.boss_y_pos += (g_vars.boss.y_velocity >> 4);
if (g_vars.boss.y_velocity >= 0) {
const uint16_t pos = ((g_res.level.boss_y_pos >> 4) << 8) | (g_res.level.boss_x_pos >> 4);
const uint8_t tile_num = level_get_tile(pos);
if (g_res.level.tile_attributes1[tile_num] != 0) {
g_res.level.boss_y_pos &= ~15;
if (g_vars.boss.y_velocity != 0) {
g_vars.shake_screen_counter = 7;
}
g_vars.boss.y_velocity = 0;
g_vars.boss.x_velocity = 0;
} else {
if (g_vars.boss.y_velocity < 224) {
g_vars.boss.y_velocity += 16;
}
}
} else {
if (g_vars.boss.y_velocity < 224) {
g_vars.boss.y_velocity += 16;
}
}
g_vars.boss.hdir = (g_res.level.boss_x_pos < g_vars.objects_tbl[1].x_pos);
g_vars.boss.x_dist = abs(g_vars.objects_tbl[1].x_pos - g_res.level.boss_x_pos);
if (g_vars.boss.x_dist > 400) {
return;
}
if (abs(g_vars.objects_tbl[1].y_pos - g_res.level.boss_y_pos) > 250) {
return;
}
if (g_res.level.boss_state == 0) { /* waiting player to be near */
if (g_vars.boss.x_dist >= 250) {
g_vars.boss.change_counter = 0;
static const uint8_t data_st0[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF4
};
g_vars.boss.next_anim = data_st0;
} else {
g_vars.boss.state_counter = 0;
g_res.level.boss_state = 1;
}
} else if (g_res.level.boss_state == 1) {
if (g_vars.boss.x_dist >= 250) {
g_res.level.boss_state = 0;
} else {
++g_vars.boss.state_counter;
if (g_res.level.boss_energy < 60) {
g_res.level.boss_state = 2;
} else {
static const uint8_t data_st1[] = {
0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0xFA
};
g_vars.boss.next_anim = data_st1;
if (g_vars.boss.state_counter >= 110) {
g_res.level.boss_state = 2;
level_update_boss_gorilla_tick();
g_vars.boss.state_counter = 0;
} else if (g_vars.player_anim_0x40_flag != 0 && (g_vars.level_draw_counter & 7) == 0) {
level_update_boss_gorilla_tick();
} else if (g_vars.boss.change_counter >= 10) {
g_res.level.boss_state = 3;
g_vars.boss.state_counter = 0;
} else if (g_vars.boss.change_counter > 3) {
g_res.level.boss_state = 2;
g_vars.boss.state_counter = 0;
}
}
}
} else if (g_res.level.boss_state == 2) {
++g_vars.boss.state_counter;
if (g_vars.boss.state_counter != 44) {
if (g_vars.boss.state_counter > 44) {
if (g_vars.boss.y_velocity > 0) {
static const uint8_t data_st2a[] = {
0x04, 0xFF
};
static const uint8_t data_st2b[] = {
0x07, 0xFF
};
g_vars.boss.next_anim = (g_res.level.boss_energy >= 100) ? data_st2a : data_st2b;
}
if (g_vars.boss.x_dist <= 80) {
g_vars.boss.state_counter = 0;
g_res.level.boss_state = 3;
g_vars.boss.change_counter = 11;
} else if (g_vars.boss.state_counter == 88) {
static const uint8_t data_st2[] = {
0x03, 0xFF
};
g_vars.boss.next_anim = data_st2;
int dx = g_res.level.boss_x_pos - g_vars.objects_tbl[1].x_pos;
int x_vel = 48;
int y_vel = abs(dx);
if (y_vel > g_res.level.boss_speed * 80) {
y_vel = -96;
} else {
y_vel = (y_vel / 14) << 4;
x_vel = y_vel >> 1;
y_vel = -y_vel;
}
g_vars.boss.y_velocity = y_vel;
if (dx >= 0) {
x_vel = -x_vel;
}
g_vars.boss.x_velocity = x_vel;
} else if (g_vars.boss.state_counter > 88) {
if (g_vars.boss.y_velocity == 0) {
g_vars.boss.change_counter = 3;
g_vars.boss.state_counter = 0;
g_res.level.boss_state = 1;
}
}
} else {
level_update_boss_gorilla_hit_player();
if (g_vars.boss.x_dist < 75) {
g_res.level.boss_state = 3;
g_vars.boss.state_counter = 0;
} else {
static const uint8_t data_st2[] = {
0x10, 0x50, 0x10, 0x11, 0x51, 0x11, 0x10, 0x50, 0x10, 0x11,
0x51, 0x11, 0x10, 0x50, 0x10, 0x11, 0x51, 0x11, 0x00, 0x00,
0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40,
0x00, 0x00, 0x40, 0x40, 0xDE
};
g_vars.boss.next_anim = data_st2;
}
}
} else {
level_update_boss_gorilla_hit_player();
g_vars.boss.y_velocity = -224;
if (g_res.level.boss_energy < 40 && g_vars.boss.x_dist < 80) {
g_res.level.boss_state = 4;
g_vars.boss.state_counter = 0;
}
static const uint8_t data_st2[] = {
0x03, 0xFF
};
g_vars.boss.next_anim = data_st2;
}
} else if (g_res.level.boss_state == 3) { /* attack player */
level_update_boss_gorilla_hit_player();
const int counter = (abs(g_res.level.boss_energy - 50) > 25) ? 66 : 154;
if (g_vars.boss.state_counter > counter) {
g_vars.boss.state_counter = 0;
g_res.level.boss_state = 2;
} else {
if (g_vars.boss.y_velocity == 0) {
if (g_vars.boss.x_dist < 100) {
if (g_vars.boss.x_dist <= 25) {
static const uint8_t data_st3[] = {
0x0D, 0x0D, 0x0E, 0x0E, 0xFC
};
g_vars.boss.next_anim = data_st3;
} else if (g_vars.boss.x_dist <= 35) {
g_res.level.boss_state = 4;
g_vars.boss.state_counter = 0;
} else {
if (g_vars.boss.change_counter == 0) {
g_res.level.boss_state = 7;
g_vars.boss.state_counter = 0;
}
static const uint8_t data_st3[] = {
0x0D, 0x0D, 0x0C, 0x0C, 0xFC
};
g_vars.boss.next_anim = data_st3;
}
} else {
g_vars.boss.y_velocity = -81;
g_vars.boss.x_velocity = (g_vars.objects_tbl[1].x_pos > g_res.level.boss_x_pos) ? 80 : -80;
}
} else if (g_vars.boss.y_velocity < 0) {
static const uint8_t data_st3[] = {
0x03, 0xFF
};
g_vars.boss.next_anim = data_st3;
} else {
static const uint8_t data_st3[] = {
0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0xFA
};
g_vars.boss.next_anim = data_st3;
}
}
} else if (g_res.level.boss_state == 4) {
level_update_boss_gorilla_hit_player();
++g_vars.boss.state_counter;
if (g_vars.boss.state_counter > 66) {
g_res.level.boss_state = 3;
g_vars.boss.state_counter = 0;
} else {
static const uint8_t data_st4[] = {
0x12, 0x12, 0x52, 0x12, 0x0E, 0x0E, 0x4E, 0x0E, 0xF8
};
g_vars.boss.next_anim = data_st4;
if (g_vars.boss.y_velocity == 0) {
g_vars.shake_screen_counter = 4;
}
}
} else if (g_res.level.boss_state == 5) { /* hit by player */
++g_vars.boss.state_counter;
if (g_vars.boss.state_counter > 19) {
g_vars.boss.state_counter = 0;
g_res.level.boss_state = 1;
} else {
static const uint8_t data_st5[] = {
0x05, 0xFF
};
g_vars.boss.next_anim = data_st5;
}
} else if (g_res.level.boss_state == 6) { /* defeated */
static const uint8_t data_st6[] = {
0x05, 0x05, 0x0F, 0x0F, 0xFC
};
g_vars.boss.next_anim = data_st6;
if (g_vars.boss.y_velocity >= 0) {
g_res.level.boss_state = 0xFF;
for (int i = 0; i < 5; ++i) {
g_vars.objects_tbl[103 + i].spr_num = 0xFFFF;
}
g_vars.current_bonus.x_pos = g_vars.objects_tbl[103].x_pos;
g_vars.current_bonus.y_pos = g_vars.objects_tbl[103].y_pos;
level_add_bonuses_4x();
g_vars.current_bonus.x_pos += 32;
g_vars.current_bonus.y_pos += 32;
level_add_bonuses_4x();
g_vars.current_bonus.x_pos -= 64;
level_add_bonuses_4x();
g_vars.current_bonus.x_pos -= 32;
g_vars.current_bonus.y_pos -= 64;
level_add_bonuses_4x();
g_vars.current_bonus.spr_num = 99; /* end of level lighter */
level_add_object23_bonus(0, 0, 1);
return;
}
} else if (g_res.level.boss_state == 7) {
++g_vars.boss.state_counter;
if (g_vars.boss.state_counter > 44) {
g_res.level.boss_state = 1;
} else {
static const uint8_t data_st7[] = {
0x03, 0xFF
};
g_vars.boss.next_anim = data_st7;
if (g_vars.boss.y_velocity == 0) {
g_vars.boss.y_velocity = -97;
g_vars.boss.x_velocity = (g_vars.objects_tbl[1].x_pos > g_res.level.boss_x_pos) ? -48 : 48;
} else if (g_vars.boss.y_velocity > 0) {
static const uint8_t data_st7[] = {
0x04, 0xFF
};
g_vars.boss.next_anim = data_st7;
}
}
}
if (g_vars.boss.prev_anim != g_vars.boss.next_anim) {
g_vars.boss.prev_anim = g_vars.boss.next_anim;
g_vars.boss.current_anim = g_vars.boss.next_anim;
}
const uint8_t *p = g_vars.boss.current_anim;
while (1) {
const uint8_t num = *p;
if (num & 0x80) {
p += (int8_t)num;
} else {
g_vars.boss.current_anim = p + 1;
g_vars.boss.anim_num = num;
g_vars.boss.parts[0].x_pos = g_res.level.boss_x_pos;
g_vars.boss.parts[0].y_pos = g_res.level.boss_y_pos;
const uint16_t *p = &boss_gorilla_data[(num & ~0x40) * 20 / sizeof(uint16_t)];
level_update_boss_gorilla_init_objects(p);
level_update_boss_gorilla_helper2();
break;
}
}
}
static void level_update_boss_tree() {
level_update_objects_boss_energy((2 - g_vars.boss_level5.state) << 1);
struct object_t *obj_player = &g_vars.objects_tbl[1];
for (int i = 0; i < 5; ++i) {
struct boss_level5_leaf_t *leaf = &g_vars.boss_level5.leaf_tbl[i];
struct object_t *obj = &g_vars.objects_tbl[98 + i];
if (leaf->spr_num == 0xFFFF) {
continue;
}
if (g_vars.restart_level_flag == 0 && level_objects_collide(obj_player, obj)) {
obj_player->hit_counter = 44;
g_vars.player_anim_0x40_flag = 0;
obj_player->data.p.y_velocity = -128;
obj_player->x_friction = 3;
obj_player->x_velocity = -128;
level_update_objects_boss_hit_player();
leaf->spr_num = 0xFFFF;
obj->spr_num = 0xFFFF;
} else {
leaf->y_pos += leaf->y_delta >> 4;
leaf->x_delta += leaf->dir;
int dx = leaf->x_delta;
if (dx >= 32 || dx < -32) {
leaf->dir = -leaf->dir;
}
uint16_t spr_num = leaf->spr_num;
dx >>= 4;
if (dx != 0) {
spr_num += (dx > 0) ? 1 : 2;
}
leaf->x_pos += dx;
obj->x_pos = leaf->x_pos;
obj->y_pos = leaf->y_pos;
if (obj->y_pos > 2008) {
leaf->spr_num = 0xFFFF;
obj->spr_num = 0xFFFF;
} else {
obj->spr_num = spr_num;
}
}
}
g_vars.objects_tbl[105].spr_num = 0xFFFF;
g_vars.objects_tbl[104].spr_num = 0xFFFF;
if (g_vars.boss_level5.state < 2) {
static const uint16_t pos2_data[] = {
0x3D5, 0x7C1, 0x1AA, 0x3FA, 0x7B6, 0x1AB, 0x3E8, 0x7A8, 0x1AC,
0x3FF, 0x788, 0x1AD, 0x3D9, 0x79B, 0x1AE, 0x3FF, 0x7A8, 0x1AF,
0x405, 0x7A9, 0x1B7, 0, 0, 0xFFFF
};
const uint16_t *p = &pos2_data[g_vars.boss_level5.state * 6];
g_vars.objects_tbl[105].x_pos = p[0];
g_vars.objects_tbl[105].y_pos = p[1];
g_vars.objects_tbl[105].spr_num = p[2];
g_vars.objects_tbl[104].x_pos = p[3];
g_vars.objects_tbl[104].y_pos = p[4];
g_vars.objects_tbl[104].spr_num = p[5];
}
static const uint16_t pos1_data[] = {
0x3A9, 0x7D4, 0x1A4, 0x3D1, 0x7B9, 0x1A5, 0x3A2, 0x7A6, 0x1A6,
0x3B4, 0x79F, 0x1A7, 0x396, 0x78A, 0x1A8, 0x3B6, 0x79C, 0x1A9,
0x3E0, 0x795, 0x1B6, 0, 0, 0xFFFF
};
const uint16_t *p = &pos1_data[g_vars.boss_level5.spr106_pos * 6];
g_vars.objects_tbl[107].x_pos = p[0];
g_vars.objects_tbl[107].y_pos = p[1];
g_vars.objects_tbl[107].spr_num = p[2];
g_vars.objects_tbl[106].x_pos = p[3];
g_vars.objects_tbl[106].y_pos = p[4];
g_vars.objects_tbl[106].spr_num = p[5];
static const uint16_t pos3_data[] = {
0x3E3, 0x773, 0x1B0, 0x3E4, 0x771, 0x1B1, 0x3E4, 0x773, 0x1B2
};
const uint16_t *q = &pos3_data[g_vars.boss_level5.spr103_pos * 3];
g_vars.objects_tbl[103].x_pos = q[0];
g_vars.objects_tbl[103].y_pos = q[1];
g_vars.objects_tbl[103].spr_num = (g_vars.boss_level5.state != 0) ? 0xFFFF : q[2];
if ((g_vars.level_draw_counter & 3) == 0) {
++g_vars.boss_level5.spr103_pos;
if (g_vars.boss_level5.spr103_pos > 2) {
g_vars.boss_level5.spr103_pos = 0;
}
}
if (g_vars.boss_level5.unk1 >= 1) {
if (g_vars.boss_level5.unk1 == 1) {
g_vars.boss_level5.unk6 = 2;
--g_vars.boss_level5.spr106_pos;
g_vars.boss_level5.tick_counter += 5;
}
--g_vars.boss_level5.unk1;
} else if (g_vars.boss_level5.tick_counter == 0) {
++g_vars.boss_level5.unk6;
if (g_vars.boss_level5.unk6 > 2) {
g_vars.boss_level5.unk6 = 0;
}
++g_vars.boss_level5.spr106_pos;
if (g_vars.boss_level5.spr106_pos > 2) {
g_vars.boss_level5.spr106_pos = 0;
}
uint8_t ah = 1;
if (g_vars.boss_level5.spr106_pos != 0) {
ah = 3;
g_vars.shake_screen_counter = 4;
obj_player->x_pos += 2;
for (int i = 0; i < 5; ++i) {
struct boss_level5_leaf_t *leaf = &g_vars.boss_level5.leaf_tbl[i];
if (leaf->spr_num == 0xFFFF) {
leaf->spr_num = 0x1B3;
leaf->y_pos = obj_player->y_pos - 150;
const uint8_t r = random_get_number();
const int dx = r & 0x7C;
leaf->x_pos = obj_player->x_pos + (((r & 4) != 0) ? dx : -dx);
leaf->y_delta = ((r & 3) + 1) << 4;
leaf->x_delta = 0;
leaf->dir = 4;
break;
}
}
}
g_vars.boss_level5.tick_counter = ah;
--g_vars.boss_level5.idle_counter;
if (g_vars.boss_level5.idle_counter == 0) {
g_vars.boss_level5.idle_counter = (random_get_number() & 15) << 3;
g_vars.boss_level5.tick_counter = 64 + ((random_get_number() & 15) << 3);
g_vars.boss_level5.unk6 = 0;
}
if (g_vars.restart_level_flag == 0) {
if (level_objects_collide(obj_player, &g_vars.objects_tbl[107]) || level_objects_collide(obj_player, &g_vars.objects_tbl[106])) {
if (obj_player->y_pos <= 1979) {
obj_player->data.p.y_velocity = -160;
} else {
obj_player->data.p.y_velocity = -160;
obj_player->hit_counter = 44;
g_vars.player_anim_0x40_flag = 0;
obj_player->x_friction = 3;
obj_player->x_velocity = -128;
level_update_objects_boss_hit_player();
level_update_objects_boss_hit_player();
level_update_objects_boss_hit_player();
}
}
}
} else if (g_vars.restart_level_flag == 0) {
if (level_objects_collide(obj_player, &g_vars.objects_tbl[107]) && g_vars.player_jump_monster_flag) {
obj_player->data.p.y_velocity = g_vars.input.key_up ? -128 : -64;
}
}
if (g_vars.restart_level_flag == 0) {
struct object_t *_si = &g_vars.objects_tbl[103 + g_vars.boss_level5.state * 2];
for (int i = 0; i < 6; ++i) {
struct object_t *_di = &g_vars.objects_tbl[i];
if (_di->spr_num == 0xFFFF || _di == obj_player) {
continue;
}
g_vars.player_using_club_flag = 1;
const bool ret = level_objects_collide(_si, _di);
g_vars.player_using_club_flag = 0;
if (ret) {
_si->spr_num ^= 0x4000;
if (g_vars.boss_level5.state != 0) {
_si[-1].spr_num ^= 0x4000;
}
_di->spr_num = 0xFFFF;
g_vars.boss_level5.unk1 = 6;
if (g_vars.boss_level5.state < 2) {
g_vars.boss_level5.unk6 = 3;
g_vars.boss_level5.spr106_pos = 3;
}
--g_vars.boss_level5.energy;
if (g_vars.boss_level5.energy == 0) {
g_vars.boss_level5.energy = 7;
++g_vars.boss_level5.state;
if (g_vars.boss_level5.state == 3) {
/* boss defeated */
g_vars.current_bonus.x_pos = g_vars.objects_tbl[103].x_pos - 200;
g_vars.current_bonus.y_pos = g_vars.objects_tbl[103].y_pos;
level_add_bonuses_4x();
g_vars.current_bonus.x_pos += 32;
g_vars.current_bonus.y_pos += 32;
level_add_bonuses_4x();
g_vars.current_bonus.x_pos -= 64;
level_add_bonuses_4x();
g_vars.current_bonus.x_pos -= 32;
g_vars.current_bonus.y_pos -= 64;
level_add_bonuses_4x();
g_vars.current_bonus.spr_num = 99; /* end of level lighter */
level_add_object23_bonus(0, 0, 1);
for (int i = 0; i < 5; ++i) {
g_vars.objects_tbl[98 + i].spr_num = 0xFFFF;
g_vars.objects_tbl[103 + i].spr_num = 0xFFFF;
}
}
}
break;
}
}
if (obj_player->x_pos > 984) {
obj_player->hit_counter = 44;
g_vars.player_anim_0x40_flag = 0;
obj_player->data.p.y_velocity = -144;
obj_player->x_friction = 3;
obj_player->x_velocity = -160;
level_update_objects_boss_hit_player();
}
}
if (g_vars.boss_level5.tick_counter > 0) {
--g_vars.boss_level5.tick_counter;
}
}
static void level_update_boss_minotaur_set_frame(int num) {
const int offset = (num * 6 + 20);
for (int y = 0; y < 7; ++y) {
for (int x = 0; x < 6; ++x) {
g_res.leveldat[(y << 8) + 12 + x] = g_res.leveldat[(y << 8) + offset + x];
}
}
}
static void level_update_boss_minotaur_add_spr_0x137() { /* boss defeated, bonus */
g_vars.current_bonus.x_pos = 185;
g_vars.current_bonus.y_pos = 30;
g_vars.current_bonus.spr_num = 0x2137;
int x_vel = 32;
int y_vel = -160;
for (int i = 0; i < 4; ++i) {
level_add_object23_bonus(x_vel, y_vel, 1);
x_vel = -x_vel;
if (x_vel >= 0) {
x_vel -= 16;
y_vel -= 16;
}
}
}
static void level_update_boss_minotaur_add_spr_0x1CA() { /* rock */
for (int i = 0; i < 32; ++i) {
struct object_t *obj = &g_vars.objects_tbl[23 + i];
if (obj->spr_num != 0xFFFF) {
continue;
}
obj->spr_num = 0x1CA;
obj->x_pos = 200;
obj->y_pos = 88;
obj->hit_counter = 0;
obj->data.t.counter = 132;
obj->data.t.ref = 0;
obj->x_velocity = -((random_get_number() & 15) << 3);
obj->data.t.y_velocity = 0;
break;
}
}
static void level_update_boss_minotaur_add_spr_0x1CB() { /* ceiling chandelier */
for (int i = 0; i < 32; ++i) {
struct object_t *obj = &g_vars.objects_tbl[23 + i];
if (obj->spr_num != 0xFFFF) {
continue;
}
obj->spr_num = 0x1CB;
obj->x_pos = (random_get_number() & 0x7F) - 16;
obj->y_pos = 0;
obj->hit_counter = 0;
obj->data.t.counter = 66;
obj->data.t.ref = 0;
obj->x_velocity = 0;
obj->data.t.y_velocity = 0;
break;
}
}
static void level_update_boss_minotaur() {
static const uint16_t data[] = {
0xA70F, 5, 0xA74E, 1, 0xA70F, 3, 0xA74E, 2, 0xA70F, 2, 0xA734, 1, 0xFFFF
};
if (!g_vars.boss_level9.seq) {
g_vars.boss_level9.anim = data;
g_vars.boss_level9.energy = 24;
g_vars.boss_level9.seq_counter = 0;
g_vars.boss_level9.hit_counter = 3;
}
level_update_objects_boss_energy(g_vars.boss_level9.energy >> 2);
if (g_vars.boss_level9.energy == 0) {
level_update_boss_minotaur_set_frame(2);
return;
}
if (g_vars.boss_level9.seq_counter == 0) {
const uint16_t *p = g_vars.boss_level9.anim;
if (p[0] == 0xFFFF) {
p = data;
}
assert(p[0] >= 0xA70F);
g_vars.boss_level9.seq = &boss_minotaur_seq_data[p[0] - 0xA70F];
g_vars.boss_level9.seq_counter = p[1];
g_vars.boss_level9.anim = p + 2;
}
for (int i = 0; i < 4; ++i) {
struct object_t *obj = &g_vars.objects_tbl[2 + i];
if (obj->spr_num == 0xFFFF) {
continue;
}
if (obj->x_pos >= 235 || obj->y_pos >= 80) {
continue;
}
g_vars.boss_level9.seq = &boss_minotaur_seq_data[0x19];
if (g_vars.boss_level9.energy > 0) {
--g_vars.boss_level9.energy;
}
if (g_vars.boss_level9.energy == 0) {
level_update_boss_minotaur_add_spr_0x137();
}
++g_vars.boss_level9.hit_counter;
g_vars.boss_level9.hit_counter &= 3;
if (g_vars.boss_level9.hit_counter == 0) {
g_vars.boss_level9.seq = &boss_minotaur_seq_data[0x25];
}
break;
}
const uint8_t *p = g_vars.boss_level9.seq;
while (1) {
if (*p == 0xFF) {
level_update_boss_minotaur_add_spr_0x1CA();
++p;
} else if (*p == 0xFE) {
level_update_boss_minotaur_add_spr_0x1CB();
++p;
} else if (*p == 0xFD) {
play_sound(2);
++p;
} else if ((*p & 0x80) == 0) {
++g_vars.boss_level9.seq;
level_update_boss_minotaur_set_frame(*p);
break;
} else {
if (g_vars.boss_level9.seq_counter > 0) {
--g_vars.boss_level9.seq_counter;
}
p += (int8_t)*p;
g_vars.boss_level9.seq = p;
}
}
}
void boss_update() {
if (g_res.level.boss_state != 0xFF) {
level_update_boss_gorilla();
}
if (g_vars.level_num == 5 && (g_res.level.scrolling_mask & ~1) == 0) {
level_update_boss_tree();
}
if (g_vars.level_num == 9) {
level_update_boss_minotaur();
}
}

View File

@ -85,26 +85,27 @@ struct object_t {
108 8 : boss energy bars
*/
struct boss_level5_proj_t {
int16_t x_pos, y_pos;
struct boss_level5_leaf_t {
int16_t x_pos;
int16_t y_pos;
uint16_t spr_num;
uint16_t unk6;
uint16_t unk8;
int16_t y_delta;
int16_t x_delta;
int8_t dir;
};
struct rotation_t {
struct orb_t {
uint16_t x_pos;
uint16_t y_pos;
uint8_t index_tbl; /* cos_/sin_tbl */
uint8_t radius;
};
struct collision_t {
struct fly_t {
uint16_t x_pos;
uint16_t y_pos;
uint8_t unk4;
uint8_t unk5;
int8_t x_delta;
int8_t y_delta;
uint8_t unk6;
uint8_t unk7;
};
@ -173,11 +174,11 @@ struct vars_t {
uint8_t level_bonuses_count_tbl[80];
uint8_t bonus_energy_counter;
int16_t level_current_object_decor_x_pos, level_current_object_decor_y_pos;
int16_t current_platform_dx, current_platform_dy;
uint16_t decor_tile0_offset; /* decor tile below the player */
struct collision_t collision_tbl[20]; /* reset by bonus 145 */
struct rotation_t rotation_tbl[20];
struct fly_t fly_tbl[20];
struct orb_t orb_tbl[20]; /* spider webs */
struct object_t *current_hit_object;
struct object_t objects_tbl[OBJECTS_COUNT];
@ -196,6 +197,8 @@ struct vars_t {
uint8_t tile_tbl3[256]; /* animated tile state 3 */
uint8_t animated_tile_flag_tbl[256]; /* 1 if tile is animated */
uint8_t columns_tiles_buf[256];
struct {
int16_t x, y;
int16_t prev_x, prev_y;
@ -214,7 +217,7 @@ struct vars_t {
} monster;
struct {
uint16_t draw_counter;
uint8_t unk_counter;
uint8_t change_counter;
int16_t x_velocity, y_velocity;
bool hdir; /* facing to the right */
int16_t x_dist; /* horizontal distance from player */
@ -238,12 +241,12 @@ struct vars_t {
uint8_t spr103_pos;
uint8_t spr106_pos;
uint8_t unk6;
uint8_t counter;
uint8_t unk8;
struct boss_level5_proj_t proj_tbl[5];
uint8_t tick_counter;
uint8_t idle_counter;
struct boss_level5_leaf_t leaf_tbl[5];
} boss_level5; /* tree */
struct {
uint16_t energy;
int16_t energy;
uint8_t seq_counter;
uint8_t hit_counter;
const uint8_t *seq;
@ -307,6 +310,11 @@ extern void game_main();
/* level.c */
extern void do_level();
extern uint8_t level_get_tile(uint16_t offset);
extern void level_player_die();
extern bool level_objects_collide(const struct object_t *, const struct object_t *);
extern void level_add_object23_bonus(int x_vel, int y_vel, int count);
extern void level_add_bonuses_4x();
/* monsters.c */
extern void monster_change_next_anim(struct object_t *obj);
@ -324,11 +332,11 @@ extern void video_draw_string2(int offset, const char *str);
extern void video_draw_tile(const uint8_t *src, int x, int y);
extern void video_convert_tiles(uint8_t *data, int len);
extern void video_load_front_tiles();
extern void video_wait_vbl();
extern void video_transition_close();
extern void video_transition_open();
extern void video_load_sprites();
extern void video_draw_sprite(int num, int x, int y, int flag);
extern void video_put_pixel(int x, int y, uint8_t color);
/* sound.c */
extern void sound_init();

1110
p2/level.c

File diff suppressed because it is too large Load Diff

View File

@ -61,9 +61,9 @@ void monster_change_prev_anim(struct object_t *obj) {
obj->data.m.anim = p;
}
static struct rotation_t *find_rotation() {
static struct orb_t *find_orb() {
for (int i = 0; i < 20; ++i) {
struct rotation_t *r = &g_vars.rotation_tbl[i];
struct orb_t *r = &g_vars.orb_tbl[i];
if (r->x_pos == 0xFFFF) {
return r;
}
@ -71,11 +71,11 @@ static struct rotation_t *find_rotation() {
return 0;
}
static void monster_rotate_tiles(struct level_monster_t *m, int index, int step) {
static void monster_add_orb(struct level_monster_t *m, int index, int step) {
step >>= 2;
uint8_t radius = step;
for (int i = 0; i < 3; ++i) {
struct rotation_t *r = find_rotation();
struct orb_t *r = find_orb();
if (r) {
r->x_pos = m->x_pos;
r->y_pos = m->y_pos - 24;
@ -89,7 +89,7 @@ static void monster_rotate_tiles(struct level_monster_t *m, int index, int step)
static void monster_rotate_pos(struct object_t *obj, struct level_monster_t *m) {
obj->x_pos = m->x_pos + ((m->type4.radius * (((int8_t)cos_tbl[m->type4.angle]) >> 2)) >> 4);
obj->y_pos = m->y_pos + ((m->type4.radius * (((int8_t)sin_tbl[m->type4.angle]) >> 2)) >> 4);
monster_rotate_tiles(m, m->type4.angle, m->type4.radius);
monster_add_orb(m, m->type4.angle, m->type4.radius);
}
static void monster_update_y_velocity(struct object_t *obj, struct level_monster_t *m) {
@ -134,7 +134,7 @@ static void monster_func1_type2(struct object_t *obj) {
struct level_monster_t *m = obj->data.m.ref;
const uint8_t state = obj->data.m.state;
if (state < 2) {
monster_rotate_tiles(m, 0, obj->y_pos - m->y_pos);
monster_add_orb(m, 0, obj->y_pos - m->y_pos);
if (state == 0) {
obj->data.m.y_velocity = m->type2.unkE << 4;
const int dy = obj->y_pos - m->y_pos;
@ -174,7 +174,7 @@ static void monster_func1_type3(struct object_t *obj) {
obj->data.m.y_velocity = 32;
monster_change_next_anim(obj);
} else if (state == 1) {
monster_rotate_tiles(m, 0, obj->y_pos - m->y_pos);
monster_add_orb(m, 0, obj->y_pos - m->y_pos);
const uint16_t pos = ((obj->y_pos >> 4) << 8) | (obj->x_pos >> 4);
const uint8_t tile_num = g_res.leveldat[pos];
if (g_res.level.tile_attributes1[tile_num] == 0) {
@ -205,7 +205,7 @@ static void monster_func1_type4(struct object_t *obj) {
return;
}
const int dy = obj->y_pos - m->y_pos;
monster_rotate_tiles(m, 0, dy);
monster_add_orb(m, 0, dy);
if (m->type4.radius > dy) {
obj->y_pos += 2;
} else {

View File

@ -104,15 +104,15 @@ void load_leveldat(const uint8_t *p, struct level_t *level) {
gate->dst_pos = READ_LE_UINT16(p); p += 2;
gate->scroll_flag = *p++;
}
for (int i = 0; i < MAX_LEVEL_UNKS; ++i) {
struct level_unk_t *unk = &g_res.level.unks_tbl[i];
unk->tilemap_pos = READ_LE_UINT16(p); p += 2;
unk->w = *p++;
unk->h = *p++;
unk->unk4 = READ_LE_UINT16(p); p += 2;
unk->unk6 = READ_LE_UINT16(p); p += 2;
unk->unk8 = *p++;
unk->unk9 = *p++;
for (int i = 0; i < MAX_LEVEL_COLUMNS; ++i) {
struct level_column_t *column = &g_res.level.columns_tbl[i];
column->tilemap_pos = READ_LE_UINT16(p); p += 2;
column->w = *p++;
column->h = *p++;
column->trigger_pos = READ_LE_UINT16(p); p += 2;
column->tiles_offset_buf = READ_LE_UINT16(p); p += 2;
column->y_target = *p++;
column->unk9 = *p++;
}
const uint8_t *monster_attr = p;
int monsters_count = 0;
@ -251,7 +251,7 @@ void load_leveldat(const uint8_t *p, struct level_t *level) {
}
g_res.level.boss_xmin = READ_LE_UINT16(p); p += 2;
g_res.level.boss_xmax = READ_LE_UINT16(p); p += 2;
g_res.level.boss_counter = *p++;
g_res.level.boss_speed = *p++;
g_res.level.boss_energy = READ_LE_UINT16(p); p += 2;
g_res.level.boss_state = *p++;
g_res.level.boss_x_pos = READ_LE_UINT16(p); p += 2;

View File

@ -11,13 +11,13 @@ struct level_gate_t {
uint8_t scroll_flag;
};
struct level_unk_t {
uint16_t tilemap_pos;
struct level_column_t {
uint16_t tilemap_pos; /* current column tilemap pos */
uint8_t w;
uint8_t h;
uint16_t unk4;
uint16_t unk6;
uint8_t unk8;
uint16_t trigger_pos; /* compared with player pos */
uint16_t tiles_offset_buf;
uint8_t y_target; /* final y pos */
uint8_t unk9;
};
@ -123,7 +123,7 @@ struct level_monster_t {
};
#define MAX_LEVEL_GATES 20
#define MAX_LEVEL_UNKS 15
#define MAX_LEVEL_COLUMNS 15
#define MAX_LEVEL_BONUSES 80
#define MAX_LEVEL_ITEMS 70
#define MAX_LEVEL_PLATFORMS 16
@ -140,7 +140,7 @@ struct level_t {
uint16_t scrolling_mask; /* 4: screen scroll down 1 line, 2: no horizontal scrolling, 1: wider vertical scrolling */
uint16_t front_tiles_lut[256];
struct level_gate_t gates_tbl[MAX_LEVEL_GATES];
struct level_unk_t unks_tbl[MAX_LEVEL_UNKS];
struct level_column_t columns_tbl[MAX_LEVEL_COLUMNS];
struct level_monster_t monsters_tbl[MAX_LEVEL_MONSTERS];
uint8_t monsters_count;
uint16_t items_spr_num_offset;
@ -151,8 +151,8 @@ struct level_t {
struct level_platform_t platforms_tbl[MAX_LEVEL_PLATFORMS];
uint16_t boss_xmin;
uint16_t boss_xmax;
uint8_t boss_counter;
uint16_t boss_energy;
uint8_t boss_speed; /* 0..4 */
int16_t boss_energy;
uint8_t boss_state; /* !=255: has boss */
uint16_t boss_x_pos;
uint16_t boss_y_pos;

View File

@ -195,9 +195,6 @@ void video_load_front_tiles() {
}
}
void video_wait_vbl() {
}
void video_transition_close() {
}
@ -272,3 +269,7 @@ void video_load_sprites() {
void video_draw_sprite(int num, int x, int y, int flag) {
g_sys.render_add_sprite(RENDER_SPR_GAME, num, x, y, flag != 0);
}
void video_put_pixel(int x, int y, uint8_t color) {
g_res.vga[y * GAME_SCREEN_W + x] = color;
}