You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1518 lines
37 KiB
1518 lines
37 KiB
/* |
|
|
|
spacetrash |
|
|
|
|
|
A game, which should runs on all displays. |
|
|
|
Copyright (c) 2012, olikraus@gmail.com |
|
Copyright (c) 2018, olikraus@gmail.com |
|
All rights reserved. |
|
|
|
Redistribution and use in source and binary forms, with or without modification, |
|
are permitted provided that the following conditions are met: |
|
|
|
* Redistributions of source code must retain the above copyright notice, this list |
|
of conditions and the following disclaimer. |
|
|
|
* Redistributions in binary form must reproduce the above copyright notice, this |
|
list of conditions and the following disclaimer in the documentation and/or other |
|
materials provided with the distribution. |
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
|
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
|
*/ |
|
|
|
#include "u8g2.h" |
|
#include <stdlib.h> // rand |
|
#include <unistd.h> // usleep |
|
|
|
#define ST_FP 4 |
|
|
|
/* object types */ |
|
struct _st_ot_struct |
|
{ |
|
/* |
|
missle and hit: |
|
bit 0: player missle and trash |
|
bit 1: trash, which might hit the player |
|
*/ |
|
|
|
uint8_t missle_mask; /* this object is a missle: it might destroy something if the target is_hit_fn says so */ |
|
uint8_t hit_mask; /* if missle_mask & hit_mask is != 0 then the object can be destroyed */ |
|
uint8_t points; |
|
uint8_t draw_fn; |
|
uint8_t move_fn; |
|
/* ST_MOVE_FN_NONE, ST_MOVE_FN_X_SLOW */ |
|
uint8_t destroy_fn; /* object can be destroyed by a missle (e.g. a missle from the space ship) */ |
|
/* ST_DESTROY_FN_NONE, ST_DESTROY_FN_SPLIT */ |
|
uint8_t is_hit_fn; /* is hit procedure */ |
|
/* ST_IS_HIT_FN_NONE, ST_IS_HIT_BBOX */ |
|
uint8_t fire_fn; |
|
/* ST_FIRE_FN_NONE, ST_FIRE_FN_X_LEFT */ |
|
|
|
}; |
|
typedef struct _st_ot_struct st_ot; |
|
|
|
/* |
|
objects, which are visible at the play area |
|
*/ |
|
struct _st_obj_struct |
|
{ |
|
uint8_t ot; /* object type: zero means, object is not used */ |
|
int8_t tmp; /* generic value, used by ST_MOVE_IMPLODE */ |
|
/* absolute position */ |
|
/* LCD pixel position is x>>ST_FP and y>>ST_FP */ |
|
int16_t x, y; |
|
int8_t x0,y0,x1,y1; /* object outline in pixel, reference point is at 0,0 */ |
|
}; |
|
typedef struct _st_obj_struct st_obj; |
|
|
|
#define ST_DRAW_NONE 0 |
|
#define ST_DRAW_BBOX 1 |
|
#define ST_DRAW_TRASH1 2 |
|
#define ST_DRAW_PLAYER1 3 |
|
#define ST_DRAW_TRASH2 4 |
|
#define ST_DRAW_PLAYER2 5 |
|
#define ST_DRAW_PLAYER3 6 |
|
#define ST_DRAW_GADGET 7 |
|
#define ST_DRAW_BACKSLASH 8 |
|
#define ST_DRAW_SLASH 9 |
|
#define ST_DRAW_BIG_TRASH 10 |
|
|
|
#define ST_MOVE_NONE 0 |
|
#define ST_MOVE_X_SLOW 1 |
|
#define ST_MOVE_PX_NORMAL 2 |
|
#define ST_MOVE_PX_FAST 3 |
|
#define ST_MOVE_PLAYER 4 |
|
#define ST_MOVE_PY 5 |
|
#define ST_MOVE_NY 6 |
|
#define ST_MOVE_IMPLODE 7 |
|
#define ST_MOVE_X_FAST 8 |
|
#define ST_MOVE_WALL 9 |
|
#define ST_MOVE_NXPY 10 |
|
#define ST_MOVE_NXNY 11 |
|
|
|
#define ST_IS_HIT_NONE 0 |
|
#define ST_IS_HIT_BBOX 1 |
|
#define ST_IS_HIT_WALL 2 |
|
|
|
#define ST_DESTROY_NONE 0 |
|
#define ST_DESTROY_DISAPPEAR 1 |
|
#define ST_DESTROY_TO_DUST 2 |
|
#define ST_DESTROY_GADGET 3 |
|
#define ST_DESTROY_PLAYER 4 |
|
#define ST_DESTROY_PLAYER_GADGETS 5 |
|
#define ST_DESTROY_BIG_TRASH 6 |
|
|
|
#define ST_FIRE_NONE 0 |
|
#define ST_FIRE_PLAYER1 1 |
|
#define ST_FIRE_PLAYER2 2 |
|
#define ST_FIRE_PLAYER3 3 |
|
|
|
#define ST_OT_WALL_SOLID 1 |
|
#define ST_OT_BIG_TRASH 2 |
|
#define ST_OT_MISSLE 3 |
|
#define ST_OT_TRASH1 4 |
|
#define ST_OT_PLAYER 5 |
|
#define ST_OT_DUST_PY 6 |
|
#define ST_OT_DUST_NY 7 |
|
#define ST_OT_TRASH_IMPLODE 8 |
|
#define ST_OT_TRASH2 9 |
|
#define ST_OT_PLAYER2 10 |
|
#define ST_OT_PLAYER3 11 |
|
#define ST_OT_GADGET 12 |
|
#define ST_OT_GADGET_IMPLODE 13 |
|
#define ST_OT_DUST_NXPY 14 |
|
#define ST_OT_DUST_NXNY 15 |
|
|
|
|
|
/*================================================================*/ |
|
/* graphics object */ |
|
/*================================================================*/ |
|
|
|
u8g2_t *st_u8g2; |
|
|
|
u8g2_uint_t u8g_height_minus_one; |
|
|
|
|
|
#define ST_AREA_HEIGHT (st_u8g2->height - 8) |
|
#define ST_AREA_WIDTH (st_u8g2->width) |
|
|
|
|
|
/*================================================================*/ |
|
/* object types */ |
|
/*================================================================*/ |
|
|
|
|
|
st_ot st_object_types[] U8X8_PROGMEM = |
|
{ |
|
/* 0: empty object type */ |
|
{ 0, 0, 0, ST_DRAW_NONE, ST_MOVE_NONE, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* 1: wall, player will be destroyed */ |
|
{ 2, 1, 30, ST_DRAW_BBOX, ST_MOVE_WALL, ST_DESTROY_DISAPPEAR, ST_IS_HIT_WALL, ST_FIRE_NONE }, |
|
/* ST_OT_BIG_TRASH (2) */ |
|
{ 2, 1, 0, ST_DRAW_BIG_TRASH, ST_MOVE_X_SLOW, ST_DESTROY_BIG_TRASH, ST_IS_HIT_BBOX, ST_FIRE_NONE }, |
|
/* 3: simple space ship (player) missle */ |
|
{ 1, 0, 0, ST_DRAW_BBOX, ST_MOVE_PX_FAST, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* ST_OT_TRASH1 (4): trash */ |
|
{ 2, 1, 0, ST_DRAW_TRASH1, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE }, |
|
/* ST_OT_PLAYER (5): player space ship */ |
|
{ 0, 2, 0, ST_DRAW_PLAYER1, ST_MOVE_PLAYER, ST_DESTROY_PLAYER, ST_IS_HIT_BBOX, ST_FIRE_PLAYER1 }, |
|
/* ST_OT_DUST_PY (6): Last part of trash */ |
|
{ 0, 0, 0, ST_DRAW_BBOX, ST_MOVE_PY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* ST_OT_DUST_NY (7): Last part of trash */ |
|
{ 0, 0, 0, ST_DRAW_BBOX, ST_MOVE_NY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* ST_OT_TRASH_IMPLODE (8): trash was hit */ |
|
{ 0, 0, 5, ST_DRAW_TRASH1, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* ST_OT_TRASH2 (9): trash */ |
|
{ 2, 1, 0, ST_DRAW_TRASH2, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE }, |
|
/* ST_OT_PLAYER2 (10): player space ship+1x enhancement */ |
|
{ 0, 2, 0, ST_DRAW_PLAYER2, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER2 }, |
|
/* ST_OT_PLAYER3 (11): player space ship+2x enhancement */ |
|
{ 0, 2, 0, ST_DRAW_PLAYER3, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER3 }, |
|
/* ST_OT_GADGET (12): adds enhancements */ |
|
{ 0, 1, 0, ST_DRAW_GADGET, ST_MOVE_X_FAST, ST_DESTROY_GADGET, ST_IS_HIT_BBOX, ST_FIRE_NONE }, |
|
/* ST_OT_GADGET_IMPLODE (13) */ |
|
{ 0, 0, 20, ST_DRAW_GADGET, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* ST_OT_DUST_NXPY (14): Last part of trash */ |
|
{ 0, 0, 0, ST_DRAW_BACKSLASH, ST_MOVE_NXPY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
/* ST_OT_DUST_NXNY (15): Last part of trash */ |
|
{ 0, 0, 0, ST_DRAW_SLASH, ST_MOVE_NXNY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, |
|
|
|
}; |
|
|
|
/*================================================================*/ |
|
/* list of all objects on the screen */ |
|
/*================================================================*/ |
|
|
|
/* use AVR RAMEND constant to derive the number of allowed objects */ |
|
|
|
#if RAMEND < 0x300 |
|
#define ST_OBJ_CNT 25 |
|
#else |
|
#define ST_OBJ_CNT 45 |
|
#endif |
|
|
|
st_obj st_objects[ST_OBJ_CNT]; |
|
|
|
/*================================================================*/ |
|
/* about players space ship*/ |
|
/*================================================================*/ |
|
|
|
/* player position */ |
|
uint8_t st_player_pos; |
|
|
|
/* points */ |
|
#define ST_POINTS_PER_LEVEL 25 |
|
uint16_t st_player_points; |
|
uint16_t st_player_points_delayed; |
|
uint16_t st_highscore = 0; |
|
|
|
/*================================================================*/ |
|
/* overall game state */ |
|
/*================================================================*/ |
|
|
|
#define ST_STATE_PREPARE 0 |
|
#define ST_STATE_IPREPARE 1 |
|
#define ST_STATE_GAME 2 |
|
#define ST_STATE_END 3 |
|
#define ST_STATE_IEND 4 |
|
|
|
uint8_t st_state = ST_STATE_PREPARE; |
|
|
|
/*================================================================*/ |
|
/* game difficulty */ |
|
/*================================================================*/ |
|
uint8_t st_difficulty = 1; |
|
#define ST_DIFF_VIS_LEN 30 |
|
#define ST_DIFF_FP 5 |
|
uint16_t st_to_diff_cnt = 0; |
|
|
|
/*================================================================*/ |
|
/* bitmaps */ |
|
/*================================================================*/ |
|
|
|
const uint8_t st_bitmap_player1[] = |
|
{ |
|
/* 01100000 */ 0x060, |
|
/* 11111000 */ 0x0f8, |
|
/* 01111110 */ 0x07e, |
|
/* 11111000 */ 0x0f8, |
|
/* 01100000 */ 0x060 |
|
}; |
|
|
|
const uint8_t st_bitmap_player2[] = |
|
{ |
|
/* 01100000 */ 0x060, |
|
/* 01111100 */ 0x078, |
|
/* 01100000 */ 0x060, |
|
/* 11100000 */ 0x0e0, |
|
/* 11111000 */ 0x0f8, |
|
/* 01111110 */ 0x07e, |
|
/* 11111000 */ 0x0f8, |
|
/* 01100000 */ 0x060 |
|
}; |
|
|
|
const uint8_t st_bitmap_player3[] = |
|
{ |
|
/* 01100000 */ 0x060, |
|
/* 01111100 */ 0x078, |
|
/* 01100000 */ 0x060, |
|
/* 11100000 */ 0x0e0, |
|
/* 11111000 */ 0x0f8, |
|
/* 01111110 */ 0x07e, |
|
/* 11111000 */ 0x0f8, |
|
/* 11100000 */ 0x0e0, |
|
/* 01100000 */ 0x060, |
|
/* 01111100 */ 0x078, |
|
/* 01100000 */ 0x060 |
|
}; |
|
|
|
const uint8_t st_bitmap_trash_5x5_1[] = |
|
{ |
|
/* 01110000 */ 0x070, |
|
/* 11110000 */ 0x0f0, |
|
/* 11111000 */ 0x0f8, |
|
/* 01111000 */ 0x078, |
|
/* 00110000 */ 0x030, |
|
}; |
|
|
|
const uint8_t st_bitmap_trash_5x5_2[] = |
|
{ |
|
/* 00110000 */ 0x030, |
|
/* 11111000 */ 0x0f8, |
|
/* 11111000 */ 0x0f8, |
|
/* 11110000 */ 0x0f0, |
|
/* 01110000 */ 0x070, |
|
}; |
|
|
|
const uint8_t st_bitmap_trash_7x7[] = |
|
{ |
|
/* 00111000 */ 0x038, |
|
/* 01111100 */ 0x07c, |
|
/* 11111100 */ 0x0fc, |
|
/* 11111110 */ 0x0fe, |
|
/* 11111110 */ 0x0fe, |
|
/* 01111110 */ 0x07e, |
|
/* 01111000 */ 0x078, |
|
}; |
|
|
|
const uint8_t st_bitmap_gadget[] = |
|
{ |
|
/* 01110000 */ 0x070, |
|
/* 11011000 */ 0x0d8, |
|
/* 10001000 */ 0x088, |
|
/* 11011000 */ 0x0d8, |
|
/* 01110000 */ 0x070, |
|
}; |
|
|
|
/*================================================================*/ |
|
/* forward definitions */ |
|
/*================================================================*/ |
|
uint8_t st_rnd(void) U8X8_NOINLINE; |
|
static st_obj *st_GetObj(uint8_t objnr) U8X8_NOINLINE; |
|
uint8_t st_GetMissleMask(uint8_t objnr); |
|
uint8_t st_GetHitMask(uint8_t objnr); |
|
int8_t st_FindObj(uint8_t ot) U8X8_NOINLINE; |
|
void st_ClrObjs(void) U8X8_NOINLINE; |
|
int8_t st_NewObj(void) U8X8_NOINLINE; |
|
uint8_t st_CntObj(uint8_t ot); |
|
uint8_t st_CalcXY(st_obj *o) U8X8_NOINLINE; |
|
void st_SetXY(st_obj *o, uint8_t x, uint8_t y) U8X8_NOINLINE; |
|
|
|
void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire) U8X8_NOINLINE; |
|
|
|
void st_InitTrash(uint8_t x, uint8_t y, int8_t dir); |
|
void st_NewGadget(uint8_t x, uint8_t y); |
|
void st_NewPlayerMissle(uint8_t x, uint8_t y) ; |
|
void st_NewTrashDust(uint8_t x, uint8_t y, int ot); |
|
void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot); |
|
void st_SetupPlayer(uint8_t objnr, uint8_t ot); |
|
|
|
|
|
/*================================================================*/ |
|
/* utility functions */ |
|
/*================================================================*/ |
|
|
|
char st_itoa_buf[12]; |
|
char *st_itoa(unsigned long v) |
|
{ |
|
volatile unsigned char i = 11; |
|
st_itoa_buf[11] = '\0'; |
|
while( i > 0) |
|
{ |
|
i--; |
|
st_itoa_buf[i] = (v % 10)+'0'; |
|
v /= 10; |
|
if ( v == 0 ) |
|
break; |
|
} |
|
return st_itoa_buf+i; |
|
} |
|
|
|
|
|
uint8_t st_rnd(void) |
|
{ |
|
return rand(); |
|
} |
|
|
|
/* |
|
for the specified index number, return the object |
|
*/ |
|
static st_obj *st_GetObj(uint8_t objnr) |
|
{ |
|
return st_objects+objnr; |
|
} |
|
|
|
|
|
/* |
|
check, if this is a missle-like object (that is, can this object destroy something else) |
|
*/ |
|
uint8_t st_GetMissleMask(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
return u8x8_pgm_read(&(st_object_types[o->ot].missle_mask)); |
|
} |
|
|
|
/* |
|
check, if this is a missle-like object (that is, can this object destroy something else) |
|
*/ |
|
uint8_t st_GetHitMask(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
return u8x8_pgm_read(&(st_object_types[o->ot].hit_mask)); |
|
} |
|
|
|
/* |
|
search an empty object |
|
*/ |
|
int8_t st_FindObj(uint8_t ot) |
|
{ |
|
int8_t i; |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
{ |
|
if ( st_objects[i].ot == ot ) |
|
return i; |
|
} |
|
return -1; |
|
} |
|
|
|
/* |
|
delete all objects |
|
*/ |
|
|
|
void st_ClrObjs(void) |
|
{ |
|
int8_t i; |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
st_objects[i].ot = 0; |
|
} |
|
|
|
/* |
|
search an empty object |
|
*/ |
|
int8_t st_NewObj(void) |
|
{ |
|
int8_t i; |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
{ |
|
if ( st_objects[i].ot == 0 ) |
|
return i; |
|
} |
|
return -1; |
|
} |
|
|
|
/* |
|
count number of objectes of the provided type |
|
st_CntObj(0) will return the number of empty objects, that means if |
|
st_CntObj(0) > 0 then st_NewObj() will return a valid index |
|
*/ |
|
uint8_t st_CntObj(uint8_t ot) |
|
{ |
|
uint8_t i; |
|
uint8_t cnt = 0; |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
{ |
|
if ( st_objects[i].ot == ot ) |
|
cnt++; |
|
} |
|
return cnt; |
|
} |
|
|
|
/* |
|
calculate the pixel coordinates of the reference point of an object |
|
return rhe x value |
|
*/ |
|
uint8_t st_px_x, st_px_y; /* pixel within area */ |
|
uint8_t st_CalcXY(st_obj *o) |
|
{ |
|
//st_obj *o = st_GetObj(objnr); |
|
st_px_y = o->y>>ST_FP; |
|
st_px_x = o->x>>ST_FP; |
|
return st_px_x; |
|
} |
|
|
|
void st_SetXY(st_obj *o, uint8_t x, uint8_t y) |
|
{ |
|
o->x = ((int16_t)x) << ST_FP; |
|
o->y = ((int16_t)y) << ST_FP; |
|
} |
|
|
|
/* |
|
calculate the object bounding box and place it into some global variables |
|
*/ |
|
int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1; |
|
|
|
void st_CalcBBOX(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
|
|
st_bbox_x0 = (uint16_t)(o->x>>ST_FP); |
|
st_bbox_x1 = st_bbox_x0; |
|
st_bbox_x0 += o->x0; |
|
st_bbox_x1 += o->x1; |
|
|
|
st_bbox_y0 = (uint16_t)(o->y>>ST_FP); |
|
st_bbox_y1 = st_bbox_y0; |
|
st_bbox_y0 += o->y0; |
|
st_bbox_y1 += o->y1; |
|
} |
|
|
|
/* |
|
clip bbox with the view window. requires a call to st_CalcBBOX |
|
return 0, if the bbox is totally outside the window |
|
*/ |
|
uint8_t st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; |
|
uint8_t st_ClipBBOX(void) |
|
{ |
|
if ( st_bbox_x0 >= ST_AREA_WIDTH ) |
|
return 0; |
|
if ( st_bbox_x0 >= 0 ) |
|
st_cbbox_x0 = (uint16_t)st_bbox_x0; |
|
else |
|
st_cbbox_x0 = 0; |
|
|
|
if ( st_bbox_x1 < 0 ) |
|
return 0; |
|
if ( st_bbox_x1 < ST_AREA_WIDTH ) |
|
st_cbbox_x1 = (uint16_t)st_bbox_x1; |
|
else |
|
st_cbbox_x1 = ST_AREA_WIDTH-1; |
|
|
|
if ( st_bbox_y0 >= ST_AREA_HEIGHT ) |
|
return 0; |
|
if ( st_bbox_y0 >= 0 ) |
|
st_cbbox_y0 = (uint16_t)st_bbox_y0; |
|
else |
|
st_cbbox_y0 = 0; |
|
|
|
if ( st_bbox_y1 < 0 ) |
|
return 0; |
|
if ( st_bbox_y1 < ST_AREA_HEIGHT ) |
|
st_cbbox_y1 = (uint16_t)st_bbox_y1; |
|
else |
|
st_cbbox_y1 = ST_AREA_HEIGHT-1; |
|
|
|
return 1; |
|
} |
|
|
|
|
|
/*================================================================*/ |
|
/* universal member functions */ |
|
/*================================================================*/ |
|
|
|
|
|
uint8_t st_IsOut(uint8_t objnr) |
|
{ |
|
st_CalcBBOX(objnr); |
|
if ( st_bbox_x0 >= ST_AREA_WIDTH ) |
|
return 1; |
|
if ( st_bbox_x1 < 0 ) |
|
return 1; |
|
if ( st_bbox_y0 >= ST_AREA_HEIGHT ) |
|
return 1; |
|
if ( st_bbox_y1 < 0 ) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
void st_Disappear(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
st_player_points += u8x8_pgm_read(&(st_object_types[o->ot].points)); |
|
o->ot = 0; |
|
} |
|
|
|
/*================================================================*/ |
|
/* type dependent member functions */ |
|
/*================================================================*/ |
|
|
|
void st_Move(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
switch(u8x8_pgm_read(&(st_object_types[o->ot].move_fn))) |
|
{ |
|
case ST_MOVE_NONE: |
|
break; |
|
case ST_MOVE_X_SLOW: |
|
o->x -= (1<<ST_FP)/8; |
|
o->x -= st_difficulty; |
|
o->y += (int16_t)o->tmp; |
|
if ( o->y >= ((ST_AREA_HEIGHT-1) << ST_FP) || o->y <= 0 ) |
|
o->tmp = - o->tmp; |
|
break; |
|
case ST_MOVE_X_FAST: |
|
o->x -= (1<<ST_FP)/2; |
|
o->y += (int16_t)o->tmp; |
|
if ( o->y >= ((ST_AREA_HEIGHT-1) << ST_FP) || o->y <= 0 ) |
|
o->tmp = - o->tmp; |
|
break; |
|
case ST_MOVE_PX_NORMAL: |
|
o->x += (1<<ST_FP)/4; |
|
break; |
|
case ST_MOVE_PX_FAST: |
|
o->x += (1<<ST_FP); |
|
break; |
|
case ST_MOVE_PLAYER: |
|
o->y = st_player_pos<<ST_FP; |
|
break; |
|
case ST_MOVE_PY: |
|
o->y += 3*ST_FP; |
|
break; |
|
case ST_MOVE_NY: |
|
o->y -= 3*ST_FP; |
|
break; |
|
case ST_MOVE_NXPY: |
|
o->y += 3*ST_FP; |
|
o->x -= 3*ST_FP; |
|
break; |
|
case ST_MOVE_NXNY: |
|
o->y -= 3*ST_FP; |
|
o->x -= 3*ST_FP; |
|
break; |
|
case ST_MOVE_IMPLODE: |
|
o->tmp++; |
|
if ( (o->tmp & 0x03) == 0 ) |
|
{ |
|
if ( o->x0 != o->x1 ) |
|
o->x0++; |
|
else |
|
st_Disappear(objnr); |
|
} |
|
break; |
|
case ST_MOVE_WALL: |
|
o->x -= 1; |
|
o->x -= (st_difficulty>>1); |
|
break; |
|
} |
|
} |
|
|
|
void st_DrawBBOX(uint8_t objnr) |
|
{ |
|
uint8_t y0, y1; |
|
/*st_obj *o = st_GetObj(objnr);*/ |
|
st_CalcBBOX(objnr); |
|
if ( st_ClipBBOX() == 0 ) |
|
return; |
|
/* st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; */ |
|
|
|
|
|
// w = st_cbbox_x1-st_cbbox_x0; |
|
// w++; |
|
// h = st_cbbox_y1-st_cbbox_y0; |
|
// h++; |
|
|
|
|
|
//dog_SetVLine(st_cbbox_x0, st_cbbox_y0, st_cbbox_y1); |
|
//dog_SetVLine(st_cbbox_x1, st_cbbox_y0, st_cbbox_y1); |
|
//dog_SetHLine(st_cbbox_x0, st_cbbox_x1, st_cbbox_y0); |
|
//dog_SetHLine(st_cbbox_x0, st_cbbox_x1, st_cbbox_y1); |
|
|
|
u8g2_SetDrawColor(st_u8g2, 1); |
|
y0 = u8g_height_minus_one - st_cbbox_y0; |
|
y1 = u8g_height_minus_one - st_cbbox_y1; |
|
|
|
u8g2_DrawFrame(st_u8g2, st_cbbox_x0, y1, st_cbbox_x1-st_cbbox_x0+1, y0-y1+1); |
|
|
|
//dog_SetBox(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1); |
|
|
|
/* |
|
if ( o->ot == ST_OT_PLAYER ) |
|
{ |
|
dog_DrawStr(0, 26, font_4x6, st_itoa(st_cbbox_y0)); |
|
dog_DrawStr(10, 26, font_4x6, st_itoa(st_cbbox_y1)); |
|
} |
|
*/ |
|
} |
|
|
|
#ifdef FN_IS_NOT_IN_USE |
|
void st_DrawFilledBox(uint8_t objnr) |
|
{ |
|
st_CalcBBOX(objnr); |
|
if ( st_ClipBBOX() == 0 ) |
|
return; |
|
/* st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; */ |
|
dog_SetBox(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1); |
|
} |
|
#endif |
|
|
|
void st_DrawBitmap(uint8_t objnr, const uint8_t * bm, uint8_t w, uint8_t h) |
|
{ |
|
/* st_obj *o = st_GetObj(objnr); */ |
|
st_CalcBBOX(objnr); |
|
/* result is here: int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1 */ |
|
//dog_SetBitmapP(st_bbox_x0,st_bbox_y1,bm,w,h); |
|
|
|
u8g2_DrawBitmap(st_u8g2, st_bbox_x0, u8g_height_minus_one - st_bbox_y1, (w+7)/8, h, bm); |
|
|
|
} |
|
|
|
void st_DrawObj(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
switch(u8x8_pgm_read(&(st_object_types[o->ot].draw_fn))) |
|
{ |
|
case ST_DRAW_NONE: |
|
break; |
|
case ST_DRAW_BBOX: |
|
st_DrawBBOX(objnr); |
|
break; |
|
case ST_DRAW_TRASH1: |
|
st_DrawBitmap(objnr, st_bitmap_trash_5x5_1,o->x1-o->x0+1, 5); |
|
break; |
|
case ST_DRAW_TRASH2: |
|
st_DrawBitmap(objnr, st_bitmap_trash_5x5_2,o->x1-o->x0+1, 5); |
|
break; |
|
case ST_DRAW_BIG_TRASH: |
|
st_DrawBitmap(objnr, st_bitmap_trash_7x7,o->x1-o->x0+1, 7); |
|
break; |
|
case ST_DRAW_PLAYER1: |
|
st_DrawBitmap(objnr, st_bitmap_player1,7,5); |
|
break; |
|
case ST_DRAW_PLAYER2: |
|
st_DrawBitmap(objnr, st_bitmap_player2,7,8); |
|
break; |
|
case ST_DRAW_PLAYER3: |
|
st_DrawBitmap(objnr, st_bitmap_player3,7,11); |
|
break; |
|
case ST_DRAW_GADGET: |
|
/* could use this proc, but... */ |
|
/* st_DrawBitmap(objnr, st_bitmap_gadget,o->x1-o->x0+1, 5); */ |
|
/* ... this one looks also funny. */ |
|
st_DrawBitmap(objnr, st_bitmap_gadget,5,5); |
|
break; |
|
case ST_DRAW_BACKSLASH: |
|
{ |
|
uint8_t x; |
|
uint8_t y; |
|
x = st_CalcXY(o); |
|
y = st_px_y; |
|
|
|
|
|
// dog_SetPixel(x,y); |
|
// x++; y--; |
|
// dog_SetPixel(x,y); |
|
// x++; y--; |
|
// dog_SetPixel(x,y); |
|
|
|
u8g2_SetDrawColor(st_u8g2, 1); |
|
u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y); |
|
x++; y--; |
|
u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y); |
|
x++; y--; |
|
u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y); |
|
} |
|
break; |
|
case ST_DRAW_SLASH: |
|
{ |
|
uint8_t x; |
|
uint8_t y; |
|
x = st_CalcXY(o); |
|
y = st_px_y; |
|
|
|
// dog_SetPixel(x,y); |
|
// x++; y++; |
|
// dog_SetPixel(x,y); |
|
// x++; y++; |
|
// dog_SetPixel(x,y); |
|
|
|
u8g2_SetDrawColor(st_u8g2, 1); |
|
u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y); |
|
x++; y++; |
|
u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y); |
|
x++; y++; |
|
u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
uint8_t st_IsHitBBOX(uint8_t objnr, uint8_t x, uint8_t y) |
|
{ |
|
st_CalcBBOX(objnr); |
|
if ( st_ClipBBOX() == 0 ) |
|
return 0; /* obj is outside (not visible) */ |
|
if ( x < st_cbbox_x0 ) |
|
return 0; |
|
if ( x > st_cbbox_x1 ) |
|
return 0; |
|
if ( y < st_cbbox_y0 ) |
|
return 0; |
|
if ( y > st_cbbox_y1 ) |
|
return 0; |
|
return 1; |
|
} |
|
|
|
void st_Destroy(uint8_t objnr) |
|
{ |
|
int8_t nr; |
|
st_obj *o = st_GetObj(objnr); |
|
switch(u8x8_pgm_read(&(st_object_types[o->ot].destroy_fn))) |
|
{ |
|
case ST_DESTROY_NONE: /* only usefull for missels or walls which stay alife */ |
|
break; |
|
case ST_DESTROY_DISAPPEAR: /* this should be the default operation */ |
|
st_Disappear(objnr); |
|
break; |
|
case ST_DESTROY_GADGET: |
|
nr = st_FindObj(ST_OT_PLAYER2); |
|
if ( nr >= 0 ) |
|
st_SetupPlayer(nr, ST_OT_PLAYER3); |
|
else |
|
{ |
|
nr = st_FindObj(ST_OT_PLAYER); |
|
if ( nr >= 0 ) |
|
st_SetupPlayer(nr, ST_OT_PLAYER2); |
|
} |
|
st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY); |
|
st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY); |
|
o->ot = ST_OT_GADGET_IMPLODE; |
|
o->tmp = 0; |
|
break; |
|
case ST_DESTROY_TO_DUST: |
|
st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY); |
|
st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY); |
|
o->ot = ST_OT_TRASH_IMPLODE; |
|
o->tmp = 0; |
|
break; |
|
case ST_DESTROY_BIG_TRASH: |
|
st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY); |
|
st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY); |
|
st_InitTrash((o->x>>ST_FP)-1, (o->y>>ST_FP)+3, 2+(st_rnd()&3)); |
|
st_InitTrash((o->x>>ST_FP)-2, (o->y>>ST_FP)-3, -2-(st_rnd()&3)); |
|
st_Disappear(objnr); |
|
break; |
|
case ST_DESTROY_PLAYER: |
|
st_Disappear(objnr); |
|
st_state = ST_STATE_END; |
|
o->tmp = 0; |
|
break; |
|
case ST_DESTROY_PLAYER_GADGETS: |
|
/* o->ot = ST_OT_PLAYER; */ |
|
st_SetupPlayer(objnr, ST_OT_PLAYER); |
|
break; |
|
} |
|
} |
|
|
|
/* |
|
check if the target (objnr) has been hit. |
|
st_IsHit() must also destroy the target. |
|
return value: |
|
0: do not destroy the missle |
|
1: destroy the missle |
|
*/ |
|
uint8_t st_IsHit(uint8_t objnr, uint8_t x, uint8_t y, uint8_t missle_mask) |
|
{ |
|
uint8_t hit_mask = st_GetHitMask(objnr); |
|
st_obj *o; |
|
|
|
if ( (hit_mask & missle_mask) == 0 ) |
|
return 0; |
|
|
|
o = st_GetObj(objnr); |
|
|
|
switch(u8x8_pgm_read(&(st_object_types[o->ot].is_hit_fn))) |
|
{ |
|
case ST_IS_HIT_NONE: |
|
break; |
|
case ST_IS_HIT_BBOX: |
|
if ( st_IsHitBBOX(objnr, x, y) != 0 ) |
|
{ |
|
st_Destroy(objnr); |
|
return 1; |
|
} |
|
break; |
|
case ST_IS_HIT_WALL: |
|
if ( st_IsHitBBOX(objnr, x, y) != 0 ) |
|
{ |
|
o->x0++; |
|
if ( o->x0 < o->x1 ) |
|
{ |
|
st_NewTrashDust(x, y, ST_OT_DUST_NXPY); |
|
st_NewTrashDust(x, y, ST_OT_DUST_NXNY); |
|
} |
|
else |
|
{ |
|
st_Destroy(objnr); |
|
st_NewTrashDust(x, y, ST_OT_DUST_NXPY); |
|
st_NewTrashDust(x, y, ST_OT_DUST_NXNY); |
|
st_NewTrashDust(x, y, ST_OT_DUST_NY); |
|
st_NewTrashDust(x, y, ST_OT_DUST_PY); |
|
} |
|
return 1; |
|
} |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
/* update all fire counters */ |
|
uint8_t st_fire_player = 0; |
|
uint8_t st_fire_period = 51; |
|
uint8_t st_manual_fire_delay = 20; |
|
uint8_t st_is_fire_last_value = 0; |
|
|
|
/* |
|
is_auto_fire == 1 |
|
is_fire will be ignored, autofire enabled |
|
is_auto_fire == 0 |
|
a transition from 1 to 0 on the is_fire variable will issue a missle |
|
*/ |
|
void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire) |
|
{ |
|
if ( is_auto_fire != 0 ) |
|
{ |
|
st_fire_player++; |
|
if ( st_fire_player >= st_fire_period ) |
|
st_fire_player = 0; |
|
} |
|
else |
|
{ |
|
if ( st_fire_player < st_manual_fire_delay ) |
|
{ |
|
st_fire_player++; |
|
} |
|
else |
|
{ |
|
if ( st_is_fire_last_value == 0 ) |
|
if ( is_fire != 0 ) |
|
st_fire_player = 0; |
|
} |
|
st_is_fire_last_value = is_fire; |
|
} |
|
} |
|
|
|
void st_Fire(uint8_t objnr) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
uint8_t x; |
|
uint8_t y; |
|
|
|
switch(u8x8_pgm_read(&(st_object_types[o->ot].fire_fn))) |
|
{ |
|
case ST_FIRE_NONE: |
|
break; |
|
case ST_FIRE_PLAYER1: |
|
if ( st_fire_player == 0 ) |
|
{ |
|
/* create missle at st_px_x and st_px_y */ |
|
x = st_CalcXY(o); |
|
y = st_px_y; |
|
st_NewPlayerMissle(x , y ); |
|
} |
|
break; |
|
case ST_FIRE_PLAYER2: |
|
if ( st_fire_player == 0 ) |
|
{ |
|
/* create missle at st_px_x and st_px_y */ |
|
x = st_CalcXY(o); |
|
y = st_px_y; |
|
st_NewPlayerMissle(x , y ); |
|
st_NewPlayerMissle(x , y+4 ); |
|
} |
|
break; |
|
case ST_FIRE_PLAYER3: |
|
if ( st_fire_player == 0 ) |
|
{ |
|
/* create missle at st_px_x and st_px_y */ |
|
x = st_CalcXY(o); |
|
y = st_px_y; |
|
st_NewPlayerMissle(x , y ); |
|
st_NewPlayerMissle(x , y+4 ); |
|
st_NewPlayerMissle(x , y-4 ); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
/*================================================================*/ |
|
/* object init functions */ |
|
/*================================================================*/ |
|
|
|
/* |
|
x,y are pixel coordinats within the play arey |
|
*/ |
|
void st_NewGadget(uint8_t x, uint8_t y) |
|
{ |
|
st_obj *o; |
|
int8_t objnr = st_NewObj(); |
|
if ( objnr < 0 ) |
|
return; |
|
o = st_GetObj(objnr); |
|
st_SetXY(o, x, y); |
|
o->ot = ST_OT_GADGET; |
|
o->tmp = 8; |
|
//o->x = (x)<<ST_FP; |
|
//o->y = (y)<<ST_FP; |
|
o->x0 = -3; |
|
o->x1 = 1; |
|
o->y0 = -2; |
|
o->y1 = 2; |
|
} |
|
|
|
/* |
|
x,y are pixel coordinats within the play arey |
|
dir: direction |
|
0: random |
|
!= 0 --> assigned |
|
*/ |
|
void st_InitTrash(uint8_t x, uint8_t y, int8_t dir) |
|
{ |
|
st_obj *o; |
|
int8_t objnr = st_NewObj(); |
|
if ( objnr < 0 ) |
|
return; |
|
o = st_GetObj(objnr); |
|
if ( (st_rnd() & 1) == 0 ) |
|
o->ot = ST_OT_TRASH1; |
|
else |
|
o->ot = ST_OT_TRASH2; |
|
if ( dir == 0 ) |
|
{ |
|
o->tmp = 0; |
|
if ( st_rnd() & 1 ) |
|
{ |
|
if ( st_rnd() & 1 ) |
|
o->tmp++; |
|
else |
|
o->tmp--; |
|
} |
|
} |
|
else |
|
{ |
|
o->tmp = dir; |
|
} |
|
st_SetXY(o, x, y); |
|
//o->x = (x)<<ST_FP; |
|
//o->y = (y)<<ST_FP; |
|
o->x0 = -3; |
|
o->x1 = 1; |
|
o->y0 = -2; |
|
o->y1 = 2; |
|
if ( st_difficulty >= 5 ) |
|
{ |
|
if ( (st_rnd() & 3) == 0 ) |
|
{ |
|
o->ot = ST_OT_BIG_TRASH; |
|
o->y0--; |
|
o->y1++; |
|
o->x0--; |
|
o->x1++; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
x,y are pixel coordinats within the play arey |
|
*/ |
|
void st_NewTrashDust(uint8_t x, uint8_t y, int ot) |
|
{ |
|
st_obj *o; |
|
int8_t objnr = st_NewObj(); |
|
if ( objnr < 0 ) |
|
return; |
|
o = st_GetObj(objnr); |
|
o->ot = ot; |
|
st_SetXY(o, x, y); |
|
//o->x = (x)<<ST_FP; |
|
//o->y = (y)<<ST_FP; |
|
o->x0 = 0; |
|
o->x1 = 0; |
|
o->y0 = -2; |
|
o->y1 = 2; |
|
} |
|
|
|
void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot) |
|
{ |
|
st_NewTrashDust(x>>ST_FP, y>>ST_FP, ot); |
|
} |
|
|
|
|
|
void st_NewWall(void) |
|
{ |
|
st_obj *o; |
|
int8_t objnr = st_NewObj(); |
|
int8_t h; |
|
if ( objnr < 0 ) |
|
return; |
|
o = st_GetObj(objnr); |
|
o->ot = ST_OT_WALL_SOLID; |
|
h = st_rnd(); |
|
h &= 63; |
|
h = (int8_t)(((int16_t)h*(int16_t)(ST_AREA_HEIGHT/4))>>6); |
|
h += ST_AREA_HEIGHT/6; |
|
|
|
o->x0 = 0; |
|
o->x1 = 5; |
|
o->x = (ST_AREA_WIDTH-1)<<ST_FP; |
|
|
|
if ( (st_rnd() & 1) == 0 ) |
|
{ |
|
o->y = (ST_AREA_HEIGHT-1)<<ST_FP; |
|
|
|
o->y0 = -h; |
|
o->y1 = 0; |
|
} |
|
else |
|
{ |
|
o->y = (0)<<ST_FP; |
|
o->y0 = 0; |
|
o->y1 = h; |
|
} |
|
} |
|
|
|
void st_NewPlayerMissle(uint8_t x, uint8_t y) |
|
{ |
|
st_obj *o; |
|
int8_t objnr = st_NewObj(); |
|
if ( objnr < 0 ) |
|
return; |
|
o = st_GetObj(objnr); |
|
o->ot = ST_OT_MISSLE; |
|
st_SetXY(o, x, y); |
|
//o->x = x<<ST_FP; |
|
//o->y = y<<ST_FP; |
|
o->x0 = -4; |
|
o->x1 = 1; |
|
o->y0 = 0; |
|
o->y1 = 0; |
|
} |
|
|
|
void st_SetupPlayer(uint8_t objnr, uint8_t ot) |
|
{ |
|
st_obj *o = st_GetObj(objnr); |
|
switch(ot) |
|
{ |
|
case ST_OT_PLAYER: |
|
o->ot = ot; |
|
o->y0 = -2; |
|
o->y1 = 2; |
|
break; |
|
case ST_OT_PLAYER2: |
|
o->ot = ot; |
|
o->y0 = -2; |
|
o->y1 = 5; |
|
break; |
|
case ST_OT_PLAYER3: |
|
o->ot = ot; |
|
o->y0 = -5; |
|
o->y1 = 5; |
|
break; |
|
} |
|
} |
|
|
|
void st_NewPlayer(void) |
|
{ |
|
st_obj *o; |
|
int8_t objnr = st_NewObj(); |
|
if ( objnr < 0 ) |
|
return; |
|
o = st_GetObj(objnr); |
|
o->x = 6<<ST_FP; |
|
o->y = (ST_AREA_HEIGHT/2)<<ST_FP; |
|
o->x0 = -6; |
|
o->x1 = 0; |
|
st_SetupPlayer(objnr, ST_OT_PLAYER); |
|
} |
|
|
|
/*================================================================*/ |
|
/* trash creation */ |
|
/*================================================================*/ |
|
|
|
void st_InitDeltaWall(void) |
|
{ |
|
uint8_t i; |
|
uint8_t cnt = 0; |
|
uint8_t max_x = 0; |
|
uint8_t max_l; |
|
|
|
uint8_t min_dist_for_new = 40; |
|
uint8_t my_difficulty = st_difficulty; |
|
|
|
if ( st_difficulty >= 2 ) |
|
{ |
|
|
|
max_l = ST_AREA_WIDTH; |
|
max_l -= min_dist_for_new; |
|
|
|
if ( my_difficulty > 30 ) |
|
my_difficulty = 30; |
|
min_dist_for_new -= my_difficulty; |
|
|
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
{ |
|
if ( st_objects[i].ot == ST_OT_WALL_SOLID ) |
|
{ |
|
cnt++; |
|
if ( max_x < (st_objects[i].x>>ST_FP) ) |
|
max_x = (st_objects[i].x>>ST_FP); |
|
} |
|
} |
|
/* if ( cnt < upper_trash_limit ) */ |
|
if ( max_x < max_l ) |
|
{ |
|
st_NewWall(); |
|
} |
|
} |
|
} |
|
|
|
|
|
void st_InitDeltaTrash(void) |
|
{ |
|
uint8_t i; |
|
uint8_t cnt = 0; |
|
uint8_t max_x = 0; |
|
uint8_t max_l; |
|
|
|
uint8_t upper_trash_limit = ST_OBJ_CNT-7; |
|
uint8_t min_dist_for_new = 20; |
|
uint8_t my_difficulty = st_difficulty; |
|
|
|
if ( my_difficulty > 14 ) |
|
my_difficulty = 14; |
|
min_dist_for_new -= my_difficulty; |
|
|
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
{ |
|
if ( st_objects[i].ot == ST_OT_TRASH1 || st_objects[i].ot == ST_OT_TRASH2 || st_objects[i].ot == ST_OT_GADGET || st_objects[i].ot == ST_OT_BIG_TRASH ) |
|
{ |
|
cnt++; |
|
if ( max_x < (st_objects[i].x>>ST_FP) ) |
|
max_x = (st_objects[i].x>>ST_FP); |
|
} |
|
} |
|
|
|
max_l = ST_AREA_WIDTH; |
|
max_l -= min_dist_for_new; |
|
|
|
if ( cnt < upper_trash_limit ) |
|
if ( max_x < max_l ) |
|
{ |
|
if ( (st_difficulty >= 3) && ((st_rnd() & 7) == 0) ) |
|
st_NewGadget(ST_AREA_WIDTH-1, rand() & (ST_AREA_HEIGHT-1)); |
|
else |
|
st_InitTrash(ST_AREA_WIDTH-1, rand() & (ST_AREA_HEIGHT-1),0 ); |
|
} |
|
} |
|
|
|
void st_InitDelta(void) |
|
{ |
|
st_InitDeltaTrash(); |
|
st_InitDeltaWall(); |
|
/* |
|
|
|
uint8_t cnt; |
|
cnt = st_CntObj(2); |
|
if ( cnt == 0 ) |
|
st_InitBrick1(); |
|
*/ |
|
} |
|
|
|
/*================================================================*/ |
|
/* API: game draw procedure */ |
|
/*================================================================*/ |
|
|
|
void st_DrawInGame(uint8_t fps) |
|
{ |
|
uint8_t i; |
|
/* draw all objects */ |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
st_DrawObj(i); |
|
|
|
//dog_ClrBox(0, ST_AREA_HEIGHT, st_u8g2->width-1, ST_AREA_HEIGHT+3); |
|
|
|
u8g2_SetDrawColor(st_u8g2, 0); |
|
u8g2_DrawBox(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT-3, st_u8g2->width, 4); |
|
|
|
u8g2_SetDrawColor(st_u8g2, 1); |
|
u8g2_DrawHLine(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT+1, ST_AREA_WIDTH); |
|
u8g2_DrawHLine(st_u8g2, 0, u8g_height_minus_one, ST_AREA_WIDTH); |
|
u8g2_SetFont(st_u8g2, u8g_font_4x6r); |
|
u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(st_difficulty)); |
|
u8g2_DrawHLine(st_u8g2, 10, u8g_height_minus_one - ST_AREA_HEIGHT-3, (st_to_diff_cnt>>ST_DIFF_FP)+1); |
|
u8g2_DrawVLine(st_u8g2, 10, u8g_height_minus_one - ST_AREA_HEIGHT-4, 3); |
|
u8g2_DrawVLine(st_u8g2, 10+ST_DIFF_VIS_LEN, u8g_height_minus_one - ST_AREA_HEIGHT-4, 3); |
|
|
|
|
|
/* player points */ |
|
u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH-5*4-2, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(st_player_points_delayed)); |
|
|
|
|
|
/* FPS output */ |
|
if ( fps > 0 ) |
|
{ |
|
//i = dog_DrawStr(ST_AREA_WIDTH-5*4-2-7*4, ST_AREA_HEIGHT, font_4x6, "FPS:"); |
|
i = u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH-5*4-2-7*4, u8g_height_minus_one - ST_AREA_HEIGHT, "FPS:"); |
|
|
|
//dog_DrawStr(ST_AREA_WIDTH-5*4-2-7*4+i, ST_AREA_HEIGHT, font_4x6, st_itoa(fps)); |
|
u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH-5*4-2-7*4+i, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(fps)); |
|
} |
|
/*dog_DrawStr(60+i, ST_AREA_HEIGHT, font_4x6, st_itoa(st_CntObj(0)));*/ |
|
} |
|
|
|
void st_Draw(uint8_t fps) |
|
{ |
|
switch(st_state) |
|
{ |
|
case ST_STATE_PREPARE: |
|
case ST_STATE_IPREPARE: |
|
//dog_DrawStr(0, (st_u8g2->height-6)/2, font_4x6, "SpaceTrash"); |
|
u8g2_SetFont(st_u8g2, u8g_font_4x6r); |
|
u8g2_SetDrawColor(st_u8g2, 1); |
|
//dog_DrawStrP(0, (st_u8g2->height-6)/2, font_4x6, DOG_PSTR("SpaceTrash")); |
|
u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - (st_u8g2->height-6)/2, "SpaceTrash"); |
|
//dog_SetHLine(st_u8g2->width-st_to_diff_cnt-10, st_u8g2->width-st_to_diff_cnt, (st_u8g2->height-6)/2-1); |
|
u8g2_DrawHLine(st_u8g2, st_u8g2->width-st_to_diff_cnt-10, u8g_height_minus_one - (st_u8g2->height-6)/2+1, 11); |
|
break; |
|
case ST_STATE_GAME: |
|
st_DrawInGame(fps); |
|
break; |
|
case ST_STATE_END: |
|
case ST_STATE_IEND: |
|
u8g2_SetFont(st_u8g2, u8g_font_4x6r); |
|
u8g2_SetDrawColor(st_u8g2, 1); |
|
//dog_DrawStr(0, (st_u8g2->height-6)/2, font_4x6, "Game Over"); |
|
//dog_DrawStrP(0, (st_u8g2->height-6)/2, font_4x6, DOG_PSTR("Game Over")); |
|
u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - (st_u8g2->height-6)/2, "Game Over"); |
|
//dog_DrawStr(50, (st_u8g2->height-6)/2, font_4x6, st_itoa(st_player_points)); |
|
u8g2_DrawStr(st_u8g2, 50, u8g_height_minus_one - (st_u8g2->height-6)/2, st_itoa(st_player_points)); |
|
//dog_DrawStr(75, (st_u8g2->height-6)/2, font_4x6, st_itoa(st_highscore)); |
|
u8g2_DrawStr(st_u8g2, 75, u8g_height_minus_one - (st_u8g2->height-6)/2, st_itoa(st_highscore)); |
|
//dog_SetHLine(st_to_diff_cnt, st_to_diff_cnt+10, (st_u8g2->height-6)/2-1); |
|
u8g2_DrawHLine(st_u8g2, st_to_diff_cnt, u8g_height_minus_one - (st_u8g2->height-6)/2+1, 11); |
|
break; |
|
} |
|
} |
|
|
|
void st_SetupInGame(void) |
|
{ |
|
st_player_points = 0; |
|
st_player_points_delayed = 0; |
|
st_difficulty = 1; |
|
st_to_diff_cnt = 0; |
|
st_ClrObjs(); |
|
st_NewPlayer(); |
|
/* st_InitBrick1(); */ |
|
} |
|
|
|
|
|
/*================================================================*/ |
|
/* API: game setup */ |
|
/*================================================================*/ |
|
|
|
void st_Setup(u8g2_t *u8g) |
|
{ |
|
st_u8g2 = u8g; |
|
u8g2_SetBitmapMode(u8g, 1); |
|
u8g_height_minus_one = u8g->height; |
|
u8g_height_minus_one--; |
|
} |
|
|
|
/*================================================================*/ |
|
/* API: game step execution */ |
|
/*================================================================*/ |
|
|
|
/* |
|
player_pos: 0..255 |
|
*/ |
|
void st_StepInGame(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire) |
|
{ |
|
uint8_t i, j; |
|
uint8_t missle_mask; |
|
|
|
/* rescale player pos */ |
|
//st_player_pos = ((uint16_t)player_pos * (uint16_t)ST_AREA_HEIGHT)/256; |
|
if ( player_pos < 64 ) |
|
st_player_pos = 0; |
|
else if ( player_pos >= 192 ) |
|
st_player_pos = ST_AREA_HEIGHT-2-1; |
|
else |
|
st_player_pos = ((uint16_t)((player_pos-64)) * (uint16_t)(ST_AREA_HEIGHT-2))/128; |
|
st_player_pos+=1; |
|
/* move all objects */ |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
st_Move(i); |
|
|
|
/* check for objects which left the play area */ |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
if ( st_objects[i].ot != 0 ) |
|
if ( st_IsOut(i) != 0 ) |
|
st_Disappear(i); |
|
|
|
/* missle and destruction handling */ |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
{ |
|
missle_mask = st_GetMissleMask(i); |
|
if ( missle_mask != 0 ) /* should we apply missle handling? */ |
|
if ( st_CalcXY(st_objects+i) != 0 ) /* yes: calculate pixel reference point (st_px_x, st_px_y) */ |
|
for( j = 0; j < ST_OBJ_CNT; j++ ) /* has any other object been hit? */ |
|
if ( i != j ) /* except missle itself... */ |
|
if ( st_IsHit(j, st_px_x, st_px_y, missle_mask) != 0 ) /* let the member function decide */ |
|
{ /* let the member function destroy the object if required */ |
|
st_Destroy(i); |
|
} |
|
} |
|
|
|
/* handle fire counter */ |
|
st_FireStep(is_auto_fire, is_fire); |
|
|
|
/* fire */ |
|
for( i = 0; i < ST_OBJ_CNT; i++ ) |
|
st_Fire(i); |
|
|
|
/* create new objects */ |
|
st_InitDelta(); |
|
|
|
/* increase difficulty */ |
|
|
|
st_to_diff_cnt++; |
|
if ( st_to_diff_cnt == (ST_DIFF_VIS_LEN<<ST_DIFF_FP) ) |
|
{ |
|
st_to_diff_cnt = 0; |
|
st_difficulty++; |
|
st_player_points += ST_POINTS_PER_LEVEL; |
|
} |
|
|
|
/* update visible player points */ |
|
if ( st_player_points_delayed < st_player_points ) |
|
st_player_points_delayed++; |
|
} |
|
|
|
void st_Step(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire) |
|
{ |
|
switch(st_state) |
|
{ |
|
case ST_STATE_PREPARE: |
|
st_to_diff_cnt = st_u8g2->width-10; /* reuse st_to_diff_cnt */ |
|
st_state = ST_STATE_IPREPARE; |
|
break; |
|
case ST_STATE_IPREPARE: |
|
st_to_diff_cnt--; |
|
if ( st_to_diff_cnt == 0 ) |
|
{ |
|
st_state = ST_STATE_GAME; |
|
st_SetupInGame(); |
|
} |
|
break; |
|
case ST_STATE_GAME: |
|
st_StepInGame(player_pos, is_auto_fire, is_fire); |
|
break; |
|
case ST_STATE_END: |
|
st_to_diff_cnt = st_u8g2->width-10; /* reuse st_to_diff_cnt */ |
|
if ( st_highscore < st_player_points) |
|
st_highscore = st_player_points; |
|
st_state = ST_STATE_IEND; |
|
break; |
|
case ST_STATE_IEND: |
|
st_to_diff_cnt--; |
|
if ( st_to_diff_cnt == 0 ) |
|
st_state = ST_STATE_PREPARE; |
|
break; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
u8g2_t u8g2; |
|
|
|
int main(void) |
|
{ |
|
uint8_t y, k; |
|
|
|
u8g2_SetupBuffer_SDL_128x64_4(&u8g2, &u8g2_cb_r0); |
|
u8x8_InitDisplay(u8g2_GetU8x8(&u8g2)); |
|
u8x8_SetPowerSave(u8g2_GetU8x8(&u8g2), 0); |
|
|
|
//u8g2_SetFont(&u8g2, u8g2_font_helvB08_tr); |
|
u8g2_SetFont(&u8g2, u8g2_font_6x10_tr); |
|
u8g2_SetFontDirection(&u8g2, 0); |
|
u8g2_SetFontRefHeightAll(&u8g2); |
|
|
|
st_Setup(&u8g2); |
|
|
|
y = 128; |
|
|
|
|
|
for(;;) |
|
{ |
|
do |
|
{ |
|
k = u8g_sdl_get_key(); |
|
//printf("Step %d\n", y); |
|
|
|
st_Step(y, /* is_auto_fire */ 1, /* is_fire */ 0); |
|
|
|
u8g2_FirstPage(&u8g2); |
|
do |
|
{ |
|
st_Draw(0); |
|
} while( u8g2_NextPage(&u8g2) ); |
|
|
|
usleep(10000); |
|
|
|
k = u8x8_GetMenuEvent(u8g2_GetU8x8(&u8g2)); |
|
|
|
} while( k == 0 ); |
|
|
|
if ( k == U8X8_MSG_GPIO_MENU_UP ) |
|
y += ST_FP; |
|
|
|
if ( k == U8X8_MSG_GPIO_MENU_DOWN ) |
|
y -= ST_FP; |
|
|
|
|
|
if ( k == U8X8_MSG_GPIO_MENU_HOME ) |
|
break; |
|
|
|
//if ( k == 273 ) y -= 1; |
|
//if ( k == 274 ) y += 1; |
|
//if ( k == 276 ) x -= 7; |
|
//if ( k == 275 ) x += 7; |
|
|
|
//if ( k == 'x' ) y -= ST_FP; |
|
//if ( k == 'e' ) y += ST_FP; |
|
//if ( k == 's' ) x -= 1; |
|
//if ( k == 'd' ) x += 1; |
|
//if ( k == 'q' ) break; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|