level messages and level sequence (1-10)
This commit is contained in:
parent
dcaaec7fb1
commit
c664b930f2
|
@ -24,6 +24,9 @@ set(ASSETS
|
|||
assets-cg/level/level5.txt
|
||||
assets-cg/level/level6.txt
|
||||
assets-cg/level/level7.txt
|
||||
assets-cg/level/level8.txt
|
||||
assets-cg/level/level9.txt
|
||||
assets-cg/level/level10.txt
|
||||
)
|
||||
|
||||
fxconv_declare_converters(converters.py)
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 925 B After Width: | Height: | Size: 939 B |
|
@ -1,4 +1,4 @@
|
|||
#it's good to see you.\nStay close to me and don't touch anything.
|
||||
#It's good to see you.\n\nStay close to me and\ndon't touch anything.
|
||||
long_vertical middle
|
||||
|
||||
left
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#This will be easy.\nJuste hold left...
|
||||
#This will be easy.\nJust hold left...
|
||||
left
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#There are some things worth fightinh for
|
||||
#There are some things\nworth fighting for.
|
||||
right
|
||||
|
||||
middle
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
#denial
|
||||
#This will be full of unexpected twists and turns
|
||||
#This will be full of\nunexpected twists and turns.
|
||||
middle rotate
|
||||
|
|
|
@ -9,8 +9,11 @@ def convert(input, output, params, target):
|
|||
|
||||
def convert_level(input, output, params, target):
|
||||
with open(input, "r") as fp:
|
||||
lines = fp.read().split("\n")
|
||||
lines = [tempo.split(",") for tempo in lines if not tempo.startswith("#")]
|
||||
raw = fp.read().split("\n")
|
||||
lines = [tempo.split(",") for tempo in raw if not tempo.startswith("#")]
|
||||
messages = [l[1:].strip() for l in raw if l.startswith("#")]
|
||||
message = "\n".join(l.replace("\\n", "\n") for l in messages)
|
||||
print(message)
|
||||
|
||||
blocks = bytes()
|
||||
block_count = 0
|
||||
|
@ -62,6 +65,14 @@ def convert_level(input, output, params, target):
|
|||
position = 2
|
||||
|
||||
# Implicit rules
|
||||
|
||||
# Rotating in the middle -> long
|
||||
if shape < 0 and position == 2 and action in [1, 2]:
|
||||
shape = 5
|
||||
# In the middle -> medium
|
||||
if shape < 0 and position == 2:
|
||||
shape = 3
|
||||
# No properties whatsoever -> normal
|
||||
if shape < 0 and action == 0:
|
||||
shape = 4
|
||||
|
||||
|
@ -76,6 +87,7 @@ def convert_level(input, output, params, target):
|
|||
|
||||
o = fxconv.ObjectData()
|
||||
o += fxconv.u32(0x3f800000) # 1.0 as a float
|
||||
o += fxconv.ref(bytes(message, 'utf-8') + bytes(1), padding=4)
|
||||
o += fxconv.u32(block_count)
|
||||
o += fxconv.ref(blocks)
|
||||
|
||||
|
|
15
src/duet.h
15
src/duet.h
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
float tempo;
|
||||
const char *message;
|
||||
int block_count;
|
||||
rectmeta_t *blocks;
|
||||
} level_t;
|
||||
|
@ -60,7 +61,7 @@ typedef struct {
|
|||
#define PLAYER_X 60
|
||||
#define PLAYER_R 40
|
||||
#define PLAYER_SIZE 8
|
||||
#define CORRIDOR_SIZE 138
|
||||
#define CORRIDOR_SIZE 150
|
||||
|
||||
#define RECT_SPEED 50 /* px/tempo */
|
||||
|
||||
|
@ -76,7 +77,7 @@ typedef struct {
|
|||
typedef struct game {
|
||||
int dead;
|
||||
float time;
|
||||
level_t *level;
|
||||
level_t const *level;
|
||||
rectmeta_t const *current;
|
||||
|
||||
rect_t table[RECT_TABLE_SIZE];
|
||||
|
@ -123,10 +124,6 @@ void rect_physics(rect_t *r, rectmeta_t const *meta, float time);
|
|||
// Levels
|
||||
//---
|
||||
|
||||
extern level_t level1;
|
||||
extern level_t level2;
|
||||
extern level_t level3;
|
||||
extern level_t level4;
|
||||
extern level_t level5;
|
||||
extern level_t level6;
|
||||
extern level_t level7;
|
||||
extern level_t level1, level2, level3, level4;
|
||||
extern level_t level5, level6, level7, level8;
|
||||
extern level_t level9, level10;
|
||||
|
|
64
src/main.c
64
src/main.c
|
@ -3,6 +3,7 @@
|
|||
#include <gint/timer.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/cpu.h>
|
||||
#include <gint/drivers/r61524.h>
|
||||
|
||||
#include <fxlibc/printf.h>
|
||||
#include <string.h>
|
||||
|
@ -33,27 +34,51 @@ level_t level0 = {
|
|||
}
|
||||
};
|
||||
|
||||
void load_level(game_t *game, level_t const *lv)
|
||||
{
|
||||
memset(game, 0x00, sizeof *game);
|
||||
game->level = lv;
|
||||
game->current = lv->blocks;
|
||||
game->time = -10.0;
|
||||
}
|
||||
|
||||
int strcount(char const *str, int c)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i = 0; str[i]; i++)
|
||||
count += (str[i] == c);
|
||||
return count;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
__printf_enable_fp();
|
||||
|
||||
/* Azur trickz */
|
||||
r61524_set(0x010, 0x0010);
|
||||
|
||||
level_t const *story_levels[] = {
|
||||
&level1, &level2, &level3, &level4, &level5, &level6, &level7,
|
||||
&level8, &level9, &level10, NULL,
|
||||
};
|
||||
int story_position = 0;
|
||||
|
||||
game_t game;
|
||||
memset(&game, 0x00, sizeof game);
|
||||
game.level = &level4;
|
||||
game.current = game.level->blocks;
|
||||
game.time = -5.0;
|
||||
load_level(&game, story_levels[story_position]);
|
||||
|
||||
volatile int need_frame = 1;
|
||||
int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame));
|
||||
timer_start(timer);
|
||||
|
||||
while (1) {
|
||||
level_t const *lv = game.level;
|
||||
|
||||
/* Time management */
|
||||
|
||||
while (need_frame == 0) sleep();
|
||||
need_frame = 0;
|
||||
|
||||
float dt = (1.0 / 30) * game.level->tempo * 2.7;
|
||||
float dt = (1.0 / 30) * lv->tempo * 2.7;
|
||||
game.time += dt;
|
||||
|
||||
/* Input analysis */
|
||||
|
@ -84,7 +109,7 @@ int main(void)
|
|||
|
||||
// Find rectangles that need to be loaded, 10 tempo in advance
|
||||
rectmeta_t const *meta = game.current;
|
||||
while(meta < game.level->blocks + game.level->block_count) {
|
||||
while(meta < lv->blocks + lv->block_count) {
|
||||
if(meta - game.current > RECT_TABLE_SIZE - game.cursor)
|
||||
break; /* oops, not enough array space left */
|
||||
if(meta->time - 10 > game.time)
|
||||
|
@ -100,9 +125,14 @@ int main(void)
|
|||
}
|
||||
|
||||
// End of level
|
||||
if(game.current >= game.level->blocks + game.level->block_count
|
||||
&& game.cursor == 0)
|
||||
break;
|
||||
if(game.current >= lv->blocks + lv->block_count && game.cursor == 0) {
|
||||
if(story_levels[++story_position] == NULL)
|
||||
break;
|
||||
|
||||
load_level(&game, story_levels[story_position]);
|
||||
need_frame = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Physics */
|
||||
|
||||
|
@ -122,9 +152,19 @@ int main(void)
|
|||
|
||||
dclear(player_collision(&game) ? C_RED : C_BLACK);
|
||||
|
||||
if(game.time < -2)
|
||||
duet_text_opt(DWIDTH*3/4, DHEIGHT/2, C_WHITE, C_NONE, DTEXT_CENTER,
|
||||
DTEXT_MIDDLE, "Change is inevitable.", -1);
|
||||
if(game.time < -5 && lv->message != NULL) {
|
||||
int x = DWIDTH/2 + 8 * (strcount(lv->message, '\n') + 1);
|
||||
|
||||
/* Split at newlines */
|
||||
char const *str = lv->message;
|
||||
while(*str) {
|
||||
char const *end = strchrnul(str, '\n');
|
||||
duet_text_opt(x, DHEIGHT/2, C_WHITE, C_NONE, DTEXT_CENTER,
|
||||
DTEXT_MIDDLE, str, end - str);
|
||||
x -= 16;
|
||||
str = end + (*end != 0);
|
||||
}
|
||||
}
|
||||
|
||||
render_player(game.player_rota);
|
||||
for(int i = 0; i < game.cursor; i++)
|
||||
|
|
|
@ -70,7 +70,7 @@ void rect_load(rect_t *r, rectmeta_t const *meta)
|
|||
break;
|
||||
case Shape_MediumBar:
|
||||
r->w = 0.2;
|
||||
r->h = 0.65;
|
||||
r->h = 0.62;
|
||||
break;
|
||||
case Shape_NormalBar:
|
||||
r->w = 0.2;
|
||||
|
|
10
src/render.c
10
src/render.c
|
@ -81,12 +81,16 @@ void dtriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color)
|
|||
|
||||
void drectoid(rect_t const *r, int color)
|
||||
{
|
||||
float sin, cos;
|
||||
sincosf(r->r, &sin, &cos);
|
||||
|
||||
float x0[4] = { r->w/2, -r->w/2, -r->w/2, r->w/2 };
|
||||
float y0[4] = { -r->h/2, -r->h/2, r->h/2, r->h/2 };
|
||||
|
||||
if(r->r == 0) {
|
||||
drect(r->x+x0[1], r->y+y0[1], r->x+x0[3], r->y+y0[3], color);
|
||||
return;
|
||||
}
|
||||
|
||||
float sin, cos;
|
||||
sincosf(r->r, &sin, &cos);
|
||||
int x[4], y[4];
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
|
|
43
src/text.c
43
src/text.c
|
@ -14,27 +14,23 @@ uint32_t topti_utf8_next(uint8_t const **str_pointer);
|
|||
|
||||
This function assumes that at least one of [fg] and [bg] is not transparent.
|
||||
|
||||
@vram Target position on VRAM, adjusted to [top] and [left]
|
||||
@x0 @y0 Target position on VRAM
|
||||
@data Glyph data
|
||||
@left Left-position of subglyph
|
||||
@top Top-Position of subglyph
|
||||
@width Subglyph width
|
||||
@height Subglyph height
|
||||
@dataw Glyph width
|
||||
@datah Total font height
|
||||
@fg @bg Foreground and background colors */
|
||||
static void topti_glyph(uint16_t *vram, uint32_t const * data, int left,
|
||||
int top, int width, int height, int dataw, int datah, int fg, int bg)
|
||||
static void topti_glyph(int x0, int y0, uint32_t const * data, int width,
|
||||
int height, int fg, int bg)
|
||||
{
|
||||
/* A C version of what is usually done in assembler */
|
||||
for(int y = 0; y < height; y++) {
|
||||
for(int x = 0; x < width; x++) {
|
||||
int bit_number = (top + y) * dataw + (left + x);
|
||||
int bit_number = y * width + x;
|
||||
int bit = (data[bit_number >> 5] >> (31 - (bit_number & 31))) & 1;
|
||||
|
||||
/* Swithing x -> datah-y-1 and y -> x here gives vertical glyphs */
|
||||
/* Swithing x->height-y-1 and y->x here gives vertical glyphs */
|
||||
if((bit ? fg : bg) != C_NONE)
|
||||
vram[DWIDTH*x + (datah-y-1)] = bit ? fg : bg;
|
||||
dpixel(x0 + (height-y-1), y0 + x, bit ? fg : bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,14 +44,6 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
|
|||
/* Raw glyph data */
|
||||
uint32_t const *data = f->data;
|
||||
|
||||
/* Storage height, top position within glyph */
|
||||
int height = f->data_height, top = 0;
|
||||
|
||||
/* Vertical clipping */
|
||||
if(x > 395 || y > 223 || y + height <= 0) return;
|
||||
if(y + height > 224) height = 224 - y;
|
||||
if(y < 0) top = -y, height += y, y = 0;
|
||||
|
||||
/* Character spacing waiting to be drawn, in pixels */
|
||||
int space = 0;
|
||||
|
||||
|
@ -71,29 +59,14 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
|
|||
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
|
||||
|
||||
/* Draw character spacing if background is opaque */
|
||||
if(space && bg >= 0) drect(x, y, x+height-1, y+space-1, bg);
|
||||
if(space && bg >= 0) drect(x, y, x+f->data_height-1, y+space-1, bg);
|
||||
y += space;
|
||||
if(y >= DHEIGHT) break;
|
||||
|
||||
int index = topti_offset(f, glyph);
|
||||
|
||||
/* Compute horizontal intersection between glyph and screen */
|
||||
|
||||
int width = dataw, left = 0;
|
||||
|
||||
if(y + dataw <= 0)
|
||||
{
|
||||
y += dataw;
|
||||
space = f->char_spacing;
|
||||
continue;
|
||||
}
|
||||
if(y < 0) left = -y, width += y;
|
||||
if(y + width > DHEIGHT) width = DHEIGHT - y;
|
||||
|
||||
/* Render glyph */
|
||||
|
||||
topti_glyph(gint_vram + 396 * y + x, data + index, left, top, width,
|
||||
height, dataw, f->data_height, fg, bg);
|
||||
topti_glyph(x, y, data + index, dataw, f->data_height, fg, bg);
|
||||
|
||||
/* Switching x -> y here (and some other places, but mostly here) gives
|
||||
vertical text */
|
||||
|
|
Loading…
Reference in New Issue