Add missile command sample game
This commit is contained in:
parent
e1f605b28c
commit
995e39a57d
|
@ -34,9 +34,10 @@ char MixedColors[4][4][8] = {
|
||||||
|
|
||||||
void bmmc_put(const Bitmap * bm, int x, int y, char c)
|
void bmmc_put(const Bitmap * bm, int x, int y, char c)
|
||||||
{
|
{
|
||||||
char * dp = bm->data + bm->cwidth * (y & ~7) + ((x & ~7) | (y & 7));
|
char * dp = bm->data + bm->cwidth * (y & ~7) + ((x & ~7) | (y & 7));
|
||||||
|
char pat = cbytes[c & 3];
|
||||||
|
|
||||||
*dp = (*dp & andmask[x & 7]) | (cbytes[c & 3] & ormask[x & 7]);
|
*dp = ((*dp ^ pat) & andmask[x & 7]) ^ pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
char bmmc_get(const Bitmap * bm, int x, int y)
|
char bmmc_get(const Bitmap * bm, int x, int y)
|
||||||
|
|
|
@ -11987,7 +11987,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(void)
|
||||||
i += 3;
|
i += 3;
|
||||||
}
|
}
|
||||||
else if (i + 5 < mIns.Size() &&
|
else if (i + 5 < mIns.Size() &&
|
||||||
mIns[i + 0].mType == ASMIT_LDA &&
|
mIns[i + 0].ChangesAccuAndFlag() &&
|
||||||
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
|
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
|
||||||
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
|
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
|
||||||
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
|
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
|
||||||
|
@ -13032,7 +13032,8 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mIns.Insert(i + 0, NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
|
mIns.Insert(i + 0, NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
|
||||||
mIns[i + 0].mLive = mIns[i - 1].mLive | LIVE_CPU_REG_Y | LIVE_MEM;
|
if (i > 0)
|
||||||
|
mIns[i + 0].mLive = mIns[i - 1].mLive | LIVE_CPU_REG_Y | LIVE_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
progress = true;
|
progress = true;
|
||||||
|
@ -13994,6 +13995,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
else if (
|
||||||
|
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
||||||
|
mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
|
||||||
|
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
|
||||||
|
{
|
||||||
|
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
|
||||||
|
mIns[i + 2].mType = ASMIT_ROL; mIns[i + 2].mAddress = mIns[i + 1].mAddress; mIns[i + 2].mLive |= LIVE_MEM;
|
||||||
|
mIns[i + 1].mType = ASMIT_ASL; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
|
||||||
|
progress = true;
|
||||||
|
}
|
||||||
#if 1
|
#if 1
|
||||||
else if (
|
else if (
|
||||||
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
||||||
|
@ -14230,6 +14241,36 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
|
||||||
progress = true;
|
progress = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if 1
|
||||||
|
else if (
|
||||||
|
mIns[i + 0].mType == ASMIT_LDA &&
|
||||||
|
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1]) &&
|
||||||
|
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
|
||||||
|
mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
|
||||||
|
{
|
||||||
|
mIns[i + 2].mType = ASMIT_ORA;
|
||||||
|
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
|
||||||
|
|
||||||
|
progress = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 1
|
||||||
|
else if (
|
||||||
|
mIns[i + 0].mType == ASMIT_LDA &&
|
||||||
|
mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
|
||||||
|
mIns[i + 2].mType == ASMIT_SEC &&
|
||||||
|
mIns[i + 3].mType == ASMIT_ADC)
|
||||||
|
{
|
||||||
|
mIns.Insert(i + 4, mIns[i + 0]);
|
||||||
|
|
||||||
|
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
|
||||||
|
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
|
||||||
|
mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_C;
|
||||||
|
mIns[i + 4].mType = ASMIT_SBC;
|
||||||
|
|
||||||
|
progress = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
else if (
|
else if (
|
||||||
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
||||||
|
|
|
@ -73,7 +73,7 @@ int main(int argc, const char** argv)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
strcpy(strProductName, "oscar64");
|
strcpy(strProductName, "oscar64");
|
||||||
strcpy(strProductVersion, "1.3.74");
|
strcpy(strProductVersion, "1.4.75");
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
uint32_t length = sizeof(basePath);
|
uint32_t length = sizeof(basePath);
|
||||||
|
|
|
@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,3,74,0
|
FILEVERSION 1,4,75,0
|
||||||
PRODUCTVERSION 1,3,74,0
|
PRODUCTVERSION 1,4,75,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -43,12 +43,12 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "oscar64"
|
VALUE "CompanyName", "oscar64"
|
||||||
VALUE "FileDescription", "oscar64 compiler"
|
VALUE "FileDescription", "oscar64 compiler"
|
||||||
VALUE "FileVersion", "1.3.74.0"
|
VALUE "FileVersion", "1.4.75.0"
|
||||||
VALUE "InternalName", "oscar64.exe"
|
VALUE "InternalName", "oscar64.exe"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2021"
|
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||||
VALUE "OriginalFilename", "oscar64.exe"
|
VALUE "OriginalFilename", "oscar64.exe"
|
||||||
VALUE "ProductName", "oscar64"
|
VALUE "ProductName", "oscar64"
|
||||||
VALUE "ProductVersion", "1.3.74.0"
|
VALUE "ProductVersion", "1.4.75.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -94,6 +94,12 @@
|
||||||
}
|
}
|
||||||
"Entry"
|
"Entry"
|
||||||
{
|
{
|
||||||
|
"MsmKey" = "8:_1ED10FB93DDA4801BF72003E21B2CE55"
|
||||||
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
"MsmKey" = "8:_1F88FA4F35F043B3ABFCB552FCEA5CDD"
|
"MsmKey" = "8:_1F88FA4F35F043B3ABFCB552FCEA5CDD"
|
||||||
"OwnerKey" = "8:_UNDEFINED"
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
"MsmSig" = "8:_UNDEFINED"
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
@ -1087,6 +1093,26 @@
|
||||||
"IsDependency" = "11:FALSE"
|
"IsDependency" = "11:FALSE"
|
||||||
"IsolateTo" = "8:"
|
"IsolateTo" = "8:"
|
||||||
}
|
}
|
||||||
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1ED10FB93DDA4801BF72003E21B2CE55"
|
||||||
|
{
|
||||||
|
"SourcePath" = "8:..\\samples\\games\\missile.c"
|
||||||
|
"TargetName" = "8:missile.c"
|
||||||
|
"Tag" = "8:"
|
||||||
|
"Folder" = "8:_BC04C0DDE264410096618981E4E890DA"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Vital" = "11:TRUE"
|
||||||
|
"ReadOnly" = "11:FALSE"
|
||||||
|
"Hidden" = "11:FALSE"
|
||||||
|
"System" = "11:FALSE"
|
||||||
|
"Permanent" = "11:FALSE"
|
||||||
|
"SharedLegacy" = "11:FALSE"
|
||||||
|
"PackageAs" = "3:1"
|
||||||
|
"Register" = "3:1"
|
||||||
|
"Exclude" = "11:FALSE"
|
||||||
|
"IsDependency" = "11:FALSE"
|
||||||
|
"IsolateTo" = "8:"
|
||||||
|
}
|
||||||
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1F88FA4F35F043B3ABFCB552FCEA5CDD"
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1F88FA4F35F043B3ABFCB552FCEA5CDD"
|
||||||
{
|
{
|
||||||
"SourcePath" = "8:..\\include\\c64\\rasterirq.c"
|
"SourcePath" = "8:..\\include\\c64\\rasterirq.c"
|
||||||
|
@ -3492,15 +3518,15 @@
|
||||||
{
|
{
|
||||||
"Name" = "8:Microsoft Visual Studio"
|
"Name" = "8:Microsoft Visual Studio"
|
||||||
"ProductName" = "8:oscar64"
|
"ProductName" = "8:oscar64"
|
||||||
"ProductCode" = "8:{109FC925-4A6D-4868-A60D-42BF3DFE541B}"
|
"ProductCode" = "8:{1FF1624F-A9FD-402D-806B-6CE9925FB690}"
|
||||||
"PackageCode" = "8:{C6215A39-7DD0-4667-93FB-46373135B9C8}"
|
"PackageCode" = "8:{47F7AA54-A5D7-4A82-8276-0DCD0FE332D4}"
|
||||||
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
|
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
|
||||||
"AspNetVersion" = "8:2.0.50727.0"
|
"AspNetVersion" = "8:2.0.50727.0"
|
||||||
"RestartWWWService" = "11:FALSE"
|
"RestartWWWService" = "11:FALSE"
|
||||||
"RemovePreviousVersions" = "11:TRUE"
|
"RemovePreviousVersions" = "11:TRUE"
|
||||||
"DetectNewerInstalledVersion" = "11:TRUE"
|
"DetectNewerInstalledVersion" = "11:TRUE"
|
||||||
"InstallAllUsers" = "11:FALSE"
|
"InstallAllUsers" = "11:FALSE"
|
||||||
"ProductVersion" = "8:1.3.74"
|
"ProductVersion" = "8:1.4.75"
|
||||||
"Manufacturer" = "8:oscar64"
|
"Manufacturer" = "8:oscar64"
|
||||||
"ARPHELPTELEPHONE" = "8:"
|
"ARPHELPTELEPHONE" = "8:"
|
||||||
"ARPHELPLINK" = "8:"
|
"ARPHELPLINK" = "8:"
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
../../bin/oscar64 snake.c
|
../../bin/oscar64 snake.c
|
||||||
../../bin/oscar64 lander.c -n
|
../../bin/oscar64 lander.c -n
|
||||||
../../bin/oscar64 maze3d.c -n
|
../../bin/oscar64 maze3d.c -n
|
||||||
|
../../bin/oscar64 missile.c -O3 -n
|
||||||
|
|
||||||
|
|
|
@ -223,15 +223,15 @@ void game_loop(void)
|
||||||
case GS_PLAYING:
|
case GS_PLAYING:
|
||||||
{
|
{
|
||||||
// Check player input on every frame
|
// Check player input on every frame
|
||||||
joy_poll(1);
|
joy_poll(0);
|
||||||
lander_move(&TheGame.lander, joyx[1], joyy[1]);
|
lander_move(&TheGame.lander, joyx[0], joyy[0]);
|
||||||
LanderCollision col = lander_check(&TheGame.lander);
|
LanderCollision col = lander_check(&TheGame.lander);
|
||||||
if (col == LCOL_GROUND)
|
if (col == LCOL_GROUND)
|
||||||
game_state(GS_COLLIDE);
|
game_state(GS_COLLIDE);
|
||||||
else if (col == LCOL_PAD)
|
else if (col == LCOL_PAD)
|
||||||
game_state(GS_LANDED);
|
game_state(GS_LANDED);
|
||||||
else
|
else
|
||||||
lander_show(&TheGame.lander, joyx[1], joyy[1]);
|
lander_show(&TheGame.lander, joyx[0], joyy[0]);
|
||||||
} break;
|
} break;
|
||||||
case GS_LANDED:
|
case GS_LANDED:
|
||||||
if (!--TheGame.count)
|
if (!--TheGame.count)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
call ..\..\bin\oscar64 snake.c
|
call ..\..\bin\oscar64 snake.c
|
||||||
call ..\..\bin\oscar64 -n lander.c
|
call ..\..\bin\oscar64 -n lander.c
|
||||||
call ..\..\bin\oscar64 -n maze3d.c
|
call ..\..\bin\oscar64 -n maze3d.c
|
||||||
call ..\..\bin\oscar64 -n missile.c
|
call ..\..\bin\oscar64 -n -O3 missile.c
|
||||||
|
|
|
@ -419,19 +419,19 @@ int main(void)
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// Read joystick input
|
// Read joystick input
|
||||||
joy_poll(1);
|
joy_poll(0);
|
||||||
|
|
||||||
// Forward or backward motion
|
// Forward or backward motion
|
||||||
if (joyy[1])
|
if (joyy[0])
|
||||||
{
|
{
|
||||||
// Target square
|
// Target square
|
||||||
sbyte tx = px - dx * joyy[1];
|
sbyte tx = px - dx * joyy[0];
|
||||||
sbyte ty = py - dy * joyy[1];
|
sbyte ty = py - dy * joyy[0];
|
||||||
|
|
||||||
// Check i empty
|
// Check i empty
|
||||||
if (maze[ty][tx] != '#')
|
if (maze[ty][tx] != '#')
|
||||||
{
|
{
|
||||||
if (joyy[1] < 0)
|
if (joyy[0] < 0)
|
||||||
{
|
{
|
||||||
// Forward animation
|
// Forward animation
|
||||||
px = tx;
|
px = tx;
|
||||||
|
@ -457,7 +457,7 @@ int main(void)
|
||||||
// Check if new rotation
|
// Check if new rotation
|
||||||
if (!rotate)
|
if (!rotate)
|
||||||
{
|
{
|
||||||
if (joyx[1] == 1)
|
if (joyx[0] == 1)
|
||||||
{
|
{
|
||||||
// Rotate right
|
// Rotate right
|
||||||
sbyte t = dx; dx = -dy; dy = t;
|
sbyte t = dx; dx = -dy; dy = t;
|
||||||
|
@ -465,7 +465,7 @@ int main(void)
|
||||||
maze_draw(zxdist0);
|
maze_draw(zxdist0);
|
||||||
screen_left();
|
screen_left();
|
||||||
}
|
}
|
||||||
else if (joyx[1] == -1)
|
else if (joyx[0] == -1)
|
||||||
{
|
{
|
||||||
// Rotate left
|
// Rotate left
|
||||||
sbyte t = dx; dx = dy; dy = -t;
|
sbyte t = dx; dx = dy; dy = -t;
|
||||||
|
@ -474,7 +474,7 @@ int main(void)
|
||||||
screen_right();
|
screen_right();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!joyx[1])
|
else if (!joyx[0])
|
||||||
{
|
{
|
||||||
// No rotation, may rotate again in next frame
|
// No rotation, may rotate again in next frame
|
||||||
rotate = false;
|
rotate = false;
|
||||||
|
|
|
@ -3,114 +3,295 @@
|
||||||
#include <c64/sprites.h>
|
#include <c64/sprites.h>
|
||||||
#include <c64/joystick.h>
|
#include <c64/joystick.h>
|
||||||
#include <c64/rasterirq.h>
|
#include <c64/rasterirq.h>
|
||||||
|
#include <c64/cia.h>
|
||||||
#include <gfx/mcbitmap.h>
|
#include <gfx/mcbitmap.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Make some room
|
||||||
#pragma region(main, 0x0a00, 0xc800, , , {code, data, bss, heap, stack} )
|
#pragma region(main, 0x0a00, 0xc800, , , {code, data, bss, heap, stack} )
|
||||||
|
|
||||||
|
// Sprite assets
|
||||||
const char MissileSprites[] = {
|
const char MissileSprites[] = {
|
||||||
#embed "../resources/missilesprites.bin"
|
#embed "../resources/missilesprites.bin"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Charset assets
|
||||||
const char MissileChars[] = {
|
const char MissileChars[] = {
|
||||||
#embed "../resources/missilechars.bin"
|
#embed "../resources/missilechars.bin"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Graphics areas in bank 3
|
||||||
#define Color1 ((char *)0xc800)
|
#define Color1 ((char *)0xc800)
|
||||||
#define Color2 ((char *)0xd800)
|
#define Color2 ((char *)0xd800)
|
||||||
#define Hires ((char *)0xe000)
|
#define Hires ((char *)0xe000)
|
||||||
#define Sprites ((char *)0xd000)
|
#define Sprites ((char *)0xd000)
|
||||||
#define Charset ((char *)0xd800)
|
#define Charset ((char *)0xd800)
|
||||||
|
|
||||||
|
// Joystick and crosshair control
|
||||||
int CrossX = 160, CrossY = 100;
|
int CrossX = 160, CrossY = 100;
|
||||||
bool CrossP = false;
|
bool CrossP = false;
|
||||||
char CrossDelay = 0;
|
char CrossDelay = 0;
|
||||||
|
|
||||||
|
// Display bitmap
|
||||||
Bitmap sbm;
|
Bitmap sbm;
|
||||||
const ClipRect scr = { 0, 0, 320, 200 };
|
const ClipRect scr = { 0, 0, 320, 200 };
|
||||||
|
|
||||||
|
// Structure for a explosion
|
||||||
struct Explosion
|
struct Explosion
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y; // Center of circle
|
||||||
char r;
|
char r; // Radius of circle
|
||||||
Explosion * next;
|
Explosion * next; // Next explosion in list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Structure for a missile (defensive and ICBM)
|
||||||
struct Missile
|
struct Missile
|
||||||
{
|
{
|
||||||
int sx, sy, tx, ty, x, y, dx, dy;
|
int sx, sy; // start position
|
||||||
int d;
|
int tx, ty; // target position
|
||||||
char cnt;
|
int x, y; // current position
|
||||||
Missile * next;
|
int dx, dy; // distance in x and y
|
||||||
|
int d; // error term for Bresenham
|
||||||
|
sbyte stepx; // direction in x (+1 or -1)
|
||||||
|
sbyte cnt; // speed counter
|
||||||
|
Missile * next; // next missile in list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Storage space for explosion
|
||||||
Explosion explosions[16];
|
Explosion explosions[16];
|
||||||
|
// First free and first used explosion
|
||||||
Explosion * efree, * eused;
|
Explosion * efree, * eused;
|
||||||
|
|
||||||
|
// Storage space for defending missiles
|
||||||
Missile missiles[8];
|
Missile missiles[8];
|
||||||
|
// First free and first used missile
|
||||||
Missile * mfree, * mused;
|
Missile * mfree, * mused;
|
||||||
|
// Number of missiles available
|
||||||
|
char nmissiles;
|
||||||
|
|
||||||
|
// Storage space for ICMBs
|
||||||
Missile icbms[16];
|
Missile icbms[16];
|
||||||
|
// First free and first used ICBM
|
||||||
Missile * ifree, * iused;
|
Missile * ifree, * iused;
|
||||||
|
// Speed and number of ICBMs still incomming
|
||||||
|
char icbmspeed, icbmcount;
|
||||||
|
|
||||||
bool cities[6];
|
// Cities not yet destroyed
|
||||||
|
bool cities[6];
|
||||||
|
char ncities;
|
||||||
|
|
||||||
|
// Init status bar at top
|
||||||
|
void status_init(void)
|
||||||
|
{
|
||||||
|
memset(Color1, ' ', 40);
|
||||||
|
memset(Color2, 1, 40);
|
||||||
|
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
Color1[i + 2] = '0';
|
||||||
|
Color1[i + 12] = '0';
|
||||||
|
Color2[i + 12] = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand an 8x8 charactor to 16x16 on screen
|
||||||
|
void char_put(char cx, char cy, char c, char color)
|
||||||
|
{
|
||||||
|
// Get pointer to glyph data
|
||||||
|
const char * sp = MissileChars + 8 * c;
|
||||||
|
|
||||||
|
// Loop over all pixel
|
||||||
|
for(char y=0; y<8; y++)
|
||||||
|
{
|
||||||
|
char cl = sp[y];
|
||||||
|
for(char x=0; x<8; x++)
|
||||||
|
{
|
||||||
|
// Draw two pixel if bit is set
|
||||||
|
if (cl & 128)
|
||||||
|
{
|
||||||
|
bmmc_put(&sbm, cx + 2 * x, cy + 2 * y + 0, color);
|
||||||
|
bmmc_put(&sbm, cx + 2 * x, cy + 2 * y + 1, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next bit
|
||||||
|
cl <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a zero terminated string on screen
|
||||||
|
void char_write(char cx, char cy, const char * s, char color)
|
||||||
|
{
|
||||||
|
// Loop over all characters
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
char_put(cx, cy, *s, color);
|
||||||
|
s++;
|
||||||
|
cx += 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment the score from a given digit on
|
||||||
|
void score_inc(char digit, unsigned val)
|
||||||
|
{
|
||||||
|
// Lowest digit to increment
|
||||||
|
char at = 9 - digit;
|
||||||
|
|
||||||
|
// Loop while there is still score to account for
|
||||||
|
while (val)
|
||||||
|
{
|
||||||
|
// Increment one character
|
||||||
|
char ch = Color1[at] + val % 10;
|
||||||
|
|
||||||
|
// Remove low digit from number
|
||||||
|
val /= 10;
|
||||||
|
|
||||||
|
// Check overflow
|
||||||
|
if (ch > '9')
|
||||||
|
{
|
||||||
|
ch -= 10;
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color1[at] = ch;
|
||||||
|
|
||||||
|
// Next higher character
|
||||||
|
at --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset score and update high score
|
||||||
|
void score_reset(void)
|
||||||
|
{
|
||||||
|
// Find first digit, where score and highscore differ
|
||||||
|
char i = 0;
|
||||||
|
while (i < 8 && Color1[i + 2] == Color1[i + 12])
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// Check if new score is higher
|
||||||
|
if (i < 8 && Color1[i + 2] > Color1[i + 12])
|
||||||
|
{
|
||||||
|
// If so, copy to highscore
|
||||||
|
while (i < 8)
|
||||||
|
{
|
||||||
|
Color1[i + 12] = Color1[i + 2];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear score
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
Color1[i + 2] = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update number of missiles
|
||||||
|
void status_missiles(char num)
|
||||||
|
{
|
||||||
|
char n = 0;
|
||||||
|
|
||||||
|
// Draw full pairs
|
||||||
|
while (2 * n + 1 < num)
|
||||||
|
{
|
||||||
|
Color1[25 + n] = 92;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
// Draw remaining single one
|
||||||
|
if (num & 1)
|
||||||
|
{
|
||||||
|
Color1[25 + n] = 93;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
// Empty remainder
|
||||||
|
while (n < 15)
|
||||||
|
{
|
||||||
|
Color1[25 + n] = 94;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize explosion list
|
||||||
void explosion_init(void)
|
void explosion_init(void)
|
||||||
{
|
{
|
||||||
|
// No explosion active
|
||||||
eused = nullptr;
|
eused = nullptr;
|
||||||
|
|
||||||
|
// First free explosion element
|
||||||
efree = explosions;
|
efree = explosions;
|
||||||
|
// Build list
|
||||||
for(char i=0; i<15; i++)
|
for(char i=0; i<15; i++)
|
||||||
explosions[i].next = explosions + i + 1;
|
explosions[i].next = explosions + i + 1;
|
||||||
|
// Terminate last element
|
||||||
explosions[15].next = nullptr;
|
explosions[15].next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start a new explosion
|
||||||
void explosion_start(int x, int y)
|
void explosion_start(int x, int y)
|
||||||
{
|
{
|
||||||
|
// Free slot in list of explosions?
|
||||||
if (efree)
|
if (efree)
|
||||||
{
|
{
|
||||||
|
// Move entry from free to used list
|
||||||
Explosion * e = efree;
|
Explosion * e = efree;
|
||||||
efree = e->next;
|
efree = e->next;
|
||||||
e->next = eused;
|
e->next = eused;
|
||||||
eused = e;
|
eused = e;
|
||||||
|
|
||||||
|
// Initialize position and size
|
||||||
e->r = 0;
|
e->r = 0;
|
||||||
e->x = x;
|
e->x = x;
|
||||||
e->y = y;
|
e->y = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Animate all explosions
|
||||||
void explosion_animate(void)
|
void explosion_animate(void)
|
||||||
{
|
{
|
||||||
|
// Loop over active explosions with "e", use "ep" to point
|
||||||
|
// to previous explosion, so we can remove the current explosion
|
||||||
|
// from the list
|
||||||
Explosion * e = eused, * ep = nullptr;
|
Explosion * e = eused, * ep = nullptr;
|
||||||
while (e)
|
while (e)
|
||||||
{
|
{
|
||||||
|
// Remember next entry in list
|
||||||
Explosion * en = e->next;
|
Explosion * en = e->next;
|
||||||
|
|
||||||
|
// Increment phase (radius)
|
||||||
e->r++;
|
e->r++;
|
||||||
|
|
||||||
|
// Advance every fourth frame
|
||||||
if (!(e->r & 3))
|
if (!(e->r & 3))
|
||||||
{
|
{
|
||||||
|
// Draw or erase outer perimeter depending on growing or
|
||||||
|
// shrinking explosion phase
|
||||||
if (e->r <= 64)
|
if (e->r <= 64)
|
||||||
bmmc_circle(&sbm, &scr, e->x, e->y, e->r >> 2, 1);
|
bmmc_circle(&sbm, &scr, e->x, e->y, e->r >> 2, 1);
|
||||||
else
|
else
|
||||||
bmmc_circle(&sbm, &scr, e->x, e->y, 33 - (e->r >> 2), 0);
|
bmmc_circle(&sbm, &scr, e->x, e->y, 33 - (e->r >> 2), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End of explosion live
|
||||||
if (e->r == 128)
|
if (e->r == 128)
|
||||||
{
|
{
|
||||||
|
// Remove explosion from used list
|
||||||
if (ep)
|
if (ep)
|
||||||
ep->next = e->next;
|
ep->next = e->next;
|
||||||
else
|
else
|
||||||
eused = e->next;
|
eused = e->next;
|
||||||
|
|
||||||
|
// Prepend it to free list
|
||||||
e->next = efree;
|
e->next = efree;
|
||||||
efree = e;
|
efree = e;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ep = e;
|
ep = e;
|
||||||
|
|
||||||
|
// Next explosion in list
|
||||||
e = en;
|
e = en;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize defending missile list
|
||||||
void missile_init(void)
|
void missile_init(void)
|
||||||
{
|
{
|
||||||
mused = nullptr;
|
mused = nullptr;
|
||||||
|
@ -120,31 +301,47 @@ void missile_init(void)
|
||||||
missiles[7].next = nullptr;
|
missiles[7].next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a new defending missile
|
||||||
void missile_start(int sx, int sy, int tx, int ty)
|
void missile_start(int sx, int sy, int tx, int ty)
|
||||||
{
|
{
|
||||||
if (mfree)
|
// Check if entry in free list and missile in silo remaining
|
||||||
|
if (mfree && nmissiles > 0)
|
||||||
{
|
{
|
||||||
|
// Detach from free list
|
||||||
Missile * m = mfree;
|
Missile * m = mfree;
|
||||||
mfree = m->next;
|
mfree = m->next;
|
||||||
|
|
||||||
|
// Attach to active list
|
||||||
m->next = mused;
|
m->next = mused;
|
||||||
mused = m;
|
mused = m;
|
||||||
|
|
||||||
|
// Initialize start and target coordinates
|
||||||
m->sx = sx >> 1; m->x = sx >> 1;
|
m->sx = sx >> 1; m->x = sx >> 1;
|
||||||
m->sy = sy; m->y = sy;
|
m->sy = sy; m->y = sy;
|
||||||
m->tx = tx >> 1;
|
m->tx = tx >> 1;
|
||||||
m->ty = ty;
|
m->ty = ty;
|
||||||
|
|
||||||
|
// Initialize line drawing parameters
|
||||||
m->dy = m->sy - m->ty;
|
m->dy = m->sy - m->ty;
|
||||||
m->dx = m->tx - m->sx;
|
m->dx = m->tx - m->sx;
|
||||||
|
m->stepx = 1;
|
||||||
if (m->dx < 0)
|
if (m->dx < 0)
|
||||||
|
{
|
||||||
m->dx = -m->dx;
|
m->dx = -m->dx;
|
||||||
|
m->stepx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
m->d = m->dy - m->dx;
|
m->d = m->dy - m->dx;
|
||||||
m->dx *= 2;
|
m->dx *= 2;
|
||||||
m->dy *= 2;
|
m->dy *= 2;
|
||||||
|
|
||||||
|
// Remove missile from silo
|
||||||
|
nmissiles--;
|
||||||
|
status_missiles(nmissiles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Animate all active missiles
|
||||||
void missile_animate(void)
|
void missile_animate(void)
|
||||||
{
|
{
|
||||||
Missile * m = mused, * mp = nullptr;
|
Missile * m = mused, * mp = nullptr;
|
||||||
|
@ -152,6 +349,7 @@ void missile_animate(void)
|
||||||
{
|
{
|
||||||
Missile * mn = m->next;
|
Missile * mn = m->next;
|
||||||
|
|
||||||
|
// Advance missile position using one step of Bresenham
|
||||||
if (m->d >= 0)
|
if (m->d >= 0)
|
||||||
{
|
{
|
||||||
m->y--;
|
m->y--;
|
||||||
|
@ -159,18 +357,18 @@ void missile_animate(void)
|
||||||
}
|
}
|
||||||
if (m->d < 0)
|
if (m->d < 0)
|
||||||
{
|
{
|
||||||
if (m->tx < m->sx)
|
m->x += m->stepx;
|
||||||
m->x--;
|
|
||||||
else
|
|
||||||
m->x++;
|
|
||||||
m->d += m->dy;
|
m->d += m->dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bmmc_get(&sbm, m->x, m->y) == 1 || m->y == m->ty)
|
// Check if target reached
|
||||||
|
if (m->y == m->ty)
|
||||||
{
|
{
|
||||||
|
// If so, clear line and start explosion
|
||||||
bmmcu_line(&sbm, m->sx * 2, m->sy, m->tx * 2, m->ty, 0);
|
bmmcu_line(&sbm, m->sx * 2, m->sy, m->tx * 2, m->ty, 0);
|
||||||
explosion_start(m->x * 2, m->y);
|
explosion_start(m->x * 2, m->y);
|
||||||
|
|
||||||
|
// Remove from active list
|
||||||
if (mp)
|
if (mp)
|
||||||
mp->next = m->next;
|
mp->next = m->next;
|
||||||
else
|
else
|
||||||
|
@ -180,6 +378,7 @@ void missile_animate(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Draw new pixel in missile trace
|
||||||
bmmc_put(&sbm, m->x * 2, m->y, 3);
|
bmmc_put(&sbm, m->x * 2, m->y, 3);
|
||||||
mp = m;
|
mp = m;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +387,7 @@ void missile_animate(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize incomming ICBM list
|
||||||
void icbm_init(void)
|
void icbm_init(void)
|
||||||
{
|
{
|
||||||
iused = nullptr;
|
iused = nullptr;
|
||||||
|
@ -197,9 +397,10 @@ void icbm_init(void)
|
||||||
icbms[15].next = nullptr;
|
icbms[15].next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a new ICBM to the attacking set
|
||||||
void icbm_start(int sx, int sy, int tx, int ty)
|
void icbm_start(int sx, int sy, int tx, int ty)
|
||||||
{
|
{
|
||||||
if (ifree)
|
if (icbmcount && ifree)
|
||||||
{
|
{
|
||||||
Missile * m = ifree;
|
Missile * m = ifree;
|
||||||
ifree = m->next;
|
ifree = m->next;
|
||||||
|
@ -210,16 +411,22 @@ void icbm_start(int sx, int sy, int tx, int ty)
|
||||||
m->sy = sy; m->y = sy;
|
m->sy = sy; m->y = sy;
|
||||||
m->tx = tx >> 1;
|
m->tx = tx >> 1;
|
||||||
m->ty = ty;
|
m->ty = ty;
|
||||||
m->cnt = 4;
|
m->cnt = 0;
|
||||||
|
|
||||||
m->dy = m->ty - m->sy;
|
m->dy = m->ty - m->sy;
|
||||||
m->dx = m->tx - m->sx;
|
m->dx = m->tx - m->sx;
|
||||||
|
m->stepx = 1;
|
||||||
if (m->dx < 0)
|
if (m->dx < 0)
|
||||||
|
{
|
||||||
m->dx = -m->dx;
|
m->dx = -m->dx;
|
||||||
|
m->stepx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
m->d = m->dy - m->dx;
|
m->d = m->dy - m->dx;
|
||||||
m->dx *= 2;
|
m->dx *= 2;
|
||||||
m->dy *= 2;
|
m->dy *= 2;
|
||||||
|
|
||||||
|
icbmcount--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,14 +437,16 @@ void icbm_animate(void)
|
||||||
{
|
{
|
||||||
Missile * mn = m->next;
|
Missile * mn = m->next;
|
||||||
|
|
||||||
m->cnt--;
|
// Check speed of ICBMs
|
||||||
|
m->cnt += icbmspeed;
|
||||||
if (!m->cnt)
|
while (m->cnt > 0)
|
||||||
{
|
{
|
||||||
|
m->cnt -= 32;
|
||||||
|
|
||||||
|
// Draw pixel in trace
|
||||||
bmmc_put(&sbm, m->x * 2, m->y, 2);
|
bmmc_put(&sbm, m->x * 2, m->y, 2);
|
||||||
|
|
||||||
m->cnt = 4;
|
// Advance using Bresenham
|
||||||
|
|
||||||
if (m->d >= 0)
|
if (m->d >= 0)
|
||||||
{
|
{
|
||||||
m->y++;
|
m->y++;
|
||||||
|
@ -245,80 +454,126 @@ void icbm_animate(void)
|
||||||
}
|
}
|
||||||
if (m->d < 0)
|
if (m->d < 0)
|
||||||
{
|
{
|
||||||
if (m->tx < m->sx)
|
m->x += m->stepx;
|
||||||
m->x--;
|
|
||||||
else
|
|
||||||
m->x++;
|
|
||||||
m->d += m->dy;
|
m->d += m->dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if colliding with cloud or target reached
|
||||||
if (bmmc_get(&sbm, m->x * 2, m->y) == 1 || m->y == m->ty)
|
if (bmmc_get(&sbm, m->x * 2, m->y) == 1 || m->y == m->ty)
|
||||||
{
|
{
|
||||||
|
// If so, clear trace and start explosion
|
||||||
bmmcu_line(&sbm, m->sx * 2, m->sy, m->tx * 2, m->ty, 0);
|
bmmcu_line(&sbm, m->sx * 2, m->sy, m->tx * 2, m->ty, 0);
|
||||||
explosion_start(m->x * 2, m->y);
|
explosion_start(m->x * 2, m->y);
|
||||||
|
|
||||||
|
// Check if we hit the ground
|
||||||
if (m->y == m->ty)
|
if (m->y == m->ty)
|
||||||
{
|
{
|
||||||
|
// If so, find matching city
|
||||||
int x = m->x * 2;
|
int x = m->x * 2;
|
||||||
char ix;
|
char ix;
|
||||||
if (x > 160)
|
if (x > 160)
|
||||||
ix = (x - 202) / 32 + 3;
|
ix = ((x - 202) >> 5) + 3;
|
||||||
else
|
else
|
||||||
ix = (x - 58) / 32;
|
ix = (x - 58) >> 5;
|
||||||
cities[ix] = false;
|
|
||||||
spr_show(ix + 1, false);
|
// Destroy, destroy, annihilate, kill, kill
|
||||||
|
if (cities[ix])
|
||||||
|
{
|
||||||
|
ncities--;
|
||||||
|
cities[ix] = false;
|
||||||
|
spr_show(ix + 1, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add score for destroyed ICBM
|
||||||
|
score_inc(0, 25);
|
||||||
|
|
||||||
|
// Remove from list
|
||||||
if (mp)
|
if (mp)
|
||||||
mp->next = m->next;
|
mp->next = m->next;
|
||||||
else
|
else
|
||||||
iused = m->next;
|
iused = m->next;
|
||||||
m->next = ifree;
|
m->next = ifree;
|
||||||
ifree = m;
|
ifree = m;
|
||||||
}
|
m = nullptr;
|
||||||
else
|
|
||||||
{
|
// End loop early
|
||||||
bmmc_put(&sbm, m->x * 2, m->y, 1);
|
break;
|
||||||
mp = m;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// If ICBM still in flight
|
||||||
|
if (m)
|
||||||
|
{
|
||||||
|
// Remember for list management
|
||||||
mp = m;
|
mp = m;
|
||||||
|
// Draw white head
|
||||||
|
bmmc_put(&sbm, m->x * 2, m->y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
m = mn;
|
m = mn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mountains_init(void)
|
// Initialize game screen
|
||||||
|
void screen_init(void)
|
||||||
{
|
{
|
||||||
|
// Clean up
|
||||||
|
bmmcu_rect_fill(&sbm, 0, 8, 320, 184, 0);
|
||||||
|
|
||||||
|
// Draw bottom
|
||||||
bmmcu_rect_fill(&sbm, 0, 192, 320, 8, 3);
|
bmmcu_rect_fill(&sbm, 0, 192, 320, 8, 3);
|
||||||
bmmc_quad_fill(&sbm, &scr, 0, 192, 16, 184, 32, 184, 48, 192, MixedColors[3][3]);
|
bmmc_quad_fill(&sbm, &scr, 0, 192, 16, 184, 32, 184, 48, 192, MixedColors[3][3]);
|
||||||
bmmc_quad_fill(&sbm, &scr, 136, 192, 152, 184, 176, 184, 192, 192, MixedColors[3][3]);
|
bmmc_quad_fill(&sbm, &scr, 136, 192, 152, 184, 176, 184, 192, 192, MixedColors[3][3]);
|
||||||
bmmc_quad_fill(&sbm, &scr, 272, 192, 288, 184, 304, 184, 320, 192, MixedColors[3][3]);
|
bmmc_quad_fill(&sbm, &scr, 272, 192, 288, 184, 304, 184, 320, 192, MixedColors[3][3]);
|
||||||
|
|
||||||
|
// Show cities
|
||||||
|
for(char i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
if (cities[i + 0])
|
||||||
|
spr_set(i + 1, true, 70 + 32 * i, 222, 65, 15, false, false, false);
|
||||||
|
if (cities[i + 3])
|
||||||
|
spr_set(i + 4, true, 214 + 32 * i, 222, 65, 15, false, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear inner area of screen
|
||||||
|
void screen_clear(void)
|
||||||
|
{
|
||||||
|
bmmcu_rect_fill(&sbm, 0, 8, 320, 176, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interrupt routine for joystick control, called by raster IRQ at bottom
|
||||||
|
// of screen
|
||||||
|
|
||||||
__interrupt void joy_interrupt()
|
__interrupt void joy_interrupt()
|
||||||
{
|
{
|
||||||
joy_poll(1);
|
// Poll joystick
|
||||||
|
joy_poll(0);
|
||||||
|
|
||||||
CrossX += joyx[1]; CrossY += joyy[1];
|
// Move crosshair coordinates
|
||||||
|
CrossX += 2 * joyx[0]; CrossY += 2 * joyy[0];
|
||||||
|
|
||||||
|
// Stop at edges of screen
|
||||||
if (CrossX < 8)
|
if (CrossX < 8)
|
||||||
CrossX = 8;
|
CrossX = 8;
|
||||||
else if (CrossX > 312)
|
else if (CrossX > 312)
|
||||||
CrossX = 312;
|
CrossX = 312;
|
||||||
if (CrossY < 16)
|
if (CrossY < 20)
|
||||||
CrossY = 16;
|
CrossY = 20;
|
||||||
else if (CrossY > 172)
|
else if (CrossY > 172)
|
||||||
CrossY = 172;
|
CrossY = 172;
|
||||||
|
|
||||||
|
// Move crosshair sprite
|
||||||
spr_move(0, CrossX + 14, CrossY + 40);
|
spr_move(0, CrossX + 14, CrossY + 40);
|
||||||
|
|
||||||
if (joyb[1])
|
// Check button
|
||||||
|
if (joyb[0])
|
||||||
{
|
{
|
||||||
|
// Avoid quickfire and bouncing
|
||||||
if (CrossDelay == 0)
|
if (CrossDelay == 0)
|
||||||
{
|
{
|
||||||
|
// Request fire from non interrupt code
|
||||||
CrossP = true;
|
CrossP = true;
|
||||||
CrossDelay = 4;
|
CrossDelay = 4;
|
||||||
}
|
}
|
||||||
|
@ -327,64 +582,267 @@ __interrupt void joy_interrupt()
|
||||||
CrossDelay--;
|
CrossDelay--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GameState
|
||||||
|
{
|
||||||
|
GS_READY, // Getting ready
|
||||||
|
GS_LEVEL, // Show level message
|
||||||
|
GS_PLAYING, // Playing the game
|
||||||
|
GS_BONUS, // Landed on pad
|
||||||
|
GS_ARMAGEDDON, // Show end game animation
|
||||||
|
GS_END // Wait for restart
|
||||||
|
};
|
||||||
|
|
||||||
|
// State of the game
|
||||||
|
struct Game
|
||||||
|
{
|
||||||
|
GameState state;
|
||||||
|
byte count, level;
|
||||||
|
|
||||||
|
} TheGame; // Only one game, so global variable
|
||||||
|
|
||||||
|
// Character buffer for some texts
|
||||||
|
char cbuffer[10];
|
||||||
|
|
||||||
|
void game_state(GameState state)
|
||||||
|
{
|
||||||
|
|
||||||
|
TheGame.state = state;
|
||||||
|
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case GS_READY:
|
||||||
|
// Start of new game
|
||||||
|
score_reset();
|
||||||
|
screen_init();
|
||||||
|
char_write(40, 100, s"READY PLAYER 1", 3);
|
||||||
|
|
||||||
|
// New cities
|
||||||
|
for(char i=0; i<6; i++)
|
||||||
|
cities[i] = true;
|
||||||
|
ncities = 6;
|
||||||
|
TheGame.count = 60;
|
||||||
|
|
||||||
|
// Starting at level 1
|
||||||
|
TheGame.level = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_LEVEL:
|
||||||
|
// Advance to next level
|
||||||
|
TheGame.level++;
|
||||||
|
utoa(TheGame.level ,cbuffer, 10);
|
||||||
|
screen_clear();
|
||||||
|
char_write(96, 100, s"LEVEL", 3);
|
||||||
|
char_write(96 + 16 * 6, 100, cbuffer, 3);
|
||||||
|
TheGame.count = 30;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_PLAYING:
|
||||||
|
// Avoid old fire request
|
||||||
|
CrossP = false;
|
||||||
|
|
||||||
|
// Setup display
|
||||||
|
screen_init();
|
||||||
|
missile_init();
|
||||||
|
explosion_init();
|
||||||
|
icbm_init();
|
||||||
|
|
||||||
|
// A new set of 30 missiles
|
||||||
|
nmissiles = 30;
|
||||||
|
status_missiles(nmissiles);
|
||||||
|
|
||||||
|
// Game parameters based on level
|
||||||
|
if (TheGame.level < 112)
|
||||||
|
icbmspeed = 8 + TheGame.level;
|
||||||
|
else
|
||||||
|
icbmspeed = 120;
|
||||||
|
|
||||||
|
if (TheGame.level < 50)
|
||||||
|
icbmcount = 5 + TheGame.level / 2;
|
||||||
|
else
|
||||||
|
icbmcount = 30;
|
||||||
|
|
||||||
|
TheGame.count = 15;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_BONUS:
|
||||||
|
{
|
||||||
|
// Show bonus
|
||||||
|
|
||||||
|
unsigned bonus = ncities * 50 + nmissiles * 5;
|
||||||
|
utoa(bonus, cbuffer, 10);
|
||||||
|
|
||||||
|
char_write(96, 100, s"BONUS", 3);
|
||||||
|
char_write(96 + 16 * 6, 100, cbuffer, 3);
|
||||||
|
|
||||||
|
score_inc(0, bonus);
|
||||||
|
TheGame.count = 30;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GS_ARMAGEDDON:
|
||||||
|
TheGame.count = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_END:
|
||||||
|
char_write(104, 92, s"THE END", 0);
|
||||||
|
TheGame.count = 120;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main game play code
|
||||||
|
void game_play(void)
|
||||||
|
{
|
||||||
|
// Check if fire request
|
||||||
|
if (CrossP)
|
||||||
|
{
|
||||||
|
// Find lauch site
|
||||||
|
int sx = 160;
|
||||||
|
if (CrossX < 120)
|
||||||
|
sx = 24;
|
||||||
|
else if (CrossX > 200)
|
||||||
|
sx = 296
|
||||||
|
|
||||||
|
// Fire missile
|
||||||
|
missile_start(sx, 184, CrossX, CrossY);
|
||||||
|
|
||||||
|
// Reset request
|
||||||
|
CrossP = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for next ICMB to enter the game
|
||||||
|
if (!--TheGame.count)
|
||||||
|
{
|
||||||
|
// Pick target city
|
||||||
|
char ci;
|
||||||
|
do {
|
||||||
|
ci = rand() & 7;
|
||||||
|
} while (ci >= 6 || !cities[ci]);
|
||||||
|
|
||||||
|
int cx;
|
||||||
|
if (ci < 3)
|
||||||
|
cx = 58 + 32 * ci;
|
||||||
|
else
|
||||||
|
cx = 202 + 32 * (ci - 3);
|
||||||
|
|
||||||
|
// Launch ICBM
|
||||||
|
icbm_start((rand() & 0xff) + 32, 0, cx, 184);
|
||||||
|
|
||||||
|
// Next lauch time
|
||||||
|
TheGame.count = 8 + (rand() & 63);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance defending missiles by four pixels
|
||||||
|
for(char i=0; i<4; i++)
|
||||||
|
missile_animate();
|
||||||
|
|
||||||
|
// Advance ICBMs
|
||||||
|
icbm_animate();
|
||||||
|
|
||||||
|
// Show explosions
|
||||||
|
explosion_animate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main game loop, entered every VSYNC, slower if too busy with explosions
|
||||||
|
void game_loop(void)
|
||||||
|
{
|
||||||
|
switch(TheGame.state)
|
||||||
|
{
|
||||||
|
case GS_READY:
|
||||||
|
if (!--TheGame.count)
|
||||||
|
game_state(GS_LEVEL);
|
||||||
|
break;
|
||||||
|
case GS_LEVEL:
|
||||||
|
if (!--TheGame.count)
|
||||||
|
game_state(GS_PLAYING);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_PLAYING:
|
||||||
|
game_play();
|
||||||
|
|
||||||
|
// Check for level and game end coditions
|
||||||
|
if (!icbmcount && !iused && !eused)
|
||||||
|
game_state(GS_BONUS);
|
||||||
|
else if (ncities == 0)
|
||||||
|
game_state(GS_ARMAGEDDON);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_BONUS:
|
||||||
|
if (!--TheGame.count)
|
||||||
|
game_state(GS_LEVEL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_ARMAGEDDON:
|
||||||
|
// Draw end game animation
|
||||||
|
TheGame.count++;
|
||||||
|
bmmc_circle(&sbm, &scr, 160, 100, TheGame.count, 1);
|
||||||
|
explosion_animate();
|
||||||
|
if (TheGame.count == 90)
|
||||||
|
game_state(GS_END);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GS_END:
|
||||||
|
if (!--TheGame.count)
|
||||||
|
game_state(GS_READY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interrupts for status line and joystick routine
|
||||||
RIRQCode bottom, top;
|
RIRQCode bottom, top;
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
// Activate trampoline
|
||||||
mmap_trampoline();
|
mmap_trampoline();
|
||||||
|
|
||||||
|
// Disable CIA interrupts, we do not want interference
|
||||||
|
// with our joystick interrupt
|
||||||
|
cia_init();
|
||||||
|
|
||||||
|
// Copy assets
|
||||||
mmap_set(MMAP_RAM);
|
mmap_set(MMAP_RAM);
|
||||||
memcpy(Sprites, MissileSprites, 1024);
|
memcpy(Sprites, MissileSprites, 1024);
|
||||||
memcpy(Charset, MissileChars, 2048);
|
memcpy(Charset, MissileChars, 2048);
|
||||||
mmap_set(MMAP_NO_ROM);
|
mmap_set(MMAP_NO_ROM);
|
||||||
|
|
||||||
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
// Clean out screen space
|
||||||
spr_init(Color1);
|
|
||||||
|
|
||||||
// initialize raster IRQ
|
|
||||||
rirq_init(true);
|
|
||||||
|
|
||||||
vic.color_back = VCOL_BLACK;
|
|
||||||
vic.color_border = VCOL_BLACK;
|
|
||||||
|
|
||||||
memset(Color1, 0x18, 1000);
|
memset(Color1, 0x18, 1000);
|
||||||
memset(Color2, 0x06, 1000);
|
memset(Color2, 0x06, 1000);
|
||||||
memset(Hires, 0, 8000);
|
memset(Hires, 0, 8000);
|
||||||
memset(Color2 + 40 * 23, 0x07, 80);
|
memset(Color2 + 40 * 23, 0x07, 80);
|
||||||
|
|
||||||
bm_init(&sbm, Hires, 40, 25);
|
// initialize raster IRQ
|
||||||
missile_init();
|
rirq_init(true);
|
||||||
explosion_init();
|
|
||||||
icbm_init();
|
|
||||||
mountains_init();
|
|
||||||
|
|
||||||
|
// Switch to hires mode
|
||||||
|
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
||||||
|
spr_init(Color1);
|
||||||
|
|
||||||
|
// Black background and border
|
||||||
|
vic.color_back = VCOL_BLACK;
|
||||||
|
vic.color_border = VCOL_BLACK;
|
||||||
|
|
||||||
|
// Init bitmap
|
||||||
|
bm_init(&sbm, Hires, 40, 25);
|
||||||
|
|
||||||
|
// Init status line
|
||||||
|
status_init();
|
||||||
|
|
||||||
|
// Init cross hair sprite
|
||||||
spr_set(0, true, CrossX + 14, CrossY + 40, 64, 1, false, false, false);
|
spr_set(0, true, CrossX + 14, CrossY + 40, 64, 1, false, false, false);
|
||||||
|
|
||||||
for(char i=0; i<3; i++)
|
// Build to multicolor highres at top of screen
|
||||||
{
|
|
||||||
spr_set(i + 1, true, 70 + 32 * i, 222, 65, 15, false, false, false);
|
|
||||||
spr_set(i + 4, true, 214 + 32 * i, 222, 65, 15, false, false, false);
|
|
||||||
|
|
||||||
cities[i + 0] = true;
|
|
||||||
cities[i + 3] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the switch to normal IRQ
|
|
||||||
rirq_build(&top, 3);
|
rirq_build(&top, 3);
|
||||||
// Change color for ceiling
|
|
||||||
rirq_delay(&top, 10);
|
rirq_delay(&top, 10);
|
||||||
rirq_write(&top, 1, &vic.ctrl1, VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
rirq_write(&top, 1, &vic.ctrl1, VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
||||||
rirq_write(&top, 2, &vic.memptr, 0x28);
|
rirq_write(&top, 2, &vic.memptr, 0x28);
|
||||||
// place this at the bottom
|
|
||||||
rirq_set(0, 57, &top);
|
rirq_set(0, 57, &top);
|
||||||
|
|
||||||
// Build the switch to normal IRQ
|
// Switch to text mode for status line and poll joystick at bottom
|
||||||
rirq_build(&bottom, 3);
|
rirq_build(&bottom, 3);
|
||||||
rirq_write(&bottom, 0, &vic.memptr, 0x27);
|
rirq_write(&bottom, 0, &vic.memptr, 0x27);
|
||||||
rirq_write(&bottom, 1, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
rirq_write(&bottom, 1, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
||||||
// Change color for ceiling
|
|
||||||
rirq_call(&bottom, 2, joy_interrupt);
|
rirq_call(&bottom, 2, joy_interrupt);
|
||||||
// place this at the bottom
|
|
||||||
rirq_set(1, 250, &bottom);
|
rirq_set(1, 250, &bottom);
|
||||||
|
|
||||||
// sort the raster IRQs
|
// sort the raster IRQs
|
||||||
|
@ -393,42 +851,12 @@ int main(void)
|
||||||
// start raster IRQ processing
|
// start raster IRQ processing
|
||||||
rirq_start();
|
rirq_start();
|
||||||
|
|
||||||
bool launched = false;
|
// start game state machine
|
||||||
|
game_state(GS_READY);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if (CrossP)
|
game_loop();
|
||||||
{
|
rirq_wait();
|
||||||
int sx = 160;
|
|
||||||
if (CrossX < 120)
|
|
||||||
sx = 24;
|
|
||||||
else if (CrossX > 200)
|
|
||||||
sx = 296
|
|
||||||
missile_start(sx, 184, CrossX, CrossY);
|
|
||||||
CrossP = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(rand() & 63))
|
|
||||||
{
|
|
||||||
char ci;
|
|
||||||
do {
|
|
||||||
ci = rand() & 7;
|
|
||||||
} while (ci >= 6 || !cities[ci]);
|
|
||||||
|
|
||||||
int cx;
|
|
||||||
if (ci < 3)
|
|
||||||
cx = 58 + 32 * ci;
|
|
||||||
else
|
|
||||||
cx = 202 + 32 * (ci - 3);
|
|
||||||
|
|
||||||
icbm_start((rand() & 0xff) + 32, 0, cx, 184);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(char i=0; i<4; i++)
|
|
||||||
missile_animate();
|
|
||||||
icbm_animate();
|
|
||||||
explosion_animate();
|
|
||||||
|
|
||||||
vic_waitFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -233,8 +233,8 @@ void game_loop(void)
|
||||||
break;
|
break;
|
||||||
case GS_PLAYING:
|
case GS_PLAYING:
|
||||||
// Check player input on every frame
|
// Check player input on every frame
|
||||||
joy_poll(1);
|
joy_poll(0);
|
||||||
snake_control(&TheGame.snake, joyx[1], joyy[1]);
|
snake_control(&TheGame.snake, joyx[0], joyy[0]);
|
||||||
|
|
||||||
if (!--TheGame.count)
|
if (!--TheGame.count)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
|
@ -388,8 +388,8 @@ int main(void)
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// Check the joystick
|
// Check the joystick
|
||||||
joy_poll(1);
|
joy_poll(0);
|
||||||
if (joyx[1] == 1)
|
if (joyx[0] == 1)
|
||||||
{
|
{
|
||||||
// Move to the right
|
// Move to the right
|
||||||
if (gridX < 24)
|
if (gridX < 24)
|
||||||
|
@ -399,7 +399,7 @@ int main(void)
|
||||||
scroll_left();
|
scroll_left();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (joyx[1] == -1)
|
else if (joyx[0] == -1)
|
||||||
{
|
{
|
||||||
// Move to the left
|
// Move to the left
|
||||||
if (gridX > 0)
|
if (gridX > 0)
|
||||||
|
@ -409,7 +409,7 @@ int main(void)
|
||||||
scroll_right();
|
scroll_right();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (joyy[1] == 1)
|
else if (joyy[0] == 1)
|
||||||
{
|
{
|
||||||
// Move down
|
// Move down
|
||||||
if (gridY < 39)
|
if (gridY < 39)
|
||||||
|
@ -419,7 +419,7 @@ int main(void)
|
||||||
scroll_up();
|
scroll_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (joyy[1] == -1)
|
else if (joyy[0] == -1)
|
||||||
{
|
{
|
||||||
// Move up
|
// Move up
|
||||||
if (gridY > 0)
|
if (gridY > 0)
|
||||||
|
|
|
@ -33,11 +33,11 @@ int main(void)
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// Poll joytick
|
// Poll joytick
|
||||||
joy_poll(1);
|
joy_poll(0);
|
||||||
|
|
||||||
// Change position according to joystick
|
// Change position according to joystick
|
||||||
spx += joyx[1];
|
spx += joyx[0];
|
||||||
spy += joyy[1];
|
spy += joyy[0];
|
||||||
|
|
||||||
// Move sprites on screen
|
// Move sprites on screen
|
||||||
spr_move(0, spx, spy);
|
spr_move(0, spx, spy);
|
||||||
|
|
Loading…
Reference in New Issue