Compare commits
3 Commits
b147f74822
...
83a508598d
Author | SHA1 | Date |
---|---|---|
Lephenixnoir | 83a508598d | |
Lephenixnoir | 87a6d28957 | |
Lephenixnoir | 357168205c |
29
src/game.cpp
29
src/game.cpp
|
@ -176,12 +176,24 @@ void game_advance(struct game *game)
|
|||
}
|
||||
}
|
||||
|
||||
static bool standable(struct platform const &p)
|
||||
{
|
||||
return p.type != PLATFORM_SEPARATING_WALL
|
||||
&& p.type != PLATFORM_BLOCK
|
||||
&& p.type != PLATFORM_BLOCK_TOP;
|
||||
}
|
||||
|
||||
static bool collidable(struct platform const &p)
|
||||
{
|
||||
return p.type == PLATFORM_BLOCK_TOP;
|
||||
}
|
||||
|
||||
num game_height_at(struct game *game, num z, int face)
|
||||
{
|
||||
num max_h = -KILL_PLANE_RADIUS;
|
||||
|
||||
for(auto const &p: game->level.platform_buffer) {
|
||||
if(p.face == face && z >= p.z && z <= p.z + p.length)
|
||||
if(standable(p) && p.face == face && z >= p.z && z <= p.z + p.length)
|
||||
max_h = (max_h >= p.height) ? max_h : p.height;
|
||||
}
|
||||
|
||||
|
@ -195,7 +207,20 @@ struct platform *game_platform_under_player(struct game *game,
|
|||
return NULL;
|
||||
|
||||
for(auto &p: game->level.platform_buffer) {
|
||||
if(player->platform == p.face
|
||||
if(standable(p) && player->platform == p.face
|
||||
&& player->z >= p.z && player->z <= p.z + p.length) {
|
||||
return &p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct platform *game_block_hitting_player(struct game *game,
|
||||
struct player const *player)
|
||||
{
|
||||
for(auto &p: game->level.platform_buffer) {
|
||||
if(collidable(p) && player->platform == p.face
|
||||
&& player->z >= p.z && player->z <= p.z + p.length) {
|
||||
return &p;
|
||||
}
|
||||
|
|
|
@ -134,4 +134,8 @@ num game_height_at(struct game *game, num z, int face);
|
|||
struct platform *game_platform_under_player(struct game *game,
|
||||
struct player const *player);
|
||||
|
||||
/* Returns the block platform that the player is hitting, if any. */
|
||||
struct platform *game_block_hitting_player(struct game *game,
|
||||
struct player const *player);
|
||||
|
||||
#endif /* __GAME_H__ */
|
||||
|
|
|
@ -57,7 +57,7 @@ struct MultiPathCarver
|
|||
void force_to_match(int face);
|
||||
|
||||
/* Add the next set of platforms (all at z) to the level. */
|
||||
void next(struct level *level, num z, num length);
|
||||
void next(struct level *level, num z, num length, num height=0.0);
|
||||
|
||||
private:
|
||||
struct Path {
|
||||
|
@ -134,6 +134,7 @@ struct AcceleronGenerator: public Generator
|
|||
|
||||
num generate_ascending_funnel(struct level *level, num z);
|
||||
num generate_tunnel_block(struct level *level, num z, int sections);
|
||||
num generate_fractured_tunnel(struct level *level, num z, int sections);
|
||||
|
||||
void change_phase(void);
|
||||
|
||||
|
@ -143,13 +144,21 @@ struct AcceleronGenerator: public Generator
|
|||
MultiPathCarver m_checkerboard_carver;
|
||||
};
|
||||
|
||||
struct gen3: public Generator
|
||||
struct RadionGenerator: public Generator
|
||||
{
|
||||
gen3();
|
||||
RadionGenerator();
|
||||
void generate(struct level *) override;
|
||||
~gen3() override = default;
|
||||
~RadionGenerator() override = default;
|
||||
|
||||
path_carver m_path_carvers[3];
|
||||
num generate_blue_spiral(struct level *level, num z);
|
||||
num generate_ascending_grid(struct level *level, num z);
|
||||
|
||||
void change_phase(void);
|
||||
|
||||
num m_z;
|
||||
bool m_initial;
|
||||
int m_phase;
|
||||
MultiPathCarver m_multi_carver;
|
||||
};
|
||||
|
||||
#endif /* GENERATOR_H */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define P_ASCF_RED num(0.2)
|
||||
#define P_TUNNEL_RED num(0.2)
|
||||
#define P_TUNNEL_RED_RING num(0.15)
|
||||
#define P_TUNNEL_BLUE num(0.05)
|
||||
|
||||
AcceleronGenerator::AcceleronGenerator():
|
||||
m_checkerboard_carver{3}
|
||||
|
@ -123,6 +124,16 @@ num AcceleronGenerator::generate_ascending_funnel(struct level *level, num z)
|
|||
return z;
|
||||
}
|
||||
|
||||
static platform_type_t tunnel_type(void)
|
||||
{
|
||||
if(num_rand() <= P_TUNNEL_BLUE)
|
||||
return PLATFORM_BLUE;
|
||||
else if(num_rand() <= P_TUNNEL_RED)
|
||||
return PLATFORM_RED;
|
||||
else
|
||||
return PLATFORM_WHITE;
|
||||
}
|
||||
|
||||
/* Generates a tunnel block, which is full ring alternating with half rings.
|
||||
The total length (which should be odd) is specified as a parameter.
|
||||
|
||||
|
@ -133,8 +144,8 @@ num AcceleronGenerator::generate_ascending_funnel(struct level *level, num z)
|
|||
########## [h=0]
|
||||
(...repeats)
|
||||
|
||||
There is a random probability for any of the platforms to be red, and also a
|
||||
random probability for entire rings to be red. */
|
||||
There is a random probability for any of the platforms to be red or blue,
|
||||
and also a random probability for entire rings to be red. */
|
||||
|
||||
num AcceleronGenerator::generate_tunnel_block(struct level *level, num z,
|
||||
int sec)
|
||||
|
@ -151,7 +162,7 @@ num AcceleronGenerator::generate_tunnel_block(struct level *level, num z,
|
|||
continue;
|
||||
|
||||
struct platform p;
|
||||
p.type = (num_rand() <= P_TUNNEL_RED) ? PLATFORM_RED : type;
|
||||
p.type = (type == PLATFORM_WHITE) ? tunnel_type() : type;
|
||||
p.face = j;
|
||||
p.z = z;
|
||||
p.length = len;
|
||||
|
@ -164,6 +175,55 @@ num AcceleronGenerator::generate_tunnel_block(struct level *level, num z,
|
|||
return z;
|
||||
}
|
||||
|
||||
/* Generates a fractured tunnel, which is a full ring followed by random-length
|
||||
platforms varying between 0 and 3 units. This is repeated for as many
|
||||
sections as requested.
|
||||
|
||||
0123456789
|
||||
########## [h=0]
|
||||
##..###.## [h=0]
|
||||
||#.||.#|.
|
||||
.|..|..|..
|
||||
(...repeats)
|
||||
|
||||
There is a random probability for any of the platforms to be red or blue. */
|
||||
num AcceleronGenerator::generate_fractured_tunnel(struct level *level, num z,
|
||||
int sec)
|
||||
{
|
||||
for(int i = 0; i < sec; i++) {
|
||||
/* Initial ring */
|
||||
for(int j = 0; j < PLATFORM_COUNT; j++) {
|
||||
struct platform p;
|
||||
p.type = tunnel_type();
|
||||
p.face = j;
|
||||
p.z = z;
|
||||
p.length = G_PLATFORM_LEN;
|
||||
p.height = 0;
|
||||
add(level, p);
|
||||
}
|
||||
|
||||
/* Fractured ring */
|
||||
for(int j = 0; j < PLATFORM_COUNT; j++) {
|
||||
int start = (num_rand() <= num(0.3)) ? 1 : 0;
|
||||
int length = rand() % (4 - start);
|
||||
if(!length)
|
||||
continue;
|
||||
|
||||
struct platform p;
|
||||
p.type = tunnel_type();
|
||||
p.face = j;
|
||||
p.z = z + (start + 1) * G_PLATFORM_LEN;
|
||||
p.length = length * G_PLATFORM_LEN;
|
||||
p.height = 0;
|
||||
add(level, p);
|
||||
}
|
||||
|
||||
z += 4 * G_PLATFORM_LEN;
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
void AcceleronGenerator::change_phase(void)
|
||||
{
|
||||
static int const freq_table[] = {
|
||||
|
@ -253,7 +313,7 @@ void AcceleronGenerator::generate(struct level *level)
|
|||
|
||||
where you can't side-jump from the middle platform to the left
|
||||
one because the wall prevents it. */
|
||||
bool walls = (i == 2 || i == 5 || i == 8 || i == 1);
|
||||
bool walls = (i == 2 || i == 5 || i == 8 || i == 11);
|
||||
|
||||
/* Start by excluding platforms from iteration #i */
|
||||
if(walls) {
|
||||
|
@ -265,7 +325,9 @@ void AcceleronGenerator::generate(struct level *level)
|
|||
}
|
||||
|
||||
/* Advance */
|
||||
m_checkerboard_carver.next(level, m_z, G_PLATFORM_LEN);
|
||||
int height = (i == 13) ? 2 : (i == 12) ? 1 : (i / 3);
|
||||
m_checkerboard_carver.next(level, m_z, G_PLATFORM_LEN,
|
||||
height * PLATFORM_HEIGHT_STEP);
|
||||
|
||||
/* Generate blocks and walls */
|
||||
if(walls) {
|
||||
|
@ -309,21 +371,13 @@ void AcceleronGenerator::generate(struct level *level)
|
|||
|
||||
/* Phase #4: Incomplete tunnel block */
|
||||
else if(m_phase == 4) {
|
||||
// TODO
|
||||
m_z = this->generate_fractured_tunnel(level, m_z, 3);
|
||||
this->change_phase();
|
||||
}
|
||||
|
||||
/* Phase #1: Almost-full tunnel with random holes? */
|
||||
|
||||
/* Phase #2: Path with spacing + random onlookers */
|
||||
|
||||
/* Phase #3: Full + odd + even tunnel combination leading into #0 */
|
||||
|
||||
|
||||
/* Phase #5: Obstacles
|
||||
/* Phase #5: Fixed obstacles
|
||||
- ##.##.#.#.
|
||||
- .##.##.#.#
|
||||
- ..#..#..#.
|
||||
- .#..#..#.. */
|
||||
|
||||
}
|
||||
|
|
|
@ -2,19 +2,166 @@
|
|||
#include "../level.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N PLATFORM_COUNT
|
||||
/* Geometric parameters */
|
||||
#define G_PLATFORM_LEN num(1.5)
|
||||
#define G_PLATFORM_SPC num(0.5)
|
||||
#define G_PLATFORM_LEN_INITIAL num(6.0)
|
||||
|
||||
gen3::gen3(): m_path_carvers{{0}, {N/3}, {2*N/3}}
|
||||
RadionGenerator::RadionGenerator():
|
||||
m_multi_carver{3}
|
||||
{
|
||||
srand(123456);
|
||||
m_initial = true;
|
||||
m_z = 0.0;
|
||||
m_phase = 0;
|
||||
|
||||
int faces[3] = { 0, 4, 8 };
|
||||
m_multi_carver.set_faces(faces);
|
||||
m_multi_carver.set_noskip(false);
|
||||
m_multi_carver.set_checkerboard(false);
|
||||
}
|
||||
|
||||
void gen3::generate(struct level *level)
|
||||
/* Generate a blue/white spiral going full circle.
|
||||
|
||||
0123456789
|
||||
.........B
|
||||
........B|
|
||||
.......B|.
|
||||
......B|.#
|
||||
.....B|.#|
|
||||
....B|.#|.
|
||||
...B|.#|..
|
||||
..B|.#|...
|
||||
.B|.#|....
|
||||
B|.#|.....
|
||||
|.#|.....#
|
||||
.#|......|
|
||||
#|........
|
||||
|......... */
|
||||
num RadionGenerator::generate_blue_spiral(struct level *level, num z)
|
||||
{
|
||||
struct platform p;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
if(m_path_carvers[i].next(3.0, &p)) {
|
||||
level->platform_buffer.push_back(p);
|
||||
for(int i = 0; i < 14; i++) {
|
||||
if(i < 10) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_BLUE;
|
||||
p.face = PLATFORM_COUNT - 1 - i;
|
||||
p.z = z;
|
||||
p.length = 2 * G_PLATFORM_LEN;
|
||||
p.height = 0.0;
|
||||
add(level, p);
|
||||
}
|
||||
if(i >= 3 && i <= 12) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = PLATFORM_COUNT - 1 - (i - 3);
|
||||
p.z = z;
|
||||
p.length = 2 * G_PLATFORM_LEN;
|
||||
p.height = 0.0;
|
||||
add(level, p);
|
||||
}
|
||||
if(i == 10) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = PLATFORM_COUNT - 1;
|
||||
p.z = z;
|
||||
p.length = 2 * G_PLATFORM_LEN;
|
||||
p.height = 0.0;
|
||||
add(level, p);
|
||||
}
|
||||
|
||||
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
/* Generate an ascending grid leading up to step #4.
|
||||
|
||||
0123456789
|
||||
#.#.#.#.#. [h=0]
|
||||
.#.#.#.#.# [h=1]
|
||||
#.#.#.#.#. [h=2]
|
||||
.#.#.#.#.# [h=3]
|
||||
#.#.#.#.#. [h=4]
|
||||
.#.#.#.#.# [h=4]
|
||||
#.#.#.#.#. [h=4]
|
||||
BBBBBBBBBB [h=4]
|
||||
|||||||||| [h=4]
|
||||
.#.#.#.#.# [h=4]
|
||||
#.#.#.#.#. [h=1] */
|
||||
num RadionGenerator::generate_ascending_grid(struct level *level, num z)
|
||||
{
|
||||
for(int i = 0; i < 11; i++) {
|
||||
int height = (i <= 4) ? i : (i == 10) ? 1 : 4;
|
||||
|
||||
for(int j = 0; j < 10; j++) {
|
||||
if((i != 7) && ((i & 1) != (j & 1)))
|
||||
continue;
|
||||
|
||||
struct platform p;
|
||||
p.type = (i == 7) ? PLATFORM_BLUE : PLATFORM_WHITE;
|
||||
p.face = j;
|
||||
p.z = z;
|
||||
p.length = (i == 7 ? 4 : 2) * G_PLATFORM_LEN;
|
||||
p.height = height * PLATFORM_HEIGHT_STEP;
|
||||
add(level, p);
|
||||
}
|
||||
|
||||
z += 2 * G_PLATFORM_LEN;
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
void RadionGenerator::change_phase(void)
|
||||
{
|
||||
static int const freq_table[] = {
|
||||
0,
|
||||
1,
|
||||
};
|
||||
int const FREQ_TABLE_SIZE = sizeof freq_table / sizeof freq_table[0];
|
||||
|
||||
int p = m_phase;
|
||||
|
||||
while(1) {
|
||||
p = freq_table[rand() % FREQ_TABLE_SIZE];
|
||||
|
||||
/* Do not repeat the same phase twice in a row */
|
||||
if(p == m_phase)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
m_phase = p;
|
||||
}
|
||||
|
||||
void RadionGenerator::generate(struct level *level)
|
||||
{
|
||||
/* m_multi_carver.next(level, m_z, G_PLATFORM_LEN);
|
||||
m_z += G_PLATFORM_LEN;
|
||||
*/
|
||||
/* Friendly platform at start of level */
|
||||
if(m_initial) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = 0;
|
||||
p.z = m_z;
|
||||
p.length = G_PLATFORM_LEN_INITIAL;
|
||||
p.height = 0.0;
|
||||
|
||||
add(level, p);
|
||||
m_z += p.length;
|
||||
m_initial = false;
|
||||
m_phase = 0;
|
||||
}
|
||||
|
||||
if(m_phase == 0) {
|
||||
m_z = this->generate_blue_spiral(level, m_z);
|
||||
this->change_phase();
|
||||
}
|
||||
else if(m_phase == 1) {
|
||||
m_z = this->generate_ascending_grid(level, m_z);
|
||||
this->change_phase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ void MultiPathCarver::force_to_match(int face)
|
|||
}
|
||||
}
|
||||
|
||||
void MultiPathCarver::next(struct level *level, num z, num length)
|
||||
void MultiPathCarver::next(struct level *level, num z, num length, num height)
|
||||
{
|
||||
/* Decide whether to skip */
|
||||
for(int i = 0; i < m_N; i++) {
|
||||
|
@ -108,7 +108,7 @@ void MultiPathCarver::next(struct level *level, num z, num length)
|
|||
p.face = face;
|
||||
p.z = z;
|
||||
p.length = length;
|
||||
p.height = 0;
|
||||
p.height = height;
|
||||
p.type = PLATFORM_WHITE;
|
||||
level->platform_buffer.push_back(p);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ struct level level_create(int level)
|
|||
break;
|
||||
case 3:
|
||||
l.name = "radion";
|
||||
l.gen = std::make_unique<struct gen3>();
|
||||
l.bgcolor = C_WHITE;
|
||||
l.gen = std::make_unique<RadionGenerator>();
|
||||
l.bgcolor = RGB24(0xe17c6a);
|
||||
break;
|
||||
}
|
||||
return l;
|
||||
|
|
|
@ -155,8 +155,10 @@ int play_level(int level_id)
|
|||
level_update(&game.level, player->z, player->platform);
|
||||
camera_track(camera, player);
|
||||
|
||||
struct platform *standing_on = game_platform_under_player(&game,
|
||||
&game.player);
|
||||
struct platform *standing_on =
|
||||
game_platform_under_player(&game, &game.player);
|
||||
struct platform *hitting =
|
||||
game_block_hitting_player(&game, &game.player);
|
||||
|
||||
//======= Rendering =======//
|
||||
|
||||
|
@ -297,7 +299,8 @@ int play_level(int level_id)
|
|||
|
||||
/* Death condition #1/2: inside a platform (hit it in front) */
|
||||
bool death_1 = (player->height >= floor - PLAYER_HEIGHT &&
|
||||
player->height < floor - STEP_HEIGHT);
|
||||
player->height < floor - STEP_HEIGHT)
|
||||
|| (hitting != NULL);
|
||||
/* Death condition #2/2: below the kill plane */
|
||||
bool death_2 = (player->height < LEVEL_RADIUS - KILL_PLANE_RADIUS);
|
||||
|
||||
|
|
|
@ -153,8 +153,10 @@ uint16_t render_platform_color(struct platform const *p,
|
|||
return camera_platform_color(camera, p->face);
|
||||
if(p->type == PLATFORM_BLUE)
|
||||
return render_color_blue_platform(t);
|
||||
if(p->type == PLATFORM_SEPARATING_WALL || p->type == PLATFORM_BLOCK_TOP)
|
||||
if(p->type == PLATFORM_SEPARATING_WALL)
|
||||
return RGB24(0x909090);
|
||||
if(p->type == PLATFORM_BLOCK_TOP)
|
||||
return RGB24(0xa0a0a0);
|
||||
if(p->type == PLATFORM_BLOCK)
|
||||
return RGB24(0x808080);
|
||||
if(p->type == PLATFORM_RED) {
|
||||
|
|
Loading…
Reference in New Issue