1698 lines
64 KiB
Plaintext
Raw Normal View History

2012-08-14 18:00:48 -04:00
<?xml version="1.0" encoding="UTF-8"?>
2013-10-10 20:01:51 -04:00
<model version="2.3.2">
2012-08-14 18:00:48 -04:00
<documentation>&quot;Fly 'n' Shoot&quot; game model from Chapters 1 &amp; 9 of PSiCC2</documentation>
<framework name="qpcpp"/>
2013-10-10 20:01:51 -04:00
<package name="Qt-port" stereotype="0x00" namespace="QP::">
<class name="GuiQActive" superclass="qpcpp::QActive">
<operation name="GuiQActive" type="QActive(initial)" visibility="0x00" properties="0x00">
<parameter name="initial" type="QStateHandler"/>
</operation>
<operation name="start" type="void" visibility="0x00" properties="0x00">
<documentation>Starts execution of an active object and registers the object with the framework. This function is strongly OS-dependent and must be defined in the QP port to a particular platform.
The function takes six arguments:
'prio' is the priority of the active object. QP allows you to start up to 63 active objects, each one having a *unique* priority number between 1 and 63 inclusive, where higher numerical values correspond to higher priority (urgency) of the active object relative to the others.
'qSto[]' and 'qLen' arguments are the storage and size of the event queue used by this active object.
'stkSto' and 'stkSize' are the stack storage and size in bytes. Please note that a per-active object stack is used only when the underlying OS requies it. If the stack is not required, or the underlying OS allocates the stack internally, the stkSto should be NULL and/or stkSize should be 0.
'ie' is an optional initialization event that can be used to pass additional startup data to the active object. (Pass NULL if your active object does not expect the initialization event).</documentation>
<parameter name="prio" type="uint8_t"/>
<parameter name="qSto[]" type="QEvt const *"/>
<parameter name="qLen" type="uint32_t"/>
<parameter name="stkSto" type="void *"/>
<parameter name="stkSize" type="uint32_t"/>
<parameter name="ie" type="QEvt const *"/>
<code>// Example:
static Table l_table; // Table active object instance
static QEvt const *l_tableQueueSto[N]; // storage for Table queue
static int l_tableStk[256]; // storage for the stack for Table AO
. . .
int main() {
TableEvt ie; // initialization event for the Table AO
. . .
ie.philNum = n; // build the initialization event
. . .
l_table.start(
6, // unique priority (1..QF_MAX_ACTIVE)
l_tableQueueSto, // event queue of the active object
Q_DIM(l_tableQueueSto),// the depth of the event queue
l_tableStk, // the stack of the acitve object (optional)
sizeof(l_tableStk), // the size of the stack in bytes (optional)
&amp;ie); // initialization event (optional)
. . .
}</code>
</operation>
<operation name="postFIFO" type="void" visibility="0x00" properties="0x00">
<documentation>Posts an event e directly to the event queue of the acitve object me using the First-In-First-Out (FIFO) policy.
Direct event posting is the simplest asynchronous communication method available in QP.
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
<parameter name="e" type="QEvt const *"/>
<code>// Example:
extern QActive *AO_Table;
. . .
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
pe-&gt;philNum = me-&gt;num;
AO_Table-&gt;postFIFO(pe); // &lt;==</code>
</operation>
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
<documentation>Posts an event e directly to the event queue of the acitve object me using the Last-In-First-Out (LIFO) policy.
Direct event posting is the simplest asynchronous communication method available in QP.
NOTE: You should be very careful with the LIFO (Last In First Out) policy, because it *reverses* the order of events in the queue. Typically, the QActive_postLIFO() operation shuould be only used for self-posting of events as reminders (see the &quot;Reminder&quot; state pattern) for continuing a processing. The postLIFO() operation is also used in the QActive::recall() operation.
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
<parameter name="e" type="QEvt const *"/>
<code>// Example:
. . .
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
pe-&gt;philNum = me-&gt;num;
. . .
me-&gt;postLIFO(pe); // &lt;==</code>
</operation>
</class>
<class name="GuiQMActive" superclass="qpcpp::QActive">
<operation name="GuiQMActive" type="QMActive(initial)" visibility="0x00" properties="0x00">
<parameter name="initial" type="QStateHandler"/>
</operation>
<operation name="start" type="void" visibility="0x00" properties="0x00">
<documentation>Starts execution of an active object and registers the object with the framework. This function is strongly OS-dependent and must be defined in the QP port to a particular platform.
The function takes six arguments:
'prio' is the priority of the active object. QP allows you to start up to 63 active objects, each one having a *unique* priority number between 1 and 63 inclusive, where higher numerical values correspond to higher priority (urgency) of the active object relative to the others.
'qSto[]' and 'qLen' arguments are the storage and size of the event queue used by this active object.
'stkSto' and 'stkSize' are the stack storage and size in bytes. Please note that a per-active object stack is used only when the underlying OS requies it. If the stack is not required, or the underlying OS allocates the stack internally, the stkSto should be NULL and/or stkSize should be 0.
'ie' is an optional initialization event that can be used to pass additional startup data to the active object. (Pass NULL if your active object does not expect the initialization event).</documentation>
<parameter name="prio" type="uint8_t"/>
<parameter name="qSto[]" type="QEvt const *"/>
<parameter name="qLen" type="uint32_t"/>
<parameter name="stkSto" type="void *"/>
<parameter name="stkSize" type="uint32_t"/>
<parameter name="ie" type="QEvt const *"/>
<code>// Example:
static Table l_table; // Table active object instance
static QEvt const *l_tableQueueSto[N]; // storage for Table queue
static int l_tableStk[256]; // storage for the stack for Table AO
. . .
int main() {
TableEvt ie; // initialization event for the Table AO
. . .
ie.philNum = n; // build the initialization event
. . .
l_table.start(
6, // unique priority (1..QF_MAX_ACTIVE)
l_tableQueueSto, // event queue of the active object
Q_DIM(l_tableQueueSto),// the depth of the event queue
l_tableStk, // the stack of the acitve object (optional)
sizeof(l_tableStk), // the size of the stack in bytes (optional)
&amp;ie); // initialization event (optional)
. . .
}</code>
</operation>
<operation name="postFIFO" type="void" visibility="0x00" properties="0x00">
<documentation>Posts an event e directly to the event queue of the acitve object me using the First-In-First-Out (FIFO) policy.
Direct event posting is the simplest asynchronous communication method available in QP.
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
<parameter name="e" type="QEvt const *"/>
<code>// Example:
extern QActive *AO_Table;
. . .
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
pe-&gt;philNum = me-&gt;num;
AO_Table-&gt;postFIFO(pe); // &lt;==</code>
</operation>
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
<documentation>Posts an event e directly to the event queue of the acitve object me using the Last-In-First-Out (LIFO) policy.
Direct event posting is the simplest asynchronous communication method available in QP.
NOTE: You should be very careful with the LIFO (Last In First Out) policy, because it *reverses* the order of events in the queue. Typically, the QActive_postLIFO() operation shuould be only used for self-posting of events as reminders (see the &quot;Reminder&quot; state pattern) for continuing a processing. The postLIFO() operation is also used in the QActive::recall() operation.
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
<parameter name="e" type="QEvt const *"/>
<code>// Example:
. . .
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
pe-&gt;philNum = me-&gt;num;
. . .
me-&gt;postLIFO(pe); // &lt;==</code>
</operation>
</class>
</package>
2012-08-14 18:00:48 -04:00
<package name="Events" stereotype="0x01" namespace="GAME::">
<class name="ObjectPosEvt" superclass="qpcpp::QEvt">
<attribute name="x" type="uint8_t" visibility="0x00" properties="0x00"/>
<attribute name="y" type="uint8_t" visibility="0x00" properties="0x00"/>
<operation name="ObjectPosEvt" type="QEvt(sig), x(x_p), y(y_p)" visibility="0x00" properties="0x02">
<parameter name="sig" type="QP::QSignal"/>
<parameter name="x_p" type="uint8_t"/>
<parameter name="y_p" type="uint8_t"/>
</operation>
</class>
<class name="ObjectImageEvt" superclass="qpcpp::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"/>
<operation name="ObjectImageEvt" type="QEvt(sig), x(x_p), y(y_p), bmp(bmp_p)" visibility="0x00" properties="0x02">
<parameter name="sig" type="QP::QSignal"/>
<parameter name="x_p" type="uint8_t"/>
<parameter name="y_p" type="uint8_t"/>
<parameter name="bmp_p" type="uint8_t"/>
</operation>
</class>
<class name="MineEvt" superclass="qpcpp::QEvt">
<attribute name="id" type="uint8_t" visibility="0x00" properties="0x00"/>
<operation name="MineEvt" type="QEvt(sig), id(id_p)" visibility="0x00" properties="0x02">
<parameter name="sig" type="QP::QSignal"/>
<parameter name="id_p" type="uint8_t"/>
</operation>
</class>
<class name="ScoreEvt" superclass="qpcpp::QEvt">
<attribute name="score" type="uint16_t" visibility="0x00" properties="0x00"/>
<operation name="ScoreEvt" type="QEvt(sig), score(score_p)" visibility="0x00" properties="0x02">
<parameter name="sig" type="QP::QSignal"/>
<parameter name="score_p" type="uint16_t"/>
</operation>
</class>
</package>
<package name="AOs" stereotype="0x02" namespace="GAME::">
2013-10-10 20:01:51 -04:00
<class name="Tunnel" superclass="Qt-port::GuiQActive">
2012-08-14 18:00:48 -04:00
<documentation>Tunnel Active Object</documentation>
<attribute name="m_blinkTimeEvt" type="QP::QTimeEvt" visibility="0x02" properties="0x00"/>
<attribute name="m_screenTimeEvt" type="QP::QTimeEvt" visibility="0x02" properties="0x00"/>
<attribute name="m_mines[GAME_MINES_MAX]" type="QP::QHsm *" visibility="0x02" properties="0x00"/>
<attribute name="m_mine1_pool[GAME_MINES_MAX]" type="QP::QHsm *" visibility="0x02" properties="0x00"/>
<attribute name="m_mine2_pool[GAME_MINES_MAX]" type="QP::QHsm *" visibility="0x02" properties="0x00"/>
<attribute name="m_blink_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_last_mine_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_last_mine_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_wall_thickness_top" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_wall_thickness_bottom" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_minimal_gap" type="uint8_t" visibility="0x02" properties="0x00"/>
2013-10-10 20:01:51 -04:00
<operation name="Tunnel" type="GuiQActive(Q_STATE_CAST(&amp;Tunnel::initial)), m_blinkTimeEvt(BLINK_TIMEOUT_SIG), m_screenTimeEvt(SCREEN_TIMEOUT_SIG), m_last_mine_x(0U), m_last_mine_y(0U)" visibility="0x00" properties="0x00">
2012-08-14 18:00:48 -04:00
<code>for (uint8_t n = 0U; n &lt; GAME_MINES_MAX; ++n) {
m_mine1_pool[n] = Mine1_getInst(n); // initialize mine1-type pool
m_mine2_pool[n] = Mine2_getInst(n); // initialize mine2-type pool
m_mines[n] = (QHsm *)0; // mine 'n' is unused
}</code>
</operation>
<operation name="advance" type="void" visibility="0x02" properties="0x00">
<code>uint32_t bmp1; // bimap representing 1 column of the image
uint32_t rnd = (random() &amp; 0xFFU);
// reduce the top wall thickness 18.75% of the time
if ((rnd &lt; 48U) &amp;&amp; (m_wall_thickness_top &gt; 0U)) {
--m_wall_thickness_top;
}
// reduce the bottom wall thickness 18.75% of the time
if ((rnd &gt; 208U) &amp;&amp; (m_wall_thickness_bottom &gt; 0U)) {
--m_wall_thickness_bottom;
}
rnd = (random() &amp; 0xFFU);
// grow the top wall thickness 18.75% of the time
if ((rnd &lt; 48U)
&amp;&amp; ((GAME_SCREEN_HEIGHT
- m_wall_thickness_top
- m_wall_thickness_bottom) &gt; m_minimal_gap)
&amp;&amp; ((m_last_mine_x &lt; (GAME_SCREEN_WIDTH - 5U))
|| (m_last_mine_y &gt; (m_wall_thickness_top + 1U))))
{
++m_wall_thickness_top;
}
// grow the bottom wall thickness 18.75% of the time
if ((rnd &gt; 208U)
&amp;&amp; ((GAME_SCREEN_HEIGHT
- m_wall_thickness_top
- m_wall_thickness_bottom) &gt; m_minimal_gap)
&amp;&amp; ((m_last_mine_x &lt; (GAME_SCREEN_WIDTH - 5U))
|| (m_last_mine_y + 1U
&lt; (GAME_SCREEN_HEIGHT - m_wall_thickness_bottom))))
{
++m_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 &lt;&lt; m_wall_thickness_top))
| (~0U &lt;&lt; (GAME_SCREEN_HEIGHT
- m_wall_thickness_bottom));
l_walls[GAME_SCREEN_WIDTH - 1] = (uint8_t)bmp1;
l_walls[GAME_SCREEN_WIDTH + GAME_SCREEN_WIDTH - 1] = (uint8_t)(bmp1 &gt;&gt; 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() &amp; 0xFFU);
if (m_last_mine_x &gt; 0U) {
--m_last_mine_x; // shift the last Mine 1 position to the left
}
// last mine far enough?
if ((m_last_mine_x + GAME_MINES_DIST_MIN &lt; GAME_SCREEN_WIDTH)
&amp;&amp; (rnd &lt; 8U)) // place the mines only 5% of the time
{
uint8_t n;
for (n = 0U; n &lt; Q_DIM(m_mines); ++n) { // look for disabled mines
if (m_mines[n] == (QHsm *)0) {
break;
}
}
if (n &lt; Q_DIM(m_mines)) { // a disabled Mine found?
rnd = (random() &amp; 0xFFFFU);
if ((rnd &amp; 1U) == 0U) { // choose the type of the mine
m_mines[n] = m_mine1_pool[n];
}
else {
m_mines[n] = m_mine2_pool[n];
}
// new Mine is planted in the last column of the tunnel
m_last_mine_x = GAME_SCREEN_WIDTH;
// choose a random y-position for the Mine in the Tunnel
rnd %= (GAME_SCREEN_HEIGHT
- m_wall_thickness_top
- m_wall_thickness_bottom - 4U);
m_last_mine_y = (uint8_t)(m_wall_thickness_top + 2U + rnd);
// event to dispatch to the Mine
ObjectPosEvt ope(MINE_PLANT_SIG,
m_last_mine_x, m_last_mine_y);
m_mines[n]-&gt;dispatch(&amp;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>Q_REQUIRE(bmp &lt; Q_DIM(l_bitmap));
uint8_t w = l_bitmap[bmp].width;
if (w &gt; GAME_SCREEN_WIDTH - x_pos) {
w = GAME_SCREEN_WIDTH - x_pos;
}
for (uint8_t x = 0U; x &lt; w; ++x) {
uint32_t bmp1;
if (y_pos &gt;= 0) {
bmp1 = (l_bitmap[bmp].bits[x] &lt;&lt; (uint8_t)y_pos);
}
else {
bmp1 = (l_bitmap[bmp].bits[x] &gt;&gt; (uint8_t)(-y_pos));
}
l_frame[x_pos + x] |= (uint8_t)bmp1;
l_frame[x_pos + x + GAME_SCREEN_WIDTH] |= (uint8_t)(bmp1 &gt;&gt; 8);
}</code>
</operation>
<operation name="dispatchToAllMines" type="void" visibility="0x02" properties="0x00">
<parameter name="e" type="QP::QEvt const *"/>
<code>for (uint8_t n = 0U; n &lt; GAME_MINES_MAX; ++n) {
if (m_mines[n] != (QHsm *)0) { // is the mine used?
m_mines[n]-&gt;dispatch(e);
}
}</code>
</operation>
<operation name="isWallHit" type="bool" 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>Q_REQUIRE(bmp &lt; Q_DIM(l_bitmap));
uint8_t w = l_bitmap[bmp].width;
if (w &gt; GAME_SCREEN_WIDTH - x_pos) {
w = GAME_SCREEN_WIDTH - x_pos;
}
for (uint8_t x = 0U; x &lt; w; ++x) {
uint32_t bmp1 = ((uint32_t)l_bitmap[bmp].bits[x] &lt;&lt; y_pos);
if (((l_walls[x_pos + x] &amp; (uint8_t)bmp1) != 0U)
|| ((l_walls[x_pos + x + GAME_SCREEN_WIDTH]
&amp; (uint8_t)(bmp1 &gt;&gt; 8)) != 0))
{
return true;
}
}
return false;</code>
</operation>
<statechart>
<initial target="../1/2">
<action>for (uint8_t n = 0; n &lt; GAME_MINES_MAX; ++n) {
me-&gt;m_mine1_pool[n]-&gt;init(); // take the initial tran. for Mine1
me-&gt;m_mine2_pool[n]-&gt;init(); // take the initial tran. for Mine2
}
randomSeed(1234); // seed the pseudo-random generator
me-&gt;subscribe(TIME_TICK_SIG);
me-&gt;subscribe(PLAYER_TRIGGER_SIG);
me-&gt;subscribe(PLAYER_QUIT_SIG);
QS_OBJ_DICTIONARY(&amp;l_tunnel); // object dictionary for Tunnel object
QS_OBJ_DICTIONARY(&amp;l_tunnel.m_blinkTimeEvt);
QS_OBJ_DICTIONARY(&amp;l_tunnel.m_screenTimeEvt);
QS_FUN_DICTIONARY(&amp;Tunnel::initial); // fun. dictionaries for Tunnel HSM
QS_FUN_DICTIONARY(&amp;Tunnel::final);
QS_FUN_DICTIONARY(&amp;Tunnel::active);
QS_FUN_DICTIONARY(&amp;Tunnel::playing);
QS_FUN_DICTIONARY(&amp;Tunnel::demo);
QS_FUN_DICTIONARY(&amp;Tunnel::game_over);
QS_FUN_DICTIONARY(&amp;Tunnel::screen_saver);
QS_FUN_DICTIONARY(&amp;Tunnel::screen_saver_hide);
QS_FUN_DICTIONARY(&amp;Tunnel::screen_saver_show);
QS_SIG_DICTIONARY(BLINK_TIMEOUT_SIG, &amp;l_tunnel); // local signals
QS_SIG_DICTIONARY(SCREEN_TIMEOUT_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(SHIP_IMG_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(MINE_IMG_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(EXPLOSION_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(SCORE_SIG, &amp;l_tunnel);</action>
2013-10-10 20:01:51 -04:00
<initial_glyph conn="2,2,5,1,26,14,-2">
2012-08-14 18:00:48 -04:00
<action box="1,-2,11,2"/>
</initial_glyph>
</initial>
<state name="active">
<tran trig="MINE_DISABLED">
<action>Q_ASSERT((Q_EVT_CAST(MineEvt)-&gt;id &lt; GAME_MINES_MAX)
&amp;&amp; (me-&gt;m_mines[Q_EVT_CAST(MineEvt)-&gt;id] != (QHsm *)0));
me-&gt;m_mines[Q_EVT_CAST(MineEvt)-&gt;id] = (QHsm *)0;</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="2,9,3,-1,15">
2012-08-14 18:00:48 -04:00
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<tran trig="PLAYER_QUIT" target="../../2">
2013-10-10 20:01:51 -04:00
<tran_glyph conn="2,12,3,1,62,76,-38">
2012-08-14 18:00:48 -04:00
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
2013-10-10 20:01:51 -04:00
<state name="show_logo">
<entry>me-&gt;m_blinkTimeEvt.postEvery(me, BSP_TICKS_PER_SEC/2U); // 1/2 sec
me-&gt;m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*5U); // 5 sec timeout
me-&gt;m_blink_ctr = 0U;
BSP_drawNString(0U, 0U, &quot; Quantum LeAps &quot;);
BSP_drawNString(0U, 1U, &quot;state-machine.co&quot;);</entry>
<exit>me-&gt;m_blinkTimeEvt.disarm();
me-&gt;m_screenTimeEvt.disarm();</exit>
<tran trig="SCREEN_TIMEOUT" target="../../3">
<tran_glyph conn="4,26,3,1,24,6,-2">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<tran trig="BLINK_TIMEOUT">
<action>me-&gt;m_blink_ctr ^= 1U; // toggle the blink couner</action>
<choice>
<guard>me-&gt;m_blink_ctr == 0U</guard>
<action>BSP_drawNString(6U*9U, 0U, &quot; LeAps&quot;);
BSP_drawNString(0U, 1U, &quot;state-machine.co&quot;);</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, &quot;LeaPs &quot;);
BSP_drawNString(0U, 1U, &quot;tate-machine.com&quot;);</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,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
2012-08-14 18:00:48 -04:00
<state name="demo">
<entry>me-&gt;m_last_mine_x = 0U; // last mine at right edge of the tunnel
me-&gt;m_last_mine_y = 0U;
// set the tunnel properties...
me-&gt;m_wall_thickness_top = 0U;
me-&gt;m_wall_thickness_bottom = 0U;
me-&gt;m_minimal_gap = GAME_SCREEN_HEIGHT - 3U;
// erase the tunnel walls
memset(l_walls, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
me-&gt;m_blinkTimeEvt.postEvery(me, BSP_TICKS_PER_SEC/2U); // 1/2 sec
me-&gt;m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*20U); // 20 sec
me-&gt;m_blink_ctr = 0U; // init the blink counter</entry>
<exit>me-&gt;m_blinkTimeEvt.disarm();
me-&gt;m_screenTimeEvt.disarm();</exit>
<tran trig="BLINK_TIMEOUT">
<action>me-&gt;m_blink_ctr ^= 1U; /* toggle the blink cunter */</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,42,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="SCREEN_TIMEOUT" target="../../5">
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,45,3,3,28">
2012-08-14 18:00:48 -04:00
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="TIME_TICK">
<action>me-&gt;advance();
if (me-&gt;m_blink_ctr != 0U) {
// add the text bitmap into the frame buffer
me-&gt;addImageAt(PRESS_BUTTON_BMP,
(GAME_SCREEN_WIDTH - 55U)/2U,
(GAME_SCREEN_HEIGHT - 8U)/2U);
}
BSP_drawBitmap(l_frame);</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,39,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,12,2"/>
</tran_glyph>
</tran>
2013-10-10 20:01:51 -04:00
<tran trig="PLAYER_TRIGGER" target="../../6">
<tran_glyph conn="4,48,3,1,24,6,-2">
2012-08-14 18:00:48 -04:00
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
2013-10-10 20:01:51 -04:00
<state_glyph node="4,30,22,20">
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state name="game_over">
<entry>me-&gt;m_blinkTimeEvt.postEvery(me, BSP_TICKS_PER_SEC/2U); // 1/2 sec
me-&gt;m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*5U); // 5 sec timeout
me-&gt;m_blink_ctr = 0U;
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U, &quot;Game Over&quot;);</entry>
<exit>me-&gt;m_blinkTimeEvt.disarm();
me-&gt;m_screenTimeEvt.disarm();
BSP_updateScore(0U); // update the score on the display</exit>
<tran trig="BLINK_TIMEOUT">
<action>me-&gt;m_blink_ctr ^= 1U; // toggle the blink couner
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U,
((me-&gt;m_blink_ctr == 0U)
? &quot;Game Over&quot;
: &quot; &quot;));</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,28,-11,-30,-19,-4">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<state_glyph node="32,68,26,14">
2012-08-14 18:00:48 -04:00
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
2013-10-10 20:01:51 -04:00
<state name="screen_saver">
<initial target="../2">
<initial_glyph conn="33,35,5,1,20,7,-2">
<action box="1,-2,6,2"/>
</initial_glyph>
</initial>
<tran trig="PLAYER_TRIGGER" target="../../3">
<tran_glyph conn="32,38,3,1,28,-8,-30,4,-4">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state name="screen_saver_hide">
<entry>BSP_displayOff(); // power down the display
me-&gt;m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*3U); // 3s timeout</entry>
<exit>me-&gt;m_screenTimeEvt.disarm();
BSP_displayOn(); // power up the display</exit>
<tran trig="SCREEN_TIMEOUT" target="../../3">
<tran_glyph conn="34,48,3,1,19,6,-2">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state_glyph node="34,40,17,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));
me-&gt;addImageAt(PRESS_BUTTON_BMP,
(uint8_t)(rnd % (GAME_SCREEN_WIDTH - 55U)),
(int8_t) (rnd % (GAME_SCREEN_HEIGHT - 8U)));
BSP_drawBitmap(l_frame);
me-&gt;m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC/3U); // 1/3 sec timeout</entry>
<exit>me-&gt;m_screenTimeEvt.disarm();
// 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="34,60,3,1,21,-15,-4">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state_glyph node="34,52,17,10">
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state_glyph node="32,31,26,33"/>
</state>
2012-08-14 18:00:48 -04:00
<state name="playing">
<entry>static QP::QEvt const takeoff(TAKE_OFF_SIG);
me-&gt;m_minimal_gap = GAME_SCREEN_HEIGHT - 3U;
// erase the walls
memset(l_walls, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
AO_Ship-&gt;POST(&amp;takeoff, me); // post the TAKEOFF sig</entry>
<exit>static QP::QEvt const recycle(MINE_RECYCLE_SIG);
me-&gt;dispatchToAllMines(&amp;recycle); // recycle all Mines</exit>
<tran trig="TIME_TICK">
<action>// render this frame on the display
BSP_drawBitmap(l_frame);
me-&gt;advance();
me-&gt;plantMine();
me-&gt;dispatchToAllMines(e);</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,61,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="SHIP_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
int8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;
// did the Ship/Missile hit the tunnel wall?
if (me-&gt;isWallHit(bmp, x, y)) {
static QP::QEvt const hit(HIT_WALL_SIG);
AO_Ship-&gt;POST(&amp;hit, me);
}
me-&gt;addImageAt(bmp, x, y);
me-&gt;dispatchToAllMines(e); // let Mines check for hits</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,64,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="MISSILE_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
int8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;
// did the Ship/Missile hit the tunnel wall?
if (me-&gt;isWallHit(bmp, x, y)) {
static QP::QEvt const hit(HIT_WALL_SIG);
AO_Missile-&gt;POST(&amp;hit, me);
}
me-&gt;addImageAt(bmp, x, y);
me-&gt;dispatchToAllMines(e); // let Mines check for hits</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,67,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,12,2"/>
</tran_glyph>
</tran>
<tran trig="MINE_IMG">
<action>me-&gt;addImageAt(Q_EVT_CAST(ObjectImageEvt)-&gt;bmp,
Q_EVT_CAST(ObjectImageEvt)-&gt;x,
Q_EVT_CAST(ObjectImageEvt)-&gt;y);</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,70,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="EXPLOSION">
<action>me-&gt;addImageAt(Q_EVT_CAST(ObjectImageEvt)-&gt;bmp,
Q_EVT_CAST(ObjectImageEvt)-&gt;x,
Q_EVT_CAST(ObjectImageEvt)-&gt;y);</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,73,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<tran trig="SCORE">
<action>BSP_updateScore(Q_EVT_CAST(ScoreEvt)-&gt;score);
// increase difficulty of the game:
// the tunnel gets narrower as the score goes up
//
me-&gt;m_minimal_gap = (uint8_t)(GAME_SCREEN_HEIGHT - 3U
- Q_EVT_CAST(ScoreEvt)-&gt;score/2000U);</action>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,76,3,-1,14">
2012-08-14 18:00:48 -04:00
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<tran trig="GAME_OVER" target="../../4">
<action>uint16_t score = Q_EVT_CAST(ScoreEvt)-&gt;score;
BSP_updateScore(score);
// clear the screen
memset(l_frame, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
BSP_drawBitmap(l_frame);
// Output the final score to the screen
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*10U)/2U, 1U, &quot;Score:&quot;);
char str[5];
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>
2013-10-10 20:01:51 -04:00
<tran_glyph conn="4,79,3,3,26,-9,2">
2012-08-14 18:00:48 -04:00
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
2013-10-10 20:01:51 -04:00
<state_glyph node="4,52,22,29">
2012-08-14 18:00:48 -04:00
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
2013-10-10 20:01:51 -04:00
<state_glyph node="2,4,60,80"/>
2012-08-14 18:00:48 -04:00
</state>
<state name="final">
<entry>// clear the screen
memset(l_frame, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
BSP_drawBitmap(l_frame);
QP::QF::stop(); /* stop QF and cleanup */</entry>
2013-10-10 20:01:51 -04:00
<state_glyph node="2,86,24,6">
2012-08-14 18:00:48 -04:00
<entry box="1,2,6,2"/>
</state_glyph>
</state>
2013-10-10 20:01:51 -04:00
<state_diagram size="66,94"/>
2012-08-14 18:00:48 -04:00
</statechart>
</class>
<class name="Ship" superclass="qpcpp::QActive">
<documentation>Ship Active Object</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_score" type="uint16_t" visibility="0x02" properties="0x00"/>
2013-10-10 20:01:51 -04:00
<operation name="Ship" type="QActive(Q_STATE_CAST(&amp;Ship::initial)), m_x(GAME_SHIP_X), m_y(GAME_SHIP_Y)" visibility="0x00" properties="0x00">
<code>// empty</code>
</operation>
2012-08-14 18:00:48 -04:00
<statechart>
<initial target="../1">
<action>me-&gt;subscribe(TIME_TICK_SIG);
me-&gt;subscribe(PLAYER_TRIGGER_SIG);
// object dictionaries...
QS_OBJ_DICTIONARY(&amp;l_ship);
// function dictionaries for Ship HSM...
QS_FUN_DICTIONARY(&amp;Ship::initial);
QS_FUN_DICTIONARY(&amp;Ship::active);
QS_FUN_DICTIONARY(&amp;Ship::parked);
QS_FUN_DICTIONARY(&amp;Ship::flying);
QS_FUN_DICTIONARY(&amp;Ship::exploding);
// local signals...
QS_SIG_DICTIONARY(PLAYER_SHIP_MOVE_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(TAKE_OFF_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(HIT_WALL_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(HIT_MINE_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &amp;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="m_x = e-&gt;x;\m_y = e-&gt;y">me-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;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>me-&gt;m_score = 0U; /* reset the score */
AO_Tunnel-&gt;POST(Q_NEW(ScoreEvt, SCORE_SIG, me-&gt;m_score), me);</entry>
<tran trig="TIME_TICK">
<action>// tell the Tunnel to draw the Ship and test for hits
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, SHIP_IMG_SIG,
me-&gt;m_x, me-&gt;m_y, SHIP_BMP),
me);
++me-&gt;m_score; // increment the score for surviving another tick
if ((me-&gt;m_score % 10U) == 0U) { // is the score &quot;round&quot;?
AO_Tunnel-&gt;POST(Q_NEW(ScoreEvt, SCORE_SIG, me-&gt;m_score), me);
}</action>
<tran_glyph conn="5,33,3,-1,16">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="PLAYER_TRIGGER">
<action>AO_Missile-&gt;POST(Q_NEW(ObjectPosEvt, MISSILE_FIRE_SIG,
me-&gt;m_x, me-&gt;m_y + SHIP_HEIGHT - 1U),
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-&gt;m_score += Q_EVT_CAST(ScoreEvt)-&gt;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-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard>me-&gt;m_exp_ctr &lt; 15U</guard>
<action>++me-&gt;m_exp_ctr;
// tell the Tunnel to draw the current stage of Explosion
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
me-&gt;m_x, (int8_t)((int)me-&gt;m_y - 4U + SHIP_HEIGHT),
EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2)),
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>AO_Tunnel-&gt;POST(Q_NEW(ScoreEvt, GAME_OVER_SIG, me-&gt;m_score), 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="qpcpp::QActive">
<documentation>Missile Active Object</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
2013-10-10 20:01:51 -04:00
<operation name="Missile" type="QActive(Q_STATE_CAST(&amp;Missile::initial))" visibility="0x00" properties="0x00">
<code>// empty</code>
</operation>
2012-08-14 18:00:48 -04:00
<statechart>
<initial target="../1">
<action>me-&gt;subscribe( TIME_TICK_SIG);
QS_OBJ_DICTIONARY(&amp;l_missile); // object dictionary for Missile object
QS_FUN_DICTIONARY(&amp;Missile::initial); // dictionaries for Missile HSM
QS_FUN_DICTIONARY(&amp;Missile::armed);
QS_FUN_DICTIONARY(&amp;Missile::flying);
QS_FUN_DICTIONARY(&amp;Missile::exploding);
QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, &amp;l_missile); // local signals
QS_SIG_DICTIONARY(HIT_WALL_SIG, &amp;l_missile);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &amp;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-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;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-&gt;m_x + GAME_MISSILE_SPEED_X &lt; GAME_SCREEN_WIDTH</guard>
<action brief="...">me-&gt;m_x += GAME_MISSILE_SPEED_X;
// tell the Tunnel to draw the Missile and test for wall hits
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, MISSILE_IMG_SIG,
me-&gt;m_x, me-&gt;m_y, MISSILE_BMP),
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>AO_Ship-&gt;POST(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-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard>(me-&gt;m_x &gt;= GAME_SPEED_X) &amp;&amp; (me-&gt;m_exp_ctr &lt; 15U)</guard>
<action brief="...">++me-&gt;m_exp_ctr; // advance the explosion counter
me-&gt;m_x -= GAME_SPEED_X; // move the explosion by one step
// tell the Tunnel to render the current stage of Explosion
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
me-&gt;m_x + 3U,
(int8_t)((int)me-&gt;m_y - 4U),
EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2)),
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="qpcpp::QHsm">
<documentation>The Mine1 orthogonal component</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x00" properties="0x00"/>
2013-10-10 20:01:51 -04:00
<operation name="Mine1" type="QHsm(Q_STATE_CAST(&amp;Mine1::initial))" visibility="0x00" properties="0x00">
<code>// empty</code>
</operation>
2012-08-14 18:00:48 -04:00
<statechart>
<initial target="../1">
<action>static bool dict_sent = false;
if (!dict_sent) {
dict_sent = true;
QS_OBJ_DICTIONARY(&amp;l_mine1[0]); // obj. dictionaries for Mine1 pool
QS_OBJ_DICTIONARY(&amp;l_mine1[1]);
QS_OBJ_DICTIONARY(&amp;l_mine1[2]);
QS_OBJ_DICTIONARY(&amp;l_mine1[3]);
QS_OBJ_DICTIONARY(&amp;l_mine1[4]);
QS_FUN_DICTIONARY(&amp;Mine1::initial);// fun. dictionaries for Mine1 HSM
QS_FUN_DICTIONARY(&amp;Mine1::unused);
QS_FUN_DICTIONARY(&amp;Mine1::used);
QS_FUN_DICTIONARY(&amp;Mine1::planted);
QS_FUN_DICTIONARY(&amp;Mine1::exploding);
}
// 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);</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-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;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
AO_Tunnel-&gt;POST(Q_NEW(MineEvt, MINE_DISABLED_SIG, MINE_ID(me)), 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-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard brief="still on screen?">(me-&gt;m_x &gt;= GAME_SPEED_X) &amp;&amp; (me-&gt;m_exp_ctr &lt; 15)</guard>
<action>++me-&gt;m_exp_ctr; // advance the explosion counter
me-&gt;m_x -= GAME_SPEED_X; // move explosion by 1 step
// tell the Game to render the current stage of Explosion
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
me-&gt;m_x + 1U, (int8_t)((int)me-&gt;m_y - 4 + 2),
EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2)),
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-&gt;m_x &gt;= GAME_SPEED_X</guard>
<action>me-&gt;m_x -= GAME_SPEED_X; // move the mine 1 step
// tell the Tunnel to draw the Mine
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, MINE_IMG_SIG,
me-&gt;m_x, me-&gt;m_y, MINE1_BMP),
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)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../../1">
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static MineEvt const mine1_hit(HIT_MINE_SIG, 1U);
AO_Ship-&gt;POST(&amp;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)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../1">
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static ScoreEvt const mine1_destroyed(DESTROYED_MINE_SIG, 25U);
AO_Missile-&gt;POST(&amp;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="qpcpp::QHsm">
<documentation>The Mine2 orthogonal component</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x00" properties="0x00"/>
2013-10-10 20:01:51 -04:00
<operation name="Mine2" type="QHsm(Q_STATE_CAST(&amp;Mine2::initial))" visibility="0x00" properties="0x00">
<code>// empty</code>
</operation>
2012-08-14 18:00:48 -04:00
<statechart>
<initial target="../1">
<action>static bool dict_sent = false;
if (!dict_sent) {
dict_sent = true;
QS_OBJ_DICTIONARY(&amp;l_mine2[0]); // obj. dictionaries for Mine2 pool
QS_OBJ_DICTIONARY(&amp;l_mine2[1]);
QS_OBJ_DICTIONARY(&amp;l_mine2[2]);
QS_OBJ_DICTIONARY(&amp;l_mine2[3]);
QS_OBJ_DICTIONARY(&amp;l_mine2[4]);
QS_FUN_DICTIONARY(&amp;Mine2::initial);// fun. dictionaries for Mine2 HSM
QS_FUN_DICTIONARY(&amp;Mine2::unused);
QS_FUN_DICTIONARY(&amp;Mine2::used);
QS_FUN_DICTIONARY(&amp;Mine2::planted);
QS_FUN_DICTIONARY(&amp;Mine2::exploding);
}
// 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);</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-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;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
AO_Tunnel-&gt;POST(Q_NEW(MineEvt, MINE_DISABLED_SIG, MINE_ID(me)), 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-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard brief="still on screen?">(me-&gt;m_x &gt;= GAME_SPEED_X) &amp;&amp; (me-&gt;m_exp_ctr &lt; 15)</guard>
<action>++me-&gt;m_exp_ctr; // advance the explosion counter
me-&gt;m_x -= GAME_SPEED_X; // move explosion by 1 step
// tell the Game to render the current stage of Explosion
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
me-&gt;m_x + 1U, (int8_t)((int)me-&gt;m_y - 4 + 2),
EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2)),
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-&gt;m_x &gt;= GAME_SPEED_X</guard>
<action>me-&gt;m_x -= GAME_SPEED_X; // move the mine 1 step
// tell the Tunnel to draw the Mine
AO_Tunnel-&gt;POST(Q_NEW(ObjectImageEvt, MINE_IMG_SIG,
me-&gt;m_x, me-&gt;m_y, MINE2_BMP),
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)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../../1">
<guard brief="collision with MINE2_BMP?">do_bitmaps_overlap(MINE2_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static MineEvt const mine2_hit(HIT_MINE_SIG, 2U);
AO_Ship-&gt;POST(&amp;mine2_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)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../1">
<guard brief="collision with MINE2_MISSILE_BMP?">do_bitmaps_overlap(MINE2_MISSILE_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static ScoreEvt const mine2_destroyed(DESTROYED_MINE_SIG, 45U);
AO_Missile-&gt;POST(&amp;mine2_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>
<attribute name="AO_Tunnel" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<attribute name="AO_Ship" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<attribute name="AO_Missile" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<operation name="do_bitmaps_overlap" type="bool" 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>
</package>
<directory name=".">
<file name="game.h">
<text>#ifndef game_h
#define game_h
namespace GAME {
enum GameSignals { // signals used in the game
TIME_TICK_SIG = QP::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 5U
#define GAME_MINES_DIST_MIN 10U
#define GAME_SPEED_X 1U
#define GAME_MISSILE_SPEED_X 2U
#define GAME_SHIP_X 10U
#define GAME_SHIP_Y (GAME_SCREEN_HEIGHT / 2U)
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
};
// 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)
// obtain instances of the Mines orthogonal components
QP::QHsm *Mine1_getInst(uint8_t id);
QP::QHsm *Mine2_getInst(uint8_t id);
} // namespace GAME
#endif // game_h</text>
</file>
<file name="missile.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
namespace GAME {
//Q_DEFINE_THIS_FILE
// local objects -------------------------------------------------------------
$declare(AOs::Missile)
static Missile l_missile; // the sole instance of the Missile active object
// Public-scope objects ------------------------------------------------------
QP::QActive * const AO_Missile = &amp;l_missile; // opaque pointer
// Active object definition --------------------------------------------------
$define(AOs::Missile)
} // namespace GAME</text>
</file>
<file name="ship.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
namespace GAME {
//Q_DEFINE_THIS_FILE
#define SHIP_WIDTH 5U
#define SHIP_HEIGHT 3U
// 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 ------------------------------------------------------
QP::QActive * const AO_Ship = &amp;l_ship; // opaque pointer
// Active object definition --------------------------------------------------
$define(AOs::Ship)
} // namespace GAME</text>
</file>
<file name="tunnel.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
#include &lt;string.h&gt; // for memmove() and memcpy()
namespace GAME {
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/8U];
static uint8_t l_frame[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U];
// local helper functions ----------------------------------------------------
static void randomSeed(uint32_t seed);
static uint32_t random(void);
// Public-scope objects ------------------------------------------------------
QP::QActive * const AO_Tunnel = &amp;l_tunnel; // opaque pointer
// helper functions ----------------------------------------------------------
//
// The bitmap for the &quot;Press Button&quot; 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 &quot;tentacles&quot;. 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
};
struct Bitmap { // the auxiliary structure to hold const bitmaps
uint8_t const *bits; // the bits in the bitmap
uint8_t width; // the width of the 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)
//............................................................................
uint32_t random(void) { // a very cheap pseudo-random-number generator
// &quot;Super-Duper&quot; 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 &gt;&gt; 8;
}
//............................................................................
void randomSeed(uint32_t seed) {
l_rnd = seed;
}
//............................................................................
bool 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 &lt; Q_DIM(l_bitmap)) &amp;&amp; (bmp_id2 &lt; Q_DIM(l_bitmap)));
bmp1 = &amp;l_bitmap[bmp_id1];
bmp2 = &amp;l_bitmap[bmp_id2];
// is the incoming object starting to overlap the Mine bitmap?
if ((x1 &lt;= x2) &amp;&amp; (x1 + bmp2-&gt;width &gt; x2)) {
x0 = x2 - x1;
w = x1 + bmp2-&gt;width - x2;
if (w &gt; bmp1-&gt;width) {
w = bmp1-&gt;width;
}
for (x = 0; x &lt; w; ++x) { // scan over the overlapping columns
bits1 = ((uint32_t)bmp2-&gt;bits[x + x0] &lt;&lt; y2);
bits2 = ((uint32_t)bmp1-&gt;bits[x] &lt;&lt; y1);
if ((bits1 &amp; bits2) != 0) { // do the bits overlap?
return true; // yes!
}
}
}
else {
if ((x1 &gt; x2) &amp;&amp; (x2 + bmp1-&gt;width &gt; x1)) {
x0 = x1 - x2;
w = x2 + bmp1-&gt;width - x1;
if (w &gt; bmp2-&gt;width) {
w = bmp2-&gt;width;
}
for (x = 0; x &lt; w; ++x) { // scan over the overlapping columns
bits1 = ((uint32_t)bmp1-&gt;bits[x + x0] &lt;&lt; y1);
bits2 = ((uint32_t)bmp2-&gt;bits[x] &lt;&lt; y2);
if ((bits1 &amp; bits2) != 0U) { // do the bits overlap?
return true; // yes!
}
}
}
}
return false; // the bitmaps do not overlap
}
} // namespace GAME</text>
</file>
<file name="mine1.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
namespace GAME {
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
//............................................................................
QP::QHsm *Mine1_getInst(uint8_t id) {
Q_REQUIRE(id &lt; GAME_MINES_MAX);
return &amp;l_mine1[id];
}
// helper function to provide the ID of this mine ............................
static inline uint8_t MINE_ID(Mine1 const * const me) {
return static_cast&lt;uint8_t&gt;(me - l_mine1);
}
// Mine1 class definition ----------------------------------------------------
$define(AOs::Mine1)
} // namespace GAME</text>
</file>
<file name="mine2.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
namespace GAME {
Q_DEFINE_THIS_FILE
// encapsulated delcaration of the Mine1 HSM ---------------------------------
$declare(AOs::Mine2)
// local objects -------------------------------------------------------------
static Mine2 l_mine2[GAME_MINES_MAX]; // a pool of type-2 mines
//............................................................................
QP::QHsm *Mine2_getInst(uint8_t id) {
Q_REQUIRE(id &lt; GAME_MINES_MAX);
return &amp;l_mine2[id];
}
// helper function to provide the ID of this mine ............................
static inline uint8_t MINE_ID(Mine2 const * const me) {
return static_cast&lt;uint8_t&gt;(me - l_mine2);
}
// Mine1 class definition ----------------------------------------------------
$define(AOs::Mine2)
} // namespace GAME</text>
</file>
</directory>
</model>