mirror of
https://github.com/QuantumLeaps/qpc.git
synced 2025-01-21 06:53:11 +08:00
1683 lines
60 KiB
XML
1683 lines
60 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<model version="2.3.2">
|
|
<documentation>"Fly 'n' Shoot" game model from Chapters 1 & 9 of PSiCC2</documentation>
|
|
<framework name="qpc"/>
|
|
<package name="Events" stereotype="0x01">
|
|
<class name="ObjectPosEvt" superclass="qpc::QEvt">
|
|
<attribute name="x" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
<attribute name="y" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
</class>
|
|
<class name="ObjectImageEvt" superclass="qpc::QEvt">
|
|
<attribute name="x" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
<attribute name="y" type="int8_t" visibility="0x00" properties="0x00"/>
|
|
<attribute name="bmp" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
</class>
|
|
<class name="MineEvt" superclass="qpc::QEvt">
|
|
<attribute name="id" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
</class>
|
|
<class name="ScoreEvt" superclass="qpc::QEvt">
|
|
<attribute name="score" type="uint16_t" visibility="0x00" properties="0x00"/>
|
|
</class>
|
|
</package>
|
|
<package name="AOs" stereotype="0x02">
|
|
<class name="Tunnel" superclass="qpc::QActive">
|
|
<documentation>Tunnel Active Object</documentation>
|
|
<attribute name="blinkTimeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/>
|
|
<attribute name="screenTimeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/>
|
|
<attribute name="mines[GAME_MINES_MAX]" type="QHsm *" visibility="0x02" properties="0x00"/>
|
|
<attribute name="mine1_pool[GAME_MINES_MAX]" type="QHsm *" visibility="0x02" properties="0x00"/>
|
|
<attribute name="mine2_pool[GAME_MINES_MAX]" type="QHsm *" visibility="0x02" properties="0x00"/>
|
|
<attribute name="blink_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="last_mine_x" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="last_mine_y" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="wall_thickness_top" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="wall_thickness_bottom" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="minimal_gap" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<operation name="advance" type="void" visibility="0x02" properties="0x00">
|
|
<code>uint32_t rnd;
|
|
uint32_t bmp1; /* bimap representing 1 column of the image */
|
|
|
|
rnd = (random() & 0xFFU);
|
|
|
|
/* reduce the top wall thickness 18.75% of the time */
|
|
if ((rnd < 48U) && (me->wall_thickness_top > 0U)) {
|
|
--me->wall_thickness_top;
|
|
}
|
|
|
|
/* reduce the bottom wall thickness 18.75% of the time */
|
|
if ((rnd > 208U) && (me->wall_thickness_bottom > 0U)) {
|
|
--me->wall_thickness_bottom;
|
|
}
|
|
|
|
rnd = (random() & 0xFFU);
|
|
|
|
/* grow the top wall thickness 18.75% of the time */
|
|
if ((rnd < 48U)
|
|
&& ((GAME_SCREEN_HEIGHT
|
|
- me->wall_thickness_top
|
|
- me->wall_thickness_bottom) > me->minimal_gap)
|
|
&& ((me->last_mine_x < (GAME_SCREEN_WIDTH - 5U))
|
|
|| (me->last_mine_y > (me->wall_thickness_top + 1U))))
|
|
{
|
|
++me->wall_thickness_top;
|
|
}
|
|
|
|
/* grow the bottom wall thickness 18.75% of the time */
|
|
if ((rnd > 208U)
|
|
&& ((GAME_SCREEN_HEIGHT
|
|
- me->wall_thickness_top
|
|
- me->wall_thickness_bottom) > me->minimal_gap)
|
|
&& ((me->last_mine_x < (GAME_SCREEN_WIDTH - 5U))
|
|
|| (me->last_mine_y + 1U
|
|
< (GAME_SCREEN_HEIGHT - me->wall_thickness_bottom))))
|
|
{
|
|
++me->wall_thickness_bottom;
|
|
}
|
|
|
|
/* advance the Tunnel by 1 game step to the left */
|
|
memmove(l_walls, l_walls + GAME_SPEED_X,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U) - GAME_SPEED_X);
|
|
|
|
bmp1 = (~(~0U << me->wall_thickness_top))
|
|
| (~0U << (GAME_SCREEN_HEIGHT
|
|
- me->wall_thickness_bottom));
|
|
|
|
l_walls[GAME_SCREEN_WIDTH - 1] = (uint8_t)bmp1;
|
|
l_walls[GAME_SCREEN_WIDTH + GAME_SCREEN_WIDTH - 1] = (uint8_t)(bmp1 >> 8);
|
|
|
|
/* copy the Tunnel layer to the main frame buffer */
|
|
memcpy(l_frame, l_walls, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));</code>
|
|
</operation>
|
|
<operation name="plantMine" type="void" visibility="0x02" properties="0x00">
|
|
<code>uint32_t rnd = (random() & 0xFFU);
|
|
|
|
if (me->last_mine_x > 0U) {
|
|
--me->last_mine_x; /* shift the last Mine 1 position to the left */
|
|
}
|
|
/* last mine far enough? */
|
|
if ((me->last_mine_x + GAME_MINES_DIST_MIN < GAME_SCREEN_WIDTH)
|
|
&& (rnd < 8U)) /* place the mines only 5% of the time */
|
|
{
|
|
uint8_t n;
|
|
for (n = 0U; n < Q_DIM(me->mines); ++n) { /*look for disabled mines */
|
|
if (me->mines[n] == (QHsm *)0) {
|
|
break;
|
|
}
|
|
}
|
|
if (n < Q_DIM(me->mines)) { /* a disabled Mine found? */
|
|
ObjectPosEvt ope; /* event to dispatch to the Mine */
|
|
rnd = (random() & 0xFFFFU);
|
|
|
|
if ((rnd & 1U) == 0U) { /* choose the type of the mine */
|
|
me->mines[n] = me->mine1_pool[n];
|
|
}
|
|
else {
|
|
me->mines[n] = me->mine2_pool[n];
|
|
}
|
|
|
|
/* new Mine is planted in the last column of the tunnel */
|
|
me->last_mine_x = GAME_SCREEN_WIDTH;
|
|
|
|
/* choose a random y-position for the Mine in the Tunnel */
|
|
rnd %= (GAME_SCREEN_HEIGHT
|
|
- me->wall_thickness_top
|
|
- me->wall_thickness_bottom - 4U);
|
|
me->last_mine_y = (uint8_t)(me->wall_thickness_top + 2U + rnd);
|
|
|
|
ope.super.sig = MINE_PLANT_SIG;
|
|
ope.x = me->last_mine_x;
|
|
ope.y = me->last_mine_y;
|
|
QHsm_dispatch(me->mines[n], (QEvt *)&ope); /* direct dispatch */
|
|
}
|
|
}
|
|
</code>
|
|
</operation>
|
|
<operation name="addImageAt" type="void" visibility="0x02" properties="0x00">
|
|
<parameter name="bmp" type="uint8_t"/>
|
|
<parameter name="x_pos" type="uint8_t"/>
|
|
<parameter name="y_pos" type="int8_t"/>
|
|
<code>uint8_t x; /* the x-index of the ship image */
|
|
uint8_t w; /* the width of the image */
|
|
|
|
Q_REQUIRE(bmp < Q_DIM(l_bitmap));
|
|
|
|
w = l_bitmap[bmp].width;
|
|
if (w > GAME_SCREEN_WIDTH - x_pos) {
|
|
w = GAME_SCREEN_WIDTH - x_pos;
|
|
}
|
|
for (x = 0U; x < w; ++x) {
|
|
uint32_t bmp1;
|
|
if (y_pos >= 0) {
|
|
bmp1 = (l_bitmap[bmp].bits[x] << (uint8_t)y_pos);
|
|
}
|
|
else {
|
|
bmp1 = (l_bitmap[bmp].bits[x] >> (uint8_t)(-y_pos));
|
|
}
|
|
l_frame[x_pos + x] |= (uint8_t)bmp1;
|
|
l_frame[x_pos + x + GAME_SCREEN_WIDTH] |= (uint8_t)(bmp1 >> 8);
|
|
}
|
|
(void)me; /* avoid the compiler warning */</code>
|
|
</operation>
|
|
<operation name="dispatchToAllMines" type="void" visibility="0x02" properties="0x00">
|
|
<parameter name="e" type="QEvt const *"/>
|
|
<code>uint8_t n;
|
|
|
|
for (n = 0U; n < GAME_MINES_MAX; ++n) {
|
|
if (me->mines[n] != (QHsm *)0) { /* is the mine used? */
|
|
QHsm_dispatch(me->mines[n], e);
|
|
}
|
|
}</code>
|
|
</operation>
|
|
<operation name="isWallHit" type="uint8_t" visibility="0x02" properties="0x00">
|
|
<parameter name="bmp" type="uint8_t"/>
|
|
<parameter name="x_pos" type="uint8_t"/>
|
|
<parameter name="y_pos" type="uint8_t"/>
|
|
<code>uint8_t x;
|
|
uint8_t w; /* the width of the image */
|
|
|
|
Q_REQUIRE(bmp < Q_DIM(l_bitmap));
|
|
|
|
w = l_bitmap[bmp].width;
|
|
if (w > GAME_SCREEN_WIDTH - x_pos) {
|
|
w = GAME_SCREEN_WIDTH - x_pos;
|
|
}
|
|
for (x = 0U; x < w; ++x) {
|
|
uint32_t bmp1 = ((uint32_t)l_bitmap[bmp].bits[x] << y_pos);
|
|
if (((l_walls[x_pos + x] & (uint8_t)bmp1) != 0U)
|
|
|| ((l_walls[x_pos + x + GAME_SCREEN_WIDTH]
|
|
& (uint8_t)(bmp1 >> 8)) != 0))
|
|
{
|
|
return (uint8_t)1;
|
|
}
|
|
}
|
|
(void)me; /* avoid the compiler warning */
|
|
return (uint8_t)0;</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1/2">
|
|
<action>uint8_t n;
|
|
for (n = 0U; n < GAME_MINES_MAX; ++n) {
|
|
QHsm_init(me->mine1_pool[n], (QEvt *)0);/*initial tran. for Mine1 */
|
|
QHsm_init(me->mine2_pool[n], (QEvt *)0);/*initial tran. for Mine2 */
|
|
}
|
|
randomSeed(1234); /* seed the pseudo-random generator */
|
|
|
|
QActive_subscribe((QActive *)me, TIME_TICK_SIG);
|
|
QActive_subscribe((QActive *)me, PLAYER_TRIGGER_SIG);
|
|
QActive_subscribe((QActive *)me, PLAYER_QUIT_SIG);
|
|
|
|
/* object dictionaries... */
|
|
QS_OBJ_DICTIONARY(&l_tunnel);
|
|
QS_OBJ_DICTIONARY(&l_tunnel.blinkTimeEvt);
|
|
QS_OBJ_DICTIONARY(&l_tunnel.screenTimeEvt);
|
|
|
|
/* function dictionaries for Tunnel HSM... */
|
|
QS_FUN_DICTIONARY(&Tunnel_initial);
|
|
QS_FUN_DICTIONARY(&Tunnel_final);
|
|
QS_FUN_DICTIONARY(&Tunnel_active);
|
|
QS_FUN_DICTIONARY(&Tunnel_show_logo);
|
|
QS_FUN_DICTIONARY(&Tunnel_demo);
|
|
QS_FUN_DICTIONARY(&Tunnel_playing);
|
|
QS_FUN_DICTIONARY(&Tunnel_game_over);
|
|
QS_FUN_DICTIONARY(&Tunnel_screen_saver);
|
|
QS_FUN_DICTIONARY(&Tunnel_screen_saver_hide);
|
|
QS_FUN_DICTIONARY(&Tunnel_screen_saver_show);
|
|
|
|
/* local signals... */
|
|
QS_SIG_DICTIONARY(BLINK_TIMEOUT_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(SCREEN_TIMEOUT_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(SHIP_IMG_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(MINE_IMG_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(EXPLOSION_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(SCORE_SIG, &l_tunnel);
|
|
|
|
(void)e; /* avoid the "unreferenced parameter" warning */</action>
|
|
<initial_glyph conn="3,2,5,1,25,14,-2">
|
|
<action box="1,-2,11,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="active">
|
|
<tran trig="MINE_DISABLED">
|
|
<action>Q_ASSERT((Q_EVT_CAST(MineEvt)->id < GAME_MINES_MAX)
|
|
&& (me->mines[Q_EVT_CAST(MineEvt)->id] != (QHsm *)0));
|
|
me->mines[Q_EVT_CAST(MineEvt)->id] = (QHsm *)0;</action>
|
|
<tran_glyph conn="2,9,3,-1,14">
|
|
<action box="0,-2,14,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="PLAYER_QUIT" target="../../2">
|
|
<tran_glyph conn="2,12,3,1,64,76,-40">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="show_logo">
|
|
<entry>QTimeEvt_postEvery(&me->blinkTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC/2U); /* 1/2 sec */
|
|
QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC*5U); /* 5 sec timeout */
|
|
me->blink_ctr = 0U;
|
|
BSP_drawNString(0U, 0U, " Quantum LeAps ");
|
|
BSP_drawNString(0U, 1U, "state-machine.co");</entry>
|
|
<exit>QTimeEvt_disarm(&me->blinkTimeEvt);
|
|
QTimeEvt_disarm(&me->screenTimeEvt);</exit>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../3">
|
|
<tran_glyph conn="4,25,3,1,24,7,-2">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="BLINK_TIMEOUT">
|
|
<action>me->blink_ctr ^= 1U; /* toggle the blink couner */</action>
|
|
<choice>
|
|
<guard>me->blink_ctr == 0U</guard>
|
|
<action>BSP_drawNString(6U*9U, 0U, " LeAps");
|
|
BSP_drawNString(0U, 1U, "state-machine.co");</action>
|
|
<choice_glyph conn="18,22,4,-1,-3,7">
|
|
<action box="1,-3,15,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice>
|
|
<guard>else</guard>
|
|
<action>BSP_drawNString(6U*9U, 0U, "LeaPs ");
|
|
BSP_drawNString(0U, 1U, "tate-machine.com");</action>
|
|
<choice_glyph conn="18,22,5,-1,7">
|
|
<action box="1,0,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,22,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,14,22,14">
|
|
<entry box="1,2,5,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="demo">
|
|
<entry>me->last_mine_x = 0U; /* last mine at right edge of the tunnel */
|
|
me->last_mine_y = 0U;
|
|
/* set the tunnel properties... */
|
|
me->wall_thickness_top = 0U;
|
|
me->wall_thickness_bottom = 0U;
|
|
me->minimal_gap = GAME_SCREEN_HEIGHT - 3U;
|
|
|
|
/* erase the tunnel walls */
|
|
memset(l_walls, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
|
|
|
|
QTimeEvt_postEvery(&me->blinkTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC/2U); /* every 1/2 sec */
|
|
QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC*20U); /* 20s timeout */
|
|
|
|
me->blink_ctr = 0U; /* init the blink counter */</entry>
|
|
<exit>QTimeEvt_disarm(&me->blinkTimeEvt);
|
|
QTimeEvt_disarm(&me->screenTimeEvt);</exit>
|
|
<tran trig="BLINK_TIMEOUT">
|
|
<action>me->blink_ctr ^= 1U; /* toggle the blink cunter */</action>
|
|
<tran_glyph conn="4,42,3,-1,14">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../6">
|
|
<tran_glyph conn="4,45,3,3,28">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="TIME_TICK">
|
|
<action>Tunnel_advance(me);
|
|
if (me->blink_ctr != 0U) {
|
|
/* add the text bitmap into the frame buffer */
|
|
Tunnel_addImageAt(me,
|
|
PRESS_BUTTON_BMP,
|
|
(GAME_SCREEN_WIDTH - 55U)/2U,
|
|
(GAME_SCREEN_HEIGHT - 8U)/2U);
|
|
}
|
|
BSP_drawBitmap(l_frame);</action>
|
|
<tran_glyph conn="4,39,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="PLAYER_TRIGGER" target="../../4">
|
|
<tran_glyph conn="4,48,3,1,24,7,-2">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,30,22,20">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="playing">
|
|
<entry>static QEvt const takeoff = { TAKE_OFF_SIG, 0U, 0U };
|
|
me->minimal_gap = GAME_SCREEN_HEIGHT - 3u;
|
|
/* erase the walls */
|
|
memset(l_walls, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
|
|
QACTIVE_POST(AO_Ship, &takeoff, me); /* post the TAKEOFF sig */</entry>
|
|
<exit>QEvt recycle;
|
|
recycle.sig = MINE_RECYCLE_SIG;
|
|
Tunnel_dispatchToAllMines(me, &recycle); /* recycle all Mines */</exit>
|
|
<tran trig="TIME_TICK">
|
|
<action>/* render this frame on the display */
|
|
BSP_drawBitmap(l_frame);
|
|
Tunnel_advance(me);
|
|
Tunnel_plantMine(me);
|
|
Tunnel_dispatchToAllMines(me, e);</action>
|
|
<tran_glyph conn="4,62,3,-1,14">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SHIP_IMG">
|
|
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x;
|
|
int8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;
|
|
|
|
/* did the Ship/Missile hit the tunnel wall? */
|
|
if (Tunnel_isWallHit(me, bmp, x, y)) {
|
|
static QEvt const hit = { HIT_WALL_SIG, 0U, 0U };
|
|
QACTIVE_POST(AO_Ship, &hit, me);
|
|
}
|
|
Tunnel_addImageAt(me, bmp, x, y);
|
|
Tunnel_dispatchToAllMines(me, e); /* let Mines check for hits */</action>
|
|
<tran_glyph conn="4,65,3,-1,14">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="MISSILE_IMG">
|
|
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x;
|
|
int8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;
|
|
|
|
/* did the Ship/Missile hit the tunnel wall? */
|
|
if (Tunnel_isWallHit(me, bmp, x, y)) {
|
|
static QEvt const hit = { HIT_WALL_SIG, 0U, 0U };
|
|
QACTIVE_POST(AO_Missile, &hit, me);
|
|
}
|
|
Tunnel_addImageAt(me, bmp, x, y);
|
|
Tunnel_dispatchToAllMines(me, e); /* let Mines check for hits */</action>
|
|
<tran_glyph conn="4,68,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="MINE_IMG">
|
|
<action>Tunnel_addImageAt(me,
|
|
Q_EVT_CAST(ObjectImageEvt)->bmp,
|
|
Q_EVT_CAST(ObjectImageEvt)->x,
|
|
Q_EVT_CAST(ObjectImageEvt)->y);</action>
|
|
<tran_glyph conn="4,71,3,-1,14">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="EXPLOSION">
|
|
<action>Tunnel_addImageAt(me,
|
|
Q_EVT_CAST(ObjectImageEvt)->bmp,
|
|
Q_EVT_CAST(ObjectImageEvt)->x,
|
|
Q_EVT_CAST(ObjectImageEvt)->y);</action>
|
|
<tran_glyph conn="4,74,3,-1,14">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SCORE">
|
|
<action>BSP_updateScore(Q_EVT_CAST(ScoreEvt)->score);
|
|
/* increase difficulty of the game:
|
|
* the tunnel gets narrower as the score goes up
|
|
*/
|
|
me->minimal_gap = (uint8_t)(GAME_SCREEN_HEIGHT - 3U
|
|
- Q_EVT_CAST(ScoreEvt)->score/2000U);</action>
|
|
<tran_glyph conn="4,77,3,-1,14">
|
|
<action box="0,-2,6,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="GAME_OVER" target="../../5">
|
|
<action>uint16_t score = Q_EVT_CAST(ScoreEvt)->score;
|
|
char str[5];
|
|
BSP_updateScore(score);
|
|
|
|
/* clear the screen */
|
|
memset(l_frame, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8));
|
|
BSP_drawBitmap(l_frame);
|
|
/* Output the final score to the screen */
|
|
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*10U)/2U, 1U, "Score:");
|
|
str[4] = '\0'; /* zero-terminate the string */
|
|
str[3] = '0' + (score % 10U); score /= 10U;
|
|
str[2] = '0' + (score % 10U); score /= 10U;
|
|
str[1] = '0' + (score % 10U); score /= 10U;
|
|
str[0] = '0' + (score % 10U);
|
|
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*10U)/2U + 6U*6U, 1U, str);</action>
|
|
<tran_glyph conn="4,80,3,3,26,-10,2">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,52,22,30">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="game_over">
|
|
<entry>QTimeEvt_postEvery(&me->blinkTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC/2U); /* 1/2 sec */
|
|
QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC*5U); /* 5 sec timeout */
|
|
me->blink_ctr = 0U;
|
|
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U, "Game Over");</entry>
|
|
<exit>QTimeEvt_disarm(&me->blinkTimeEvt);
|
|
QTimeEvt_disarm(&me->screenTimeEvt);
|
|
BSP_updateScore(0); /* update the score on the display */</exit>
|
|
<tran trig="BLINK_TIMEOUT">
|
|
<action>me->blink_ctr ^= 1U; /* toggle the blink couner */
|
|
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2, 0U,
|
|
((me->blink_ctr == 0U)
|
|
? "Game Over"
|
|
: " "));</action>
|
|
<tran_glyph conn="32,80,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../3">
|
|
<tran_glyph conn="32,77,3,1,30,-11,-32,-19,-4">
|
|
<action box="0,-2,14,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="32,68,28,14">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="screen_saver">
|
|
<initial target="../2">
|
|
<initial_glyph conn="36,34,5,1,20,8,-2">
|
|
<action box="1,-2,6,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<tran trig="PLAYER_TRIGGER" target="../../3">
|
|
<tran_glyph conn="32,38,3,1,30,-10,-32,6,-4">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="screen_saver_hide">
|
|
<entry>BSP_displayOff(); /* power down the display */
|
|
QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC*3U); /* 3s timeout */</entry>
|
|
<exit>QTimeEvt_disarm(&me->screenTimeEvt);
|
|
BSP_displayOn(); /* power up the display */</exit>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../3">
|
|
<tran_glyph conn="36,48,3,1,20,6,-2">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="36,40,18,10">
|
|
<entry box="1,2,5,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="screen_saver_show">
|
|
<entry>uint32_t rnd = random();
|
|
/* clear the screen frame buffer */
|
|
memset(l_frame, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
|
|
Tunnel_addImageAt(me,
|
|
PRESS_BUTTON_BMP,
|
|
(uint8_t)(rnd % (GAME_SCREEN_WIDTH - 55U)),
|
|
(int8_t) (rnd % (GAME_SCREEN_HEIGHT - 8U)));
|
|
BSP_drawBitmap(l_frame);
|
|
QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me,
|
|
BSP_TICKS_PER_SEC/3U); /* 1/3 sec timeout */</entry>
|
|
<exit>QTimeEvt_disarm(&me->screenTimeEvt);
|
|
/* clear the screen frame buffer */
|
|
memset(l_frame, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
|
|
BSP_drawBitmap(l_frame);</exit>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../2">
|
|
<tran_glyph conn="36,60,3,1,22,-15,-4">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="36,52,18,10">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_glyph node="32,30,28,34"/>
|
|
</state>
|
|
<state_glyph node="2,4,62,80"/>
|
|
</state>
|
|
<state name="final">
|
|
<entry>/* clear the screen */
|
|
memset(l_frame, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8));
|
|
BSP_drawBitmap(l_frame);
|
|
QF_stop(); /* stop QF and cleanup */</entry>
|
|
<state_glyph node="2,86,24,6">
|
|
<entry box="1,2,6,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_diagram size="68,94"/>
|
|
</statechart>
|
|
</class>
|
|
<class name="Ship" superclass="qpc::QActive">
|
|
<documentation>Ship Active Object</documentation>
|
|
<attribute name="x" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="y" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="score" type="uint16_t" visibility="0x02" properties="0x00"/>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>(void)e; /* avoid the compiler warning 'usused parameter' */
|
|
QActive_subscribe((QActive *)me, TIME_TICK_SIG);
|
|
QActive_subscribe((QActive *)me, PLAYER_TRIGGER_SIG);
|
|
/* object dictionaries... */
|
|
QS_OBJ_DICTIONARY(&l_ship);
|
|
/* function dictionaries for Ship HSM... */
|
|
QS_FUN_DICTIONARY(&Ship_initial);
|
|
QS_FUN_DICTIONARY(&Ship_active);
|
|
QS_FUN_DICTIONARY(&Ship_parked);
|
|
QS_FUN_DICTIONARY(&Ship_flying);
|
|
QS_FUN_DICTIONARY(&Ship_exploding);
|
|
/* local signals... */
|
|
QS_SIG_DICTIONARY(PLAYER_SHIP_MOVE_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(TAKE_OFF_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(HIT_WALL_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(HIT_MINE_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &l_ship);</action>
|
|
<initial_glyph conn="3,2,5,1,36,4,-2">
|
|
<action box="1,-2,6,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="active">
|
|
<initial target="../2">
|
|
<initial_glyph conn="4,8,5,1,29,10,-2">
|
|
<action box="1,-2,6,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<tran trig="PLAYER_SHIP_MOVE">
|
|
<action brief="me->x = e->x;\me->y = e->y">me->x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->y = Q_EVT_CAST(ObjectPosEvt)->y;</action>
|
|
<tran_glyph conn="3,11,3,-1,21">
|
|
<action box="1,-2,15,6"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="parked">
|
|
<tran trig="TAKE_OFF" target="../../3">
|
|
<tran_glyph conn="5,22,3,1,28,6,-2">
|
|
<action box="0,-2,8,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="5,16,26,8"/>
|
|
</state>
|
|
<state name="flying">
|
|
<entry>ScoreEvt *sev;
|
|
me->score = 0U; /* reset the score */
|
|
sev = Q_NEW(ScoreEvt, SCORE_SIG);
|
|
sev->score = me->score;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)sev, me);</entry>
|
|
<tran trig="TIME_TICK">
|
|
<action>/* tell the Tunnel to draw the Ship and test for hits */
|
|
ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, SHIP_IMG_SIG);
|
|
oie->x = me->x;
|
|
oie->y = me->y;
|
|
oie->bmp = SHIP_BMP;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
|
|
|
|
++me->score; /* increment the score for surviving another tick */
|
|
|
|
if ((me->score % 10U) == 0U) { /* is the score "round"? */
|
|
ScoreEvt *sev = Q_NEW(ScoreEvt, SCORE_SIG);
|
|
sev->score = me->score;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)sev, me);
|
|
}</action>
|
|
<tran_glyph conn="5,33,3,-1,16">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="PLAYER_TRIGGER">
|
|
<action>ObjectPosEvt *ope = Q_NEW(ObjectPosEvt, MISSILE_FIRE_SIG);
|
|
ope->x = me->x;
|
|
ope->y = me->y + SHIP_HEIGHT - 1U;
|
|
QACTIVE_POST(AO_Missile, (QEvt *)ope, me);</action>
|
|
<tran_glyph conn="5,36,3,-1,16">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="DESTROYED_MINE">
|
|
<action>me->score += Q_EVT_CAST(ScoreEvt)->score;
|
|
/* the score will be sent to the Tunnel by the next TIME_TICK */</action>
|
|
<tran_glyph conn="5,39,3,-1,16">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="HIT_WALL" target="../../4">
|
|
<tran_glyph conn="5,42,3,1,28,9,-2">
|
|
<action box="0,-2,8,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="HIT_MINE" target="../../4">
|
|
<tran_glyph conn="5,45,3,1,28,6,-2">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="5,26,26,21">
|
|
<entry box="1,2,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="exploding">
|
|
<entry>me->exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>me->exp_ctr < 15U</guard>
|
|
<action>ObjectImageEvt *oie;
|
|
++me->exp_ctr;
|
|
/* tell the Tunnel to draw the current stage of Explosion */
|
|
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
|
|
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
|
|
oie->x = me->x; /* x of explosion */
|
|
oie->y = (int8_t)((int)me->y - 4U + SHIP_HEIGHT);
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="14,57,5,-1,15">
|
|
<action box="1,0,15,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../2">
|
|
<guard brief="else"/>
|
|
<action>ScoreEvt *gameOver = Q_NEW(ScoreEvt, GAME_OVER_SIG);
|
|
gameOver->score = me->score;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)gameOver, me);</action>
|
|
<choice_glyph conn="14,57,4,1,4,21,-41,-4">
|
|
<action box="1,4,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="5,57,3,-1,9">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="5,49,26,14">
|
|
<entry box="1,2,13,4"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_glyph node="3,4,34,61"/>
|
|
</state>
|
|
<state_diagram size="41,67"/>
|
|
</statechart>
|
|
</class>
|
|
<class name="Missile" superclass="qpc::QActive">
|
|
<documentation>Missile Active Object</documentation>
|
|
<attribute name="x" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="y" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>(void)e;
|
|
QActive_subscribe((QActive *)me, TIME_TICK_SIG);
|
|
|
|
QS_OBJ_DICTIONARY(&l_missile); /* object dictionary for Missile object */
|
|
|
|
QS_FUN_DICTIONARY(&Missile_initial); /* dictionaries for Missile HSM */
|
|
QS_FUN_DICTIONARY(&Missile_armed);
|
|
QS_FUN_DICTIONARY(&Missile_flying);
|
|
QS_FUN_DICTIONARY(&Missile_exploding);
|
|
|
|
QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, &l_missile); /* local signals */
|
|
QS_SIG_DICTIONARY(HIT_WALL_SIG, &l_missile);
|
|
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &l_missile);</action>
|
|
<initial_glyph conn="3,3,5,1,35,4,-2">
|
|
<action box="1,-2,6,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="armed">
|
|
<tran trig="MISSILE_FIRE" target="../../2">
|
|
<action>me->x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->y = Q_EVT_CAST(ObjectPosEvt)->y;</action>
|
|
<tran_glyph conn="3,11,3,1,35,6,-2">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="3,5,33,8"/>
|
|
</state>
|
|
<state name="flying">
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>me->x + GAME_MISSILE_SPEED_X < GAME_SCREEN_WIDTH</guard>
|
|
<action brief="...">ObjectImageEvt *oie;
|
|
me->x += GAME_MISSILE_SPEED_X;
|
|
/*tell the Tunnel to draw the Missile and test for wall hits*/
|
|
oie = Q_NEW(ObjectImageEvt, MISSILE_IMG_SIG);
|
|
oie->x = me->x;
|
|
oie->y = me->y;
|
|
oie->bmp = MISSILE_BMP;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="12,21,5,-1,20">
|
|
<action box="1,0,22,4"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../1">
|
|
<guard brief="else"/>
|
|
<choice_glyph conn="12,21,4,1,5,28,-17,-4">
|
|
<action box="1,5,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="3,21,3,-1,9">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="HIT_WALL" target="../../3">
|
|
<tran_glyph conn="3,33,3,1,35,6,-2">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="DESTROYED_MINE" target="../../1">
|
|
<action>QACTIVE_POST(AO_Ship, e, me);</action>
|
|
<tran_glyph conn="3,30,3,1,39,-21,-6">
|
|
<action box="0,-2,15,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="3,15,33,20"/>
|
|
</state>
|
|
<state name="exploding">
|
|
<entry>me->exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>(me->x >= GAME_SPEED_X) && (me->exp_ctr < 15U)</guard>
|
|
<action brief="...">ObjectImageEvt *oie;
|
|
|
|
++me->exp_ctr; /* advance the explosion counter */
|
|
me->x -= GAME_SPEED_X; /* move the explosion by one step */
|
|
|
|
/* tell the Tunnel to render the current stage of Explosion */
|
|
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
|
|
oie->x = me->x + 3U; /* x-pos of explosion */
|
|
oie->y = (int8_t)((int)me->y - 4U); /* y-pos */
|
|
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="12,46,5,-1,20">
|
|
<action box="1,0,19,4"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../1">
|
|
<guard brief="else"/>
|
|
<choice_glyph conn="12,46,4,1,5,32,-42,-8">
|
|
<action box="1,5,7,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="3,46,3,-1,9">
|
|
<action box="0,-2,8,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="3,37,33,16">
|
|
<entry box="1,2,14,4"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_diagram size="46,55"/>
|
|
</statechart>
|
|
</class>
|
|
<class name="Mine1" superclass="qpc::QHsm">
|
|
<documentation>The Mine1 orthogonal component</documentation>
|
|
<attribute name="x" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="y" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="exp_ctr" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>static uint8_t dict_sent;
|
|
|
|
if (!dict_sent) {
|
|
QS_OBJ_DICTIONARY(&l_mine1[0]); /* obj. dictionaries for Mine1 pool */
|
|
QS_OBJ_DICTIONARY(&l_mine1[1]);
|
|
QS_OBJ_DICTIONARY(&l_mine1[2]);
|
|
QS_OBJ_DICTIONARY(&l_mine1[3]);
|
|
QS_OBJ_DICTIONARY(&l_mine1[4]);
|
|
|
|
QS_FUN_DICTIONARY(&Mine1_initial);/*fun. dictionaries for Mine1 HSM */
|
|
QS_FUN_DICTIONARY(&Mine1_unused);
|
|
QS_FUN_DICTIONARY(&Mine1_used);
|
|
QS_FUN_DICTIONARY(&Mine1_planted);
|
|
QS_FUN_DICTIONARY(&Mine1_exploding);
|
|
|
|
dict_sent = 1U;
|
|
}
|
|
/* local signals */
|
|
QS_SIG_DICTIONARY(MINE_PLANT_SIG, me);
|
|
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, me);
|
|
QS_SIG_DICTIONARY(MINE_RECYCLE_SIG, me);
|
|
QS_SIG_DICTIONARY(SHIP_IMG_SIG, me);
|
|
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, me);
|
|
|
|
(void)e; /* avoid the "unreferenced parameter" warning */</action>
|
|
<initial_glyph conn="2,2,5,1,31,4,-2">
|
|
<action box="0,-2,11,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="unused">
|
|
<tran trig="MINE_PLANT" target="../../2/2">
|
|
<action>me->x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->y = Q_EVT_CAST(ObjectPosEvt)->y;</action>
|
|
<tran_glyph conn="2,10,3,1,43,16,-8">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="2,4,29,8"/>
|
|
</state>
|
|
<state name="used">
|
|
<exit brief="...">/* tell the Tunnel that this mine is becoming disabled */
|
|
MineEvt *mev = Q_NEW(MineEvt, MINE_DISABLED_SIG);
|
|
mev->id = MINE_ID(me);
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)mev, me);</exit>
|
|
<tran trig="MINE_RECYCLE" target="../../1">
|
|
<tran_glyph conn="2,21,3,1,41,-13,-12">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="exploding">
|
|
<entry>me->exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard brief="still on screen?">(me->x >= GAME_SPEED_X) && (me->exp_ctr < 15)</guard>
|
|
<action>ObjectImageEvt *oie;
|
|
++me->exp_ctr; /* advance the explosion counter */
|
|
me->x -= GAME_SPEED_X; /* move explosion by 1 step */
|
|
|
|
/* tell the Game to render the current stage of Explosion */
|
|
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
|
|
oie->x = me->x + 1U; /* x of explosion */
|
|
oie->y = (int8_t)((int)me->y - 4 + 2); /* y of explosion */
|
|
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="14,57,5,-1,21">
|
|
<action box="1,0,20,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../../1">
|
|
<guard brief="else"/>
|
|
<choice_glyph conn="14,57,4,1,5,37,-54,-20">
|
|
<action box="1,5,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,57,3,-1,10">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,50,33,14">
|
|
<entry box="1,2,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="planted">
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>me->x >= GAME_SPEED_X</guard>
|
|
<action>ObjectImageEvt *oie;
|
|
me->x -= GAME_SPEED_X; /* move the mine 1 step */
|
|
/* tell the Tunnel to draw the Mine */
|
|
oie = Q_NEW(ObjectImageEvt, MINE_IMG_SIG);
|
|
oie->x = me->x;
|
|
oie->y = me->y;
|
|
oie->bmp = MINE1_BMP;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="15,30,5,-1,20">
|
|
<action box="1,0,20,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../../1">
|
|
<guard brief="else"/>
|
|
<choice_glyph conn="15,30,4,1,4,32,-26,-16">
|
|
<action box="1,4,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,30,3,-1,11">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SHIP_IMG">
|
|
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../../1">
|
|
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me->x, me->y, bmp, x, y)</guard>
|
|
<action brief="...">static MineEvt const mine1_hit = {
|
|
{ HIT_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
|
|
1U /* type of the mine (1 for Mine type-1) */
|
|
};
|
|
QACTIVE_POST(AO_Ship, (QEvt *)&mine1_hit, me);
|
|
/* go straight to 'disabled' and let the Ship do
|
|
* the exploding */</action>
|
|
<choice_glyph conn="15,37,5,1,34,-29,-18">
|
|
<action box="1,0,22,4"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,37,3,-1,11">
|
|
<action box="0,-2,8,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="MISSILE_IMG">
|
|
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../1">
|
|
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me->x, me->y, bmp, x, y)</guard>
|
|
<action brief="...">static ScoreEvt const mine1_destroyed = {
|
|
{ DESTROYED_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
|
|
25U /* score for destroying Mine type-1 */
|
|
};
|
|
QACTIVE_POST(AO_Missile, (QEvt *)&mine1_destroyed, me);</action>
|
|
<choice_glyph conn="15,43,5,1,24,9,-2">
|
|
<action box="1,0,22,4"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,43,3,-1,11">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,24,33,24"/>
|
|
</state>
|
|
<state_glyph node="2,14,39,52">
|
|
<exit box="1,2,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_diagram size="53,68"/>
|
|
</statechart>
|
|
</class>
|
|
<class name="Mine2" superclass="qpc::QHsm">
|
|
<documentation>The Mine2 orthogonal component</documentation>
|
|
<attribute name="x" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="y" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="exp_ctr" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>static uint8_t dict_sent;
|
|
|
|
if (!dict_sent) {
|
|
/* object dictionaries for Mine2 pool... */
|
|
QS_OBJ_DICTIONARY(&l_mine2[0]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[1]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[2]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[3]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[4]);
|
|
|
|
/*function dictionaries for Mine2 HSM... */
|
|
QS_FUN_DICTIONARY(&Mine2_initial);
|
|
QS_FUN_DICTIONARY(&Mine2_unused);
|
|
QS_FUN_DICTIONARY(&Mine2_used);
|
|
QS_FUN_DICTIONARY(&Mine2_planted);
|
|
QS_FUN_DICTIONARY(&Mine2_exploding);
|
|
|
|
dict_sent = 1U;
|
|
}
|
|
/* local signals... */
|
|
QS_SIG_DICTIONARY(MINE_PLANT_SIG, me);
|
|
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, me);
|
|
QS_SIG_DICTIONARY(MINE_RECYCLE_SIG, me);
|
|
QS_SIG_DICTIONARY(SHIP_IMG_SIG, me);
|
|
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, me);
|
|
|
|
(void)e; /* avoid the "unreferenced parameter" warning */</action>
|
|
<initial_glyph conn="2,2,5,1,31,4,-2">
|
|
<action box="1,-2,6,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="unused">
|
|
<tran trig="MINE_PLANT" target="../../2/1">
|
|
<action>me->x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->y = Q_EVT_CAST(ObjectPosEvt)->y;</action>
|
|
<tran_glyph conn="2,10,3,1,43,16,-8">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="2,4,29,8"/>
|
|
</state>
|
|
<state name="used">
|
|
<exit brief="...">/* tell the Tunnel that this mine is becoming disabled */
|
|
MineEvt *mev = Q_NEW(MineEvt, MINE_DISABLED_SIG);
|
|
mev->id = MINE_ID(me);
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)mev, me);</exit>
|
|
<tran trig="MINE_RECYCLE" target="../../1">
|
|
<tran_glyph conn="2,21,3,1,41,-13,-12">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="planted">
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>me->x >= GAME_SPEED_X</guard>
|
|
<action>ObjectImageEvt *oie;
|
|
me->x -= GAME_SPEED_X; /* move the mine 1 step */
|
|
/* tell the Tunnel to draw the Mine */
|
|
oie = Q_NEW(ObjectImageEvt, MINE_IMG_SIG);
|
|
oie->x = me->x;
|
|
oie->y = me->y;
|
|
oie->bmp = MINE2_BMP;
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="15,30,5,-1,20">
|
|
<action box="1,0,20,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../../1">
|
|
<guard brief="else"/>
|
|
<choice_glyph conn="15,30,4,1,4,32,-26,-16">
|
|
<action box="1,4,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,30,3,-1,11">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SHIP_IMG">
|
|
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../../1">
|
|
<guard brief="collision with MINE2_BMP?">do_bitmaps_overlap(MINE2_BMP, me->x, me->y, bmp, x, y)</guard>
|
|
<action>static MineEvt const mine1_hit = {
|
|
{ HIT_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
|
|
2U /* type of the mine (2 for Mine type-2) */
|
|
};
|
|
QACTIVE_POST(AO_Ship, (QEvt *)&mine1_hit, me);
|
|
/* go straight to 'disabled' and let the Ship do
|
|
* the exploding */</action>
|
|
<choice_glyph conn="15,37,5,1,34,-29,-18">
|
|
<action box="1,0,21,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,37,3,-1,11">
|
|
<action box="0,-2,8,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="MISSILE_IMG">
|
|
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../2">
|
|
<guard brief="collision with MINE2_MISSILE_BMP?">do_bitmaps_overlap(MINE2_MISSILE_BMP, me->x, me->y, bmp, x, y)</guard>
|
|
<action>/* NOTE: Mine type-2 is nastier than Mine type-1.
|
|
* The type-2 mine can hit the Ship with any of its
|
|
* "tentacles". However, it can be destroyed by the
|
|
* Missile only by hitting its center, defined as
|
|
* a smaller bitmap MINE2_MISSILE_BMP.
|
|
*/
|
|
static ScoreEvt const mine2_destroyed = {
|
|
{ DESTROYED_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
|
|
45U /* score for destroying Mine type-2 */
|
|
};
|
|
QACTIVE_POST(AO_Missile, (QEvt *)&mine2_destroyed, me);</action>
|
|
<choice_glyph conn="15,43,5,1,24,9,-2">
|
|
<action box="1,0,26,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,43,3,-1,11">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,24,33,24"/>
|
|
</state>
|
|
<state name="exploding">
|
|
<entry>me->exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard brief="still on screen?">(me->x >= GAME_SPEED_X) && (me->exp_ctr < 15U)</guard>
|
|
<action>ObjectImageEvt *oie;
|
|
++me->exp_ctr; /* advance the explosion counter */
|
|
me->x -= GAME_SPEED_X; /* move explosion by 1 step */
|
|
|
|
/* tell the Game to render the current stage of Explosion */
|
|
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
|
|
oie->x = me->x + 1U; /* x of explosion */
|
|
oie->y = (int8_t)((int)me->y - 4 + 2); /* y of explosion */
|
|
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
|
|
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);</action>
|
|
<choice_glyph conn="15,57,5,-1,20">
|
|
<action box="1,0,19,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice target="../../../../1">
|
|
<guard brief="else"/>
|
|
<choice_glyph conn="15,57,4,1,5,36,-54,-20">
|
|
<action box="1,5,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,57,3,-1,11">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,50,33,14">
|
|
<entry box="1,2,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_glyph node="2,14,39,52">
|
|
<exit box="1,2,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_diagram size="53,68"/>
|
|
</statechart>
|
|
</class>
|
|
<attribute name="AO_Tunnel" type="QActive * const" visibility="0x00" properties="0x00"/>
|
|
<attribute name="AO_Ship" type="QActive * const" visibility="0x00" properties="0x00"/>
|
|
<attribute name="AO_Missile" type="QActive * const" visibility="0x00" properties="0x00"/>
|
|
<operation name="do_bitmaps_overlap" type="uint8_t" visibility="0x00" properties="0x00">
|
|
<parameter name="bmp_id1" type="uint8_t"/>
|
|
<parameter name="x1" type="uint8_t"/>
|
|
<parameter name="y1" type="uint8_t"/>
|
|
<parameter name="bmp_id2" type="uint8_t"/>
|
|
<parameter name="x2" type="uint8_t"/>
|
|
<parameter name="y2" type="uint8_t"/>
|
|
</operation>
|
|
<operation name="Tunnel_ctor" type="void" visibility="0x00" properties="0x01">
|
|
<code>uint8_t n;
|
|
Tunnel *me = &l_tunnel;
|
|
QActive_ctor(&me->super, (QStateHandler)&Tunnel_initial);
|
|
QTimeEvt_ctor(&me->blinkTimeEvt, BLINK_TIMEOUT_SIG);
|
|
QTimeEvt_ctor(&me->screenTimeEvt, SCREEN_TIMEOUT_SIG);
|
|
for (n = 0; n < GAME_MINES_MAX; ++n) {
|
|
me->mine1_pool[n] = Mine1_ctor(n); /* instantiate Mine1 in the pool */
|
|
me->mine2_pool[n] = Mine2_ctor(n); /* instantiate Mine2 in the pool */
|
|
me->mines[n] = (QHsm *)0; /* mine 'n' is unused */
|
|
}
|
|
me->last_mine_x = 0; /* the last mine at the right edge of the tunnel */
|
|
me->last_mine_y = 0;</code>
|
|
</operation>
|
|
<operation name="Ship_ctor" type="void" visibility="0x00" properties="0x01">
|
|
<code>Ship *me = &l_ship;
|
|
QActive_ctor(&me->super, (QStateHandler)&Ship_initial);
|
|
me->x = GAME_SHIP_X;
|
|
me->y = GAME_SHIP_Y;</code>
|
|
</operation>
|
|
<operation name="Missile_ctor" type="void" visibility="0x00" properties="0x01">
|
|
<code>Missile *me = &l_missile;
|
|
QActive_ctor(&me->super, (QStateHandler)&Missile_initial);</code>
|
|
</operation>
|
|
<operation name="Mine1_ctor" type="QHsm *" visibility="0x00" properties="0x01">
|
|
<parameter name="id" type="uint8_t"/>
|
|
<code>Mine1 *me;
|
|
Q_REQUIRE(id < GAME_MINES_MAX);
|
|
me = &l_mine1[id];
|
|
/* superclass' ctor */
|
|
QHsm_ctor(&me->super, (QStateHandler)&Mine1_initial);
|
|
return (QHsm *)me;</code>
|
|
</operation>
|
|
<operation name="Mine2_ctor" type="QHsm *" visibility="0x00" properties="0x01">
|
|
<parameter name="id" type="uint8_t"/>
|
|
<code>Mine2 *me;
|
|
Q_REQUIRE(id < GAME_MINES_MAX);
|
|
me = &l_mine2[id];
|
|
/* superclass' ctor */
|
|
QHsm_ctor(&me->super, (QStateHandler)&Mine2_initial);
|
|
return (QHsm *)me;</code>
|
|
</operation>
|
|
</package>
|
|
<directory name=".">
|
|
<file name="game.h">
|
|
<text>#ifndef game_h
|
|
#define game_h
|
|
|
|
enum GameSignals { /* signals used in the game */
|
|
TIME_TICK_SIG = Q_USER_SIG, /* published from tick ISR */
|
|
PLAYER_TRIGGER_SIG, /* published by Player (ISR) to trigger the Missile */
|
|
PLAYER_QUIT_SIG, /* published by Player (ISR) to quit the game */
|
|
GAME_OVER_SIG, /* published by Ship when it finishes exploding */
|
|
|
|
/* insert other published signals here ... */
|
|
MAX_PUB_SIG, /* the last published signal */
|
|
|
|
PLAYER_SHIP_MOVE_SIG, /* posted by Player (ISR) to the Ship to move it */
|
|
|
|
|
|
BLINK_TIMEOUT_SIG, /* signal for Tunnel's blink timeout event */
|
|
SCREEN_TIMEOUT_SIG, /* signal for Tunnel's screen timeout event */
|
|
|
|
TAKE_OFF_SIG, /* from Tunnel to Ship to grant permission to take off */
|
|
HIT_WALL_SIG, /* from Tunnel to Ship when Ship hits the wall */
|
|
HIT_MINE_SIG, /* from Mine to Ship or Missile when it hits the mine */
|
|
SHIP_IMG_SIG, /* from Ship to the Tunnel to draw and check for hits */
|
|
MISSILE_IMG_SIG, /* from Missile the Tunnel to draw and check for hits */
|
|
MINE_IMG_SIG, /* sent by Mine to the Tunnel to draw the mine */
|
|
MISSILE_FIRE_SIG, /* sent by Ship to the Missile to fire */
|
|
DESTROYED_MINE_SIG, /* from Missile to Ship when Missile destroyed Mine */
|
|
EXPLOSION_SIG, /* from any exploding object to render the explosion */
|
|
MINE_PLANT_SIG, /* from Tunnel to the Mine to plant it */
|
|
MINE_DISABLED_SIG, /* from Mine to Tunnel when it becomes disabled */
|
|
MINE_RECYCLE_SIG, /* sent by Tunnel to Mine to recycle the mine */
|
|
SCORE_SIG, /* from Ship to Tunnel to adjust game level based on score */
|
|
|
|
MAX_SIG /* the last signal (keep always last) */
|
|
};
|
|
|
|
$declare(Events::ObjectPosEvt)
|
|
$declare(Events::ObjectImageEvt)
|
|
$declare(Events::MineEvt)
|
|
$declare(Events::ScoreEvt)
|
|
|
|
#define GAME_SCREEN_WIDTH BSP_SCREEN_WIDTH
|
|
#define GAME_SCREEN_HEIGHT BSP_SCREEN_HEIGHT
|
|
#define GAME_MINES_MAX 5
|
|
#define GAME_MINES_DIST_MIN 10
|
|
#define GAME_SPEED_X 1
|
|
#define GAME_MISSILE_SPEED_X 2
|
|
#define GAME_SHIP_X 10
|
|
#define GAME_SHIP_Y (GAME_SCREEN_HEIGHT / 2)
|
|
|
|
enum GameBitmapIds {
|
|
PRESS_BUTTON_BMP,
|
|
SHIP_BMP,
|
|
MISSILE_BMP,
|
|
MINE1_BMP,
|
|
MINE2_BMP,
|
|
MINE2_MISSILE_BMP,
|
|
EXPLOSION0_BMP,
|
|
EXPLOSION1_BMP,
|
|
EXPLOSION2_BMP,
|
|
EXPLOSION3_BMP,
|
|
MAX_BMP
|
|
};
|
|
|
|
/* active objects' "constructors" */
|
|
$declare(AOs::Tunnel_ctor)
|
|
$declare(AOs::Ship_ctor)
|
|
$declare(AOs::Missile_ctor)
|
|
|
|
/* instantiation of the Mines orthogonal components */
|
|
$declare(AOs::Mine1_ctor)
|
|
$declare(AOs::Mine2_ctor)
|
|
|
|
/* opaque pointers to active objects in the application */
|
|
$declare(AOs::AO_Tunnel)
|
|
$declare(AOs::AO_Ship)
|
|
$declare(AOs::AO_Missile)
|
|
|
|
/* helper function for all AOs */
|
|
$declare(AOs::do_bitmaps_overlap)
|
|
|
|
#endif /* game_h */</text>
|
|
</file>
|
|
<file name="missile.c">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
/* Q_DEFINE_THIS_FILE */
|
|
|
|
/* local objects -----------------------------------------------------------*/
|
|
$declare(AOs::Missile)
|
|
static Missile l_missile; /* the sole instance of the Missile active object */
|
|
|
|
/* Public-scope objects ----------------------------------------------------*/
|
|
QActive * const AO_Missile = (QActive *)&l_missile; /* opaque pointer */
|
|
|
|
/* Active object definition ------------------------------------------------*/
|
|
$define(AOs::Missile_ctor)
|
|
$define(AOs::Missile)</text>
|
|
</file>
|
|
<file name="ship.c">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
/* Q_DEFINE_THIS_FILE */
|
|
|
|
#define SHIP_WIDTH 5
|
|
#define SHIP_HEIGHT 3
|
|
|
|
/* encapsulated delcaration of the Ship active object ----------------------*/
|
|
$declare(AOs::Ship)
|
|
|
|
/* local objects -----------------------------------------------------------*/
|
|
static Ship l_ship; /* the sole instance of the Ship active object */
|
|
|
|
/* Public-scope objects ----------------------------------------------------*/
|
|
QActive * const AO_Ship = (QActive *)&l_ship; /* opaque pointer */
|
|
|
|
/* Active object definition ------------------------------------------------*/
|
|
$define(AOs::Ship_ctor)
|
|
$define(AOs::Ship)</text>
|
|
</file>
|
|
<file name="tunnel.c">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
#include <string.h> /* for memmove() and memcpy() */
|
|
|
|
Q_DEFINE_THIS_FILE
|
|
|
|
/* local objects -----------------------------------------------------------*/
|
|
$declare(AOs::Tunnel)
|
|
static Tunnel l_tunnel; /* the sole instance of the Tunnel active object */
|
|
|
|
static uint32_t l_rnd; /* random seed */
|
|
static uint8_t l_walls[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8];
|
|
static uint8_t l_frame[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8];
|
|
|
|
/* local helper functions --------------------------------------------------*/
|
|
static void randomSeed(uint32_t seed);
|
|
static uint32_t random(void);
|
|
|
|
/* Public-scope objects ----------------------------------------------------*/
|
|
QActive * const AO_Tunnel = (QActive *)&l_tunnel; /* opaque pointer */
|
|
|
|
/* helper functions --------------------------------------------------------*/
|
|
|
|
/*
|
|
* The bitmap for the "Press Button" text:
|
|
*
|
|
* xxx.........................xxx........x...x...........
|
|
* x..x........................x..x.......x...x...........
|
|
* x..x.x.xx..xx...xxx..xxx....x..x.x..x.xxx.xxx..xx..xxx.
|
|
* xxx..xx...x..x.x....x.......xxx..x..x..x...x..x..x.x..x
|
|
* x....x....xxxx..xx...xx.....x..x.x..x..x...x..x..x.x..x
|
|
* x....x....x.......x....x....x..x.x..x..x...x..x..x.x..x
|
|
* x....x.....xxx.xxx..xxx.....xxx...xxx...x...x..xx..x..x
|
|
* .......................................................
|
|
*/
|
|
static uint8_t const press_button_bits[] = {
|
|
0x7F, 0x09, 0x09, 0x06, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x00,
|
|
0x38, 0x54, 0x54, 0x58, 0x00, 0x48, 0x54, 0x54, 0x24, 0x00,
|
|
0x48, 0x54, 0x54, 0x24, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x49,
|
|
0x49, 0x36, 0x00, 0x3C, 0x40, 0x40, 0x7C, 0x00, 0x04, 0x3F,
|
|
0x44, 0x00, 0x04, 0x3F, 0x44, 0x00, 0x38, 0x44, 0x44, 0x38,
|
|
0x00, 0x7C, 0x04, 0x04, 0x78
|
|
};
|
|
|
|
/* bitmap of the Ship:
|
|
*
|
|
* x....
|
|
* xxx..
|
|
* xxxxx
|
|
*/
|
|
static uint8_t const ship_bits[] = {
|
|
0x07, 0x06, 0x06, 0x04, 0x04
|
|
};
|
|
|
|
/* bitmap of the Missile:
|
|
*
|
|
* xxx
|
|
*/
|
|
static uint8_t const missile_bits[] = {
|
|
0x01, 0x01, 0x01
|
|
};
|
|
|
|
/* bitmap of the Mine type-1:
|
|
*
|
|
* .x.
|
|
* xxx
|
|
* .x.
|
|
*/
|
|
static uint8_t const mine1_bits[] = {
|
|
0x02, 0x07, 0x02
|
|
};
|
|
|
|
/* bitmap of the Mine type-2:
|
|
*
|
|
* x..x
|
|
* .xx.
|
|
* .xx.
|
|
* x..x
|
|
*/
|
|
static uint8_t const mine2_bits[] = {
|
|
0x09, 0x06, 0x06, 0x09
|
|
};
|
|
|
|
/* Mine type-2 is nastier than Mine type-1. The type-2 mine can
|
|
* hit the Ship with any of its "tentacles". However, it can be
|
|
* destroyed by the Missile only by hitting its center, defined as
|
|
* the following bitmap:
|
|
*
|
|
* ....
|
|
* .xx.
|
|
* .xx.
|
|
* ....
|
|
*/
|
|
static uint8_t const mine2_missile_bits[] = {
|
|
0x00, 0x06, 0x06, 0x00
|
|
};
|
|
|
|
/*
|
|
* The bitmap of the explosion stage 0:
|
|
*
|
|
* .......
|
|
* .......
|
|
* ...x...
|
|
* ..x.x..
|
|
* ...x...
|
|
* .......
|
|
* .......
|
|
*/
|
|
static uint8_t const explosion0_bits[] = {
|
|
0x00, 0x00, 0x08, 0x14, 0x08, 0x00, 0x00
|
|
};
|
|
|
|
/*
|
|
* The bitmap of the explosion stage 1:
|
|
*
|
|
* .......
|
|
* .......
|
|
* ..x.x..
|
|
* ...x...
|
|
* ..x.x..
|
|
* .......
|
|
* .......
|
|
*/
|
|
static uint8_t const explosion1_bits[] = {
|
|
0x00, 0x00, 0x14, 0x08, 0x14, 0x00, 0x00
|
|
};
|
|
|
|
/*
|
|
* The bitmap of the explosion stage 2:
|
|
*
|
|
* .......
|
|
* .x...x.
|
|
* ..x.x..
|
|
* ...x...
|
|
* ..x.x..
|
|
* .x...x.
|
|
* .......
|
|
*/
|
|
static uint8_t const explosion2_bits[] = {
|
|
0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00
|
|
};
|
|
|
|
/*
|
|
* The bitmap of the explosion stage 3:
|
|
*
|
|
* x..x..x
|
|
* .x.x.x.
|
|
* ..x.x..
|
|
* xx.x.xx
|
|
* ..x.x..
|
|
* .x.x.x.
|
|
* x..x..x
|
|
*/
|
|
static uint8_t const explosion3_bits[] = {
|
|
0x49, 0x2A, 0x14, 0x6B, 0x14, 0x2A, 0x49
|
|
};
|
|
|
|
typedef struct BitmapTag { /* the auxiliary structure to hold const bitmaps */
|
|
uint8_t const *bits; /* the bits in the bitmap */
|
|
uint8_t width; /* the width of the bitmap */
|
|
} Bitmap;
|
|
|
|
static Bitmap const l_bitmap[MAX_BMP] = {
|
|
{ press_button_bits, Q_DIM(press_button_bits) },
|
|
{ ship_bits, Q_DIM(ship_bits) },
|
|
{ missile_bits, Q_DIM(missile_bits) },
|
|
{ mine1_bits, Q_DIM(mine1_bits) },
|
|
{ mine2_bits, Q_DIM(mine2_bits) },
|
|
{ mine2_missile_bits, Q_DIM(mine2_missile_bits) },
|
|
{ explosion0_bits, Q_DIM(explosion0_bits) },
|
|
{ explosion1_bits, Q_DIM(explosion1_bits) },
|
|
{ explosion2_bits, Q_DIM(explosion2_bits) },
|
|
{ explosion3_bits, Q_DIM(explosion3_bits) }
|
|
};
|
|
|
|
/* Active object definition ================================================*/
|
|
$define(AOs::Tunnel_ctor)
|
|
$define(AOs::Tunnel)
|
|
|
|
/*..........................................................................*/
|
|
uint32_t random(void) { /* a very cheap pseudo-random-number generator */
|
|
/* "Super-Duper" Linear Congruential Generator (LCG)
|
|
* LCG(2^32, 3*7*11*13*23, 0, seed)
|
|
*/
|
|
l_rnd = l_rnd * (3*7*11*13*23);
|
|
return l_rnd >> 8;
|
|
}
|
|
/*..........................................................................*/
|
|
void randomSeed(uint32_t seed) {
|
|
l_rnd = seed;
|
|
}
|
|
/*..........................................................................*/
|
|
uint8_t do_bitmaps_overlap(uint8_t bmp_id1, uint8_t x1, uint8_t y1,
|
|
uint8_t bmp_id2, uint8_t x2, uint8_t y2)
|
|
{
|
|
uint8_t x;
|
|
uint8_t x0;
|
|
uint8_t w;
|
|
uint32_t bits1;
|
|
uint32_t bits2;
|
|
Bitmap const *bmp1;
|
|
Bitmap const *bmp2;
|
|
|
|
Q_REQUIRE((bmp_id1 < Q_DIM(l_bitmap)) && (bmp_id2 < Q_DIM(l_bitmap)));
|
|
|
|
bmp1 = &l_bitmap[bmp_id1];
|
|
bmp2 = &l_bitmap[bmp_id2];
|
|
|
|
/* is the incoming object starting to overlap the Mine bitmap? */
|
|
if ((x1 <= x2) && (x1 + bmp2->width > x2)) {
|
|
x0 = x2 - x1;
|
|
w = x1 + bmp2->width - x2;
|
|
if (w > bmp1->width) {
|
|
w = bmp1->width;
|
|
}
|
|
for (x = 0; x < w; ++x) { /* scan over the overlapping columns */
|
|
bits1 = ((uint32_t)bmp2->bits[x + x0] << y2);
|
|
bits2 = ((uint32_t)bmp1->bits[x] << y1);
|
|
if ((bits1 & bits2) != 0) { /* do the bits overlap? */
|
|
return (uint8_t)1; /* yes! */
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ((x1 > x2) && (x2 + bmp1->width > x1)) {
|
|
x0 = x1 - x2;
|
|
w = x2 + bmp1->width - x1;
|
|
if (w > bmp2->width) {
|
|
w = bmp2->width;
|
|
}
|
|
for (x = 0; x < w; ++x) { /* scan over the overlapping columns */
|
|
bits1 = ((uint32_t)bmp1->bits[x + x0] << y1);
|
|
bits2 = ((uint32_t)bmp2->bits[x] << y2);
|
|
if ((bits1 & bits2) != 0) { /* do the bits overlap? */
|
|
return (uint8_t)1; /* yes! */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (uint8_t)0; /* the bitmaps do not overlap */
|
|
}</text>
|
|
</file>
|
|
<file name="mine1.c">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
Q_DEFINE_THIS_FILE
|
|
|
|
/* encapsulated delcaration of the Mine1 HSM -------------------------------*/
|
|
$declare(AOs::Mine1)
|
|
|
|
/* local objects -----------------------------------------------------------*/
|
|
static Mine1 l_mine1[GAME_MINES_MAX]; /* a pool of type-1 mines */
|
|
|
|
/* helper macro to provide the ID of this mine */
|
|
#define MINE_ID(me_) ((uint8_t)((me_) - l_mine1))
|
|
|
|
/* Mine1 class definition --------------------------------------------------*/
|
|
$define(AOs::Mine1_ctor)
|
|
$define(AOs::Mine1)</text>
|
|
</file>
|
|
<file name="mine2.c">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
Q_DEFINE_THIS_FILE
|
|
|
|
/* encapsulated delcaration of the Mine2 HSM -------------------------------*/
|
|
$declare(AOs::Mine2)
|
|
|
|
/* local objects -----------------------------------------------------------*/
|
|
static Mine2 l_mine2[GAME_MINES_MAX]; /* a pool of type-2 mines */
|
|
|
|
/* helper macro to provide the ID of this mine */
|
|
#define MINE_ID(me_) ((uint8_t)((me_) - l_mine2))
|
|
|
|
/* Mine2 class definition --------------------------------------------------*/
|
|
$define(AOs::Mine2_ctor)
|
|
$define(AOs::Mine2)</text>
|
|
</file>
|
|
<file name="main.c">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
/* Local-scope objects -----------------------------------------------------*/
|
|
static QEvt const * l_missileQueueSto[2];
|
|
static QEvt const * l_shipQueueSto[3];
|
|
static QEvt const * l_tunnelQueueSto[GAME_MINES_MAX + 5];
|
|
|
|
static QF_MPOOL_EL(QEvt) l_smlPoolSto[10];
|
|
static QF_MPOOL_EL(ObjectImageEvt) l_medPoolSto[2*GAME_MINES_MAX + 10];
|
|
|
|
static QSubscrList l_subscrSto[MAX_PUB_SIG];
|
|
|
|
/*..........................................................................*/
|
|
int main() {
|
|
/* explicitly invoke the active objects' ctors... */
|
|
Missile_ctor();
|
|
Ship_ctor();
|
|
Tunnel_ctor();
|
|
|
|
QF_init(); /* initialize the framework and the underlying RT kernel */
|
|
|
|
BSP_init(); /* initialize the Board Support Package */
|
|
|
|
/* initialize the event pools... */
|
|
QF_poolInit(l_smlPoolSto, sizeof(l_smlPoolSto), sizeof(l_smlPoolSto[0]));
|
|
QF_poolInit(l_medPoolSto, sizeof(l_medPoolSto), sizeof(l_medPoolSto[0]));
|
|
|
|
QF_psInit(l_subscrSto, Q_DIM(l_subscrSto)); /* init publish-subscribe */
|
|
|
|
/* send object dictionaries for event queues... */
|
|
QS_OBJ_DICTIONARY(l_missileQueueSto);
|
|
QS_OBJ_DICTIONARY(l_shipQueueSto);
|
|
QS_OBJ_DICTIONARY(l_tunnelQueueSto);
|
|
|
|
/* send object dictionaries for event pools... */
|
|
QS_OBJ_DICTIONARY(l_smlPoolSto);
|
|
QS_OBJ_DICTIONARY(l_medPoolSto);
|
|
|
|
/* send signal dictionaries for globally published events... */
|
|
QS_SIG_DICTIONARY(TIME_TICK_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(PLAYER_TRIGGER_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(PLAYER_QUIT_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(GAME_OVER_SIG, (void *)0);
|
|
|
|
/* start the active objects... */
|
|
QActive_start(AO_Missile,
|
|
1U, /* priority */
|
|
l_missileQueueSto, Q_DIM(l_missileQueueSto), /* evt queue */
|
|
(void *)0, 0U, /* no per-thread stack */
|
|
(QEvt *)0); /* no initialization event */
|
|
QActive_start(AO_Ship,
|
|
2U, /* priority */
|
|
l_shipQueueSto, Q_DIM(l_shipQueueSto), /* evt queue */
|
|
(void *)0, 0U, /* no per-thread stack */
|
|
(QEvt *)0); /* no initialization event */
|
|
QActive_start(AO_Tunnel,
|
|
3U, /* priority */
|
|
l_tunnelQueueSto, Q_DIM(l_tunnelQueueSto), /* evt queue */
|
|
(void *)0, 0U, /* no per-thread stack */
|
|
(QEvt *)0); /* no initialization event */
|
|
|
|
return QF_run(); /* run the QF application */
|
|
}
|
|
</text>
|
|
</file>
|
|
</directory>
|
|
</model>
|