// Game Boy Advance library for Logic Machines F'05 // Version 6, November 16th, 2005 // These includes come from libgba #include "gba_input.h" #include "gba_video.h" #include "gba_sprites.h" #include "gba_systemcalls.h" #include "gbaio.h" #include "gbamath.h" static void srand(void); static void load_web_palette(unsigned short *palette); static void init_sprites(void); static void init_numbers(void); // **************************************************************************************************** // Initialization void start_game(void) { srand(); start_drawing(); // set up video on the vblank so there are no screen glitches video_mode(3); init_sprites(); init_numbers(); } // **************************************************************************************************** // Input static unsigned short previous_buttons_down = 0, buttons_down = 0; void start_input(void) { previous_buttons_down = buttons_down; buttons_down = (REG_KEYINPUT ^ 0xFFFF); } int button_pressed(int which) { return (buttons_down & which) && !(previous_buttons_down & which); } int button_released(int which) { return !(buttons_down & which) && (previous_buttons_down & which); } int button_held(int which) { return (buttons_down & which) != 0; } // **************************************************************************************************** // Drawing static unsigned short display_control = 0x0000; static int free_tile; const static char shroom[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xAD, 0xAD, 0x00, 0x00, 0x00, 0xAD, 0xAD, 0x01, 0x01, 0x6C, 0x00, 0x00, 0xAD, 0x01, 0x01, 0x01, 0x24, 0x24, 0x00, 0xAD, 0x6C, 0x6C, 0x24, 0x24, 0x16, 0x16, 0x00, 0xAD, 0x6C, 0x24, 0x24, 0x16, 0x16, 0x16, 0xAD, 0x01, 0x24, 0x24, 0x16, 0x16, 0x01, 0x01, 0xAD, 0x01, 0x01, 0x24, 0x16, 0x01, 0x01, 0x01, 0xAD, 0x01, 0x01, 0x24, 0x16, 0x01, 0x01, 0x01, 0xAD, 0xAD, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x01, 0x01, 0xAD, 0xAD, 0x00, 0x00, 0x00, 0x24, 0x24, 0x01, 0x01, 0x01, 0xAD, 0x00, 0x00, 0x16, 0x16, 0x24, 0x24, 0x6C, 0x6C, 0xAD, 0x00, 0x16, 0x16, 0x16, 0x24, 0x24, 0x6C, 0xAD, 0x00, 0x01, 0x01, 0x16, 0x16, 0x24, 0x24, 0x01, 0xAD, 0x01, 0x01, 0x01, 0x16, 0x24, 0x01, 0x01, 0xAD, 0x01, 0x01, 0x01, 0x16, 0x24, 0x01, 0x01, 0xAD, 0xAD, 0x01, 0x24, 0x24, 0x24, 0x01, 0x01, 0x01, 0xAD, 0x6C, 0x24, 0x24, 0x6C, 0x6C, 0x01, 0x01, 0xAD, 0x6C, 0x6C, 0x6C, 0xAD, 0xAD, 0xAD, 0xAD, 0x00, 0xAD, 0xAD, 0xAD, 0x0F, 0x0F, 0xAD, 0x0F, 0x00, 0x00, 0xAD, 0x0F, 0x01, 0x01, 0xAD, 0x01, 0x00, 0x00, 0xAD, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0xAD, 0x0F, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xAD, 0xAD, 0xAD, 0x01, 0x01, 0x01, 0x24, 0x24, 0x24, 0x01, 0xAD, 0x01, 0x01, 0x6C, 0x6C, 0x24, 0x24, 0x6C, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0x6C, 0x6C, 0x6C, 0xAD, 0x0F, 0xAD, 0x0F, 0x0F, 0xAD, 0xAD, 0xAD, 0x00, 0x01, 0xAD, 0x01, 0x01, 0x0F, 0xAD, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x0F, 0xAD, 0x00, 0x00, 0x01, 0x01, 0x01, 0x0F, 0xAD, 0x00, 0x00, 0x00, 0xAD, 0xAD, 0xAD, 0xAD, 0x00, 0x00, 0x00, 0x00 }; static void init_sprites(void) { int sprite; load_web_palette(OBJ_COLORS); load_image(511, shroom, IMAGE_16x16); for (sprite = 0; sprite < 128; ++sprite) { set_sprite_image(sprite, 511); draw_sprite(sprite, 240, 160); // off screen } display_control |= OBJ_1D_MAP | OBJ_ENABLE; REG_DISPCNT = display_control; } int start_drawing(void) { int count = 0; while ((REG_DISPSTAT & LCDC_VBL_FLAG)) ++count; while (!(REG_DISPSTAT & LCDC_VBL_FLAG)) ++count; return count; } const static unsigned char num_tiles_table[] = { 2, // IMAGE_8x8 8, // IMAGE_16x16 32, // IMAGE_32x32 128, // IMAGE_64x64 4, // IMAGE_16x8 8, // IMAGE_32x8 16, // IMAGE_32x16 64, // IMAGE_64x32 4, // IMAGE_8x16 8, // IMAGE_8x32 16, // IMAGE_16x32 64 // IMAGE_32x64 }; const static unsigned char size0_table[] = { 0, // IMAGE_8x8 0, // IMAGE_16x16 0, // IMAGE_32x32 0, // IMAGE_64x64 1, // IMAGE_16x8 1, // IMAGE_32x8 1, // IMAGE_32x16 1, // IMAGE_64x32 2, // IMAGE_8x16 2, // IMAGE_8x32 2, // IMAGE_16x32 2 // IMAGE_32x64 }; const static unsigned char size1_table[] = { 0, // IMAGE_8x8 1, // IMAGE_16x16 2, // IMAGE_32x32 3, // IMAGE_64x64 0, // IMAGE_16x8 1, // IMAGE_32x8 2, // IMAGE_32x16 3, // IMAGE_64x32 0, // IMAGE_8x16 1, // IMAGE_8x32 2, // IMAGE_16x32 3 // IMAGE_32x64 }; static unsigned int image_tile[512]; static unsigned char image_size[512]; void load_image(int image_number, const char *image, int size) { int tile, num_tiles; void *dest; tile = free_tile; num_tiles = num_tiles_table[size]; dest = OBJ_BASE_ADR + (tile * 32); CpuFastSet(image, dest, num_tiles * 32); free_tile += num_tiles; image_tile[image_number] = tile; image_size[image_number] = size; } void set_sprite_image(int sprite_number, int image_number) { OBJATTR *s; unsigned int tile, size; tile = image_tile[image_number]; size = image_size[image_number]; s = &OAM[sprite_number]; s->attr0 = (s->attr0 & 0x1FFF) | OBJ_256_COLOR | OBJ_SHAPE((unsigned int)size0_table[size]); s->attr1 = (s->attr1 & 0x3FFF) | OBJ_SIZE((unsigned int)size1_table[size]); s->attr2 = (s->attr2 & 0xFC00) | tile; } void draw_sprite(int sprite_number, int x, int y) { OBJATTR *s; s = &OAM[sprite_number]; s->attr0 = (s->attr0 & 0xFF00) | (y & 0xFF); s->attr1 = (s->attr1 & 0xFE00) | (x & 0x1FF); } void set_transform_rotation(int transform_number, real angle) { OBJAFFINE *a; s16 c, s; c = cosr(angle) >> (REAL_SHIFT - 8); s = sinr(angle) >> (REAL_SHIFT - 8); a = &((OBJAFFINE *)OAM)[transform_number]; a->pa = c; a->pb = -s; a->pc = s; a->pd = c; } void set_sprite_transform(int sprite_number, int transform_number) { OBJATTR *s; s = &OAM[transform_number]; s->attr0 = s->attr0 | (OBJ_ROT_SCALE_ON | OBJ_DOUBLE); s->attr1 = (s->attr1 & ~OBJ_ROT_SCALE(0x1F)) | OBJ_ROT_SCALE(transform_number); } int *animations[50]; // How can I declare an arbitrary amount of animations? // Each sprite can have one sprite_anim assigned to it at a time. struct sprite_anim{ int anim_number; // Which animation is assigned? int amt_frames; int fcounter; // Frame counter int pause; // The pause between frames int pcounter; // Pause counter } sprite_animations[128]; void load_animation(int animation_number, int* images){ animations[animation_number] = images; } void set_sprite_animation(int sprite_number, int animation_number, int amt_frames, int pause ){ sprite_animations[sprite_number] = make_sprite_anim(animation_number, amt_frames, 0, pause, 0); set_sprite_image(sprite_number, animations[ animation_number ][ 0 ]); } struct sprite_anim make_sprite_anim(int anim_number, int amt_frames, int fcounter, int pause, int pcounter){ struct sprite_anim temp; temp.anim_number = anim_number; temp.amt_frames = amt_frames; temp.fcounter = fcounter; temp.pause = pause; temp.pcounter = pcounter; return temp; } #define this sprite_animations[sprite_number] void animate_sprite(int sprite_number){ if( this.pcounter++ == this.pause ){ // Check if it's time to loop animation; increment frame if( this.fcounter++ == this.amt_frames - 1 ){ this.fcounter = 0; } set_sprite_image(sprite_number, animations[ this.anim_number ][ this.fcounter ]); this.pcounter = 0; } } #undef this static void load_web_palette(unsigned short *palette) { static unsigned char factor[] = {0, 7, 13, 19, 25, 31}; int r, g, b; *palette++ = 0x0000; // transparent color placeholder for (r = 5; r >=0; --r) for (g = 5; g >= 0; --g) for (b = 5; b >= 0; --b) *palette++ = rgb_color(factor[r], factor[g], factor[b]); } void set_color(int color_number, int red, int green, int blue) { OBJ_COLORS[color_number] = rgb_color(red, green, blue); } unsigned short rgb_color(int red, int green, int blue) { return (blue<<10) | (green<<5) | red; } #define BG_MEM ((u16*)0x06000000) #define BG_WIDTH 240 void draw_dot( int x, int y, int r, int g, int b ){ int color = RGB5(r, g, b); BG_MEM[x+y*BG_WIDTH] = color; } void color_background( int r, int g, int b ){ int x, y; int color = RGB5(r, g, b); for( x=0; x<240; x++ ) for( y=0; y<160; y++ ) BG_MEM[x+y*BG_WIDTH] = color; } void video_mode(int mode) { display_control = (display_control & 0xFFF8) | mode; if (mode == 3) { display_control |= BG2_ENABLE; free_tile = 512; } REG_DISPCNT = display_control; } // **************************************************************************************************** // Utility functions static int nxti, nxtp; static unsigned long ma[56]; static int seeded = 0; #define INITIAL_SEED 161803398L int rand(int min, int max) { unsigned long mj; if (!seeded) srand(); if (++nxti == 56) nxti = 1; if (++nxtp == 56) nxtp = 1; mj = ma[nxti] - ma[nxtp]; ma[nxti] = mj; mj = ((mj / 10000) % (max - min + 1)) + min; return (int) mj; } static void srand(void) { unsigned long mj, mk; int i, k; mj = INITIAL_SEED; ma[55] = mj; mk = 1; for (i = 1; i <= 54; ++i) { int ii = (21 * i) % 55; ma[ii] = mk; mk = mj - mk; mj = ma[ii]; } for (k = 1; k <= 4; ++k) for (i = 1; i <= 55; ++i) ma[i] -= ma[1 + (i + 30) % 55]; nxti = 0; nxtp = 31; seeded = 1; } // **************************************************************************************************** // Character generator #define O 0x01, #define _ 0x00, const static char zero[] = { // 0 _ O O O _ _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char one[] = { // 1 _ _ O _ _ _ _ _ _ O O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char two[] = { // 2 _ O O O _ _ _ _ O _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ O O _ _ _ _ _ O _ _ _ _ _ _ O _ _ _ _ _ _ _ O O O O O _ _ _ _ _ _ _ _ _ _ _ }; const static char three[] = { // 3 O O O O O _ _ _ _ _ _ _ O _ _ _ _ _ _ O _ _ _ _ _ _ O O _ _ _ _ _ _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char four[] = { // 4 _ _ _ O _ _ _ _ _ _ O O _ _ _ _ _ O _ O _ _ _ _ O _ _ O _ _ _ _ O O O O O _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char five[] = { // 5 O O O O O _ _ _ O _ _ _ _ _ _ _ O O O O _ _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char six[] = { // 6 _ _ O O O _ _ _ _ O _ _ _ _ _ _ O _ _ _ _ _ _ _ O O O O _ _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char seven[] = { // 7 O O O O O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ O _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ _ _ _ _ _ _ }; const static char eight[] = { // 8 _ O O O _ _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O _ _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ }; const static char nine[] = { // 9 _ O O O _ _ _ _ O _ _ _ O _ _ _ O _ _ _ O _ _ _ _ O O O O _ _ _ _ _ _ _ O _ _ _ _ _ _ O _ _ _ _ O O O _ _ _ _ _ _ _ _ _ _ _ _ _ }; const static char minus[] = { // - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ O O O O O _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ }; const static char plus[] = { // + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ O O O O O _ _ _ _ _ O _ _ _ _ _ _ _ O _ _ _ _ _ _ _ _ _ _ _ _ _ }; const static char point[] = { // . _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ O O _ _ _ _ _ _ O O _ _ _ _ _ _ _ _ _ _ _ _ }; #undef O #undef _ static void init_numbers(void) { load_image(498, plus, IMAGE_8x8); load_image(499, minus, IMAGE_8x8); load_image(500, zero, IMAGE_8x8); load_image(501, one, IMAGE_8x8); load_image(502, two, IMAGE_8x8); load_image(503, three, IMAGE_8x8); load_image(504, four, IMAGE_8x8); load_image(505, five, IMAGE_8x8); load_image(506, six, IMAGE_8x8); load_image(507, seven, IMAGE_8x8); load_image(508, eight, IMAGE_8x8); load_image(509, nine, IMAGE_8x8); load_image(510, point, IMAGE_8x8); } typedef struct { int sprite; int remaining; int x; int y; int force_sign; int draw_leading_zeroes; int draw_trailing_zeroes; int max_digits; } drawing_t; static void draw_char(drawing_t *d, int image) { if (d->remaining == 0) return; d->remaining -= 1; set_sprite_image(d->sprite, image); draw_sprite(d->sprite, d->x, d->y); d->sprite += 1; d->x += 7; } static void clear_chars(drawing_t *d) { while (d->remaining > 0) { draw_sprite(d->sprite, 240, 160); d->sprite += 1; d->remaining -= 1; } } static void draw_num(drawing_t *d, int number) { int t, p; int pow; int seen_nonzero; static int powers[] = {100000, 10000, 1000, 100, 10, 1}; if (number < 0) { draw_char(d, 499); number = -number; } else if (d->force_sign) { draw_char(d, 498); } seen_nonzero = NO; for (p = 0; p < 6; ++p) { pow = powers[p]; for (t = 0; number >= pow; number -= pow, ++t) ; if (t == 0) { if (!seen_nonzero && !d->draw_leading_zeroes && pow != 1) continue; } else seen_nonzero = YES; if (p >= 6 - d->max_digits) draw_char(d, 500+t); } } void clear_number(int first_sprite_number, int num_sprites) { drawing_t d; d.sprite = first_sprite_number; d.remaining = num_sprites; clear_chars(&d); } void draw_number(int number, int x, int y, int first_sprite_number, int num_sprites) { drawing_t d; d.sprite = first_sprite_number; d.remaining = num_sprites; d.x = x; d.y = y; d.force_sign = NO; d.draw_leading_zeroes = NO; d.max_digits = 6; d.draw_trailing_zeroes = YES; draw_num(&d, number); clear_chars(&d); } void draw_number_advanced(int number, int x, int y, int first_sprite_number, int num_sprites, int force_sign, int draw_leading_zeroes, int max_digits) { drawing_t d; d.sprite = first_sprite_number; d.remaining = num_sprites; d.x = x; d.y = y; d.force_sign = force_sign; d.draw_leading_zeroes = draw_leading_zeroes; d.max_digits = max_digits; d.draw_trailing_zeroes = YES; draw_num(&d, number); clear_chars(&d); } void draw_real(real number, int x, int y, int first_sprite_number, int num_sprites) { drawing_t d; int frac; d.sprite = first_sprite_number; d.remaining = num_sprites; d.x = x; d.y = y; d.force_sign = NO; d.draw_leading_zeroes = NO; d.max_digits = 6; draw_num(&d, INT(number)); draw_char(&d, 510); if (number < 0) number = -number; d.draw_leading_zeroes = YES; d.draw_trailing_zeroes = NO; d.max_digits = 3; frac = INT(mulr(FRAC(number), REAL(1000))); draw_num(&d, frac); clear_chars(&d); }