mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-03-14 20:15:05 +00:00
446 lines
No EOL
24 KiB
HolyC
Executable file
446 lines
No EOL
24 KiB
HolyC
Executable file
RegDefault("ZealOS/BomberGolf", "I64 best_score=99999;\n");
|
||
RegExe("ZealOS/BomberGolf");
|
||
|
||
|
||
|
||
$SP,"<1>",BI=1$
|
||
|
||
|
||
|
||
|
||
$SP,"<2>",BI=2$
|
||
|
||
|
||
|
||
$SP,"<3>",BI=3$
|
||
|
||
|
||
$SP,"<4>",BI=4$
|
||
|
||
|
||
$SP,"<5>",BI=5$
|
||
|
||
|
||
|
||
$SP,"<6>",BI=6$
|
||
|
||
|
||
|
||
|
||
$SP,"<7>",BI=7$
|
||
|
||
|
||
|
||
|
||
$SP,"<8>",BI=8$
|
||
|
||
|
||
|
||
|
||
$SP,"<9>",BI=9$
|
||
|
||
|
||
|
||
|
||
$SP,"<10>",BI=10$
|
||
|
||
|
||
#define MAP_WIDTH 600
|
||
#define MAP_HEIGHT 600
|
||
|
||
#define TREES_NUM 64
|
||
class Tree
|
||
{
|
||
I64 x, y;
|
||
|
||
} trees[TREES_NUM];
|
||
|
||
|
||
I64 target_count, key_count;
|
||
|
||
|
||
#define TARGETS_NUM 10
|
||
|
||
#define MDF_TANK 0
|
||
#define MDF_BUNKER 1
|
||
|
||
#define TANK_V 10.0
|
||
|
||
class Target
|
||
{
|
||
F64 x, y, Θ;
|
||
U8 *alive_img, *dead_img1, *dead_img2;
|
||
U8 type;
|
||
Bool dead, pad[6];
|
||
|
||
} targets[TARGETS_NUM];
|
||
|
||
#define FALL_TIME 3.00
|
||
#define EXPLODE_TIME 0.25
|
||
class Bomb
|
||
{
|
||
Bomb *next, *last;
|
||
F64 x, y, t;
|
||
Bool exploding;
|
||
|
||
} bomb_head;
|
||
|
||
F64 v, x, y, Θ, Θf; //Θf is the final theta. Θ is gradually changed until it reaches Θf.
|
||
|
||
U0 DrawIt(CTask *task, CDC *dc)
|
||
{
|
||
I64 i, j;
|
||
Bomb *tmpb;
|
||
Target *tmpt;
|
||
F64 ts = tS, dx, dy;
|
||
|
||
dc->color = ROPF_DITHER|BROWN << 16 | YELLOW;
|
||
GrRect3(dc, 0, 0, 0, dc->width, dc->height);
|
||
|
||
dc->x = task->pix_width >> 1;
|
||
dc->y = task->pix_height >> 1;
|
||
dc->flags |= DCF_TRANSFORMATION;
|
||
Mat4x4TranslationEqu(dc->r, x, y, 0);
|
||
Mat4x4RotZ(dc->r, Θ);
|
||
dc->color = BLACK;
|
||
GrBorder(dc, -MAP_WIDTH >> 1, -MAP_HEIGHT >> 1, MAP_WIDTH >> 1, MAP_HEIGHT >> 1);
|
||
for (i = 0; i < TARGETS_NUM; i++)
|
||
{
|
||
tmpt = &targets[i];
|
||
if (tmpt->dead)
|
||
{
|
||
if (i & 1)
|
||
{
|
||
dc->flags |= DCF_SYMMETRY | DCF_JUST_MIRROR;
|
||
DCSymmetry3Set(dc, tmpt->x, tmpt->y, 0,
|
||
tmpt->x, tmpt->y, 1,
|
||
tmpt->x + 1024 * Cos(tmpt->Θ), tmpt->y + 1024 * Sin(tmpt->Θ), 0);
|
||
}
|
||
if (Blink(15))
|
||
Sprite3ZB(dc, tmpt->x, tmpt->y, 0, tmpt->dead_img1, tmpt->Θ);
|
||
else
|
||
Sprite3ZB(dc, tmpt->x, tmpt->y, 0, tmpt->dead_img2, tmpt->Θ);
|
||
dc->flags &= ~(DCF_SYMMETRY|DCF_JUST_MIRROR);
|
||
}
|
||
else
|
||
Sprite3ZB(dc, tmpt->x, tmpt->y, 0, tmpt->alive_img, tmpt->Θ);
|
||
}
|
||
|
||
for (i = 0; i < TREES_NUM; i++)
|
||
Sprite3(dc, trees[i].x, trees[i].y, 0, $IB,"<2>",BI=2$);
|
||
|
||
for (i = 0; i < TARGETS_NUM; i++)
|
||
{
|
||
tmpt = &targets[i];
|
||
if (tmpt->dead)
|
||
{
|
||
for (j = 0; j < 40; j++)
|
||
{
|
||
dc->thick = 4;
|
||
if (j & 1)
|
||
dc->color = ROPF_DITHER | LTGRAY << 16 | BLACK;
|
||
else
|
||
dc->color = ROPF_DITHER | DKGRAY << 16 | LTGRAY;
|
||
dx = 15 * Sin(ts / 4 + j << 6) + j >> 2;
|
||
dy = 10 * FullTri(ts / 3 + j / 2.0, 20) + j >> 2;
|
||
GrPlot3(dc, tmpt->x + 5 + dx + 0.5 * dy, tmpt->y + 0.5 * dx + dy, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
tmpb = bomb_head.next;
|
||
while (tmpb != &bomb_head)
|
||
{
|
||
if (tmpb->t + FALL_TIME < tS)
|
||
{
|
||
if (Blink(10))
|
||
Sprite3(dc, tmpb->x, tmpb->y, 0, $IB,"<9>",BI=9$);
|
||
else
|
||
Sprite3(dc, tmpb->x, tmpb->y, 0, $IB,"<10>",BI=10$);
|
||
}
|
||
tmpb = tmpb->next;
|
||
}
|
||
|
||
dc->flags &= ~DCF_TRANSFORMATION;
|
||
Sprite3(dc, task->pix_width >> 1, task->pix_height >> 1, 0, $IB,"<1>",BI=1$);
|
||
dc->color = RED;
|
||
GrPrint(dc, 0, 0, "Targets:%02d KeyStrokes:%04d Best:%04d", target_count, key_count, best_score);
|
||
if (!target_count && Blink(4))
|
||
GrPrint(dc, (task->pix_width - FONT_WIDTH * 14) >> 1,
|
||
(task->pix_height - FONT_HEIGHT) >> 1 - 32, "Game Completed");
|
||
}
|
||
|
||
U0 BombHit(Bomb *tmpb)
|
||
{
|
||
I64 i;
|
||
|
||
for (i = 0; i < TARGETS_NUM; i++)
|
||
{
|
||
if (!targets[i].dead && SqrI64(tmpb->x - targets[i].x) + SqrI64(tmpb->y - targets[i].y) < 20 * 20)
|
||
{
|
||
targets[i].dead = TRUE;
|
||
target_count--;
|
||
}
|
||
}
|
||
QueueRemove(tmpb);
|
||
Free(tmpb);
|
||
}
|
||
|
||
U0 BombDrop(F64 x, F64 y)
|
||
{
|
||
Bomb *tmpb = MAlloc(sizeof(Bomb));
|
||
|
||
tmpb->x = x;
|
||
tmpb->y = y;
|
||
tmpb->t = tS;
|
||
tmpb->exploding = FALSE;
|
||
QueueInsert(tmpb, bomb_head.last);
|
||
Sweep(FALL_TIME * 1000, 74, 62);
|
||
}
|
||
|
||
I64 AnimateTask(CTask *)
|
||
{
|
||
F64 last_t = tS, dt;
|
||
I64 i;
|
||
Bomb *tmpb, *tmpb1;
|
||
Target *tmpt;
|
||
|
||
while (TRUE)
|
||
{
|
||
dt = tS - last_t;
|
||
last_t = tS;
|
||
|
||
if (bomb_head.next == &bomb_head)
|
||
{
|
||
if (target_count)
|
||
Sound(Freq2Ona(100 + 60 * Clamp(0.1 * (1.0 + Abs(Wrap(Θf - Θ, -π))) ` 4.0, -3, 3)));
|
||
else if (key_count < best_score)
|
||
{
|
||
best_score = key_count;
|
||
Sleep(150);
|
||
Sound(74);
|
||
Sleep(150);
|
||
Sound;
|
||
Sleep(150);
|
||
Sound(74);
|
||
Sleep(150);
|
||
Sound;
|
||
}
|
||
else
|
||
Sound;
|
||
}
|
||
|
||
Θ += dt * (Θf - Θ);
|
||
x += dt * v * Sin(Θ);
|
||
y += dt * v * Cos(Θ);
|
||
|
||
for (i = 0; i < TARGETS_NUM; i++)
|
||
{
|
||
tmpt = &targets[i];
|
||
if (!tmpt->dead && tmpt->type == MDF_TANK)
|
||
{
|
||
tmpt->x += dt * TANK_V * Cos(tmpt->Θ);
|
||
tmpt->y += dt * TANK_V * Sin(tmpt->Θ);
|
||
if (i & 1)
|
||
tmpt->Θ += dt * π / 16;
|
||
else
|
||
tmpt->Θ -= dt * π / 16;
|
||
}
|
||
}
|
||
|
||
tmpb = bomb_head.next;
|
||
while (tmpb != &bomb_head)
|
||
{
|
||
tmpb1 = tmpb->next;
|
||
if (tmpb->t + FALL_TIME + EXPLODE_TIME < tS)
|
||
BombHit(tmpb);
|
||
else if (tmpb->t + FALL_TIME < tS && !tmpb->exploding)
|
||
{
|
||
Noise(EXPLODE_TIME * 1000, 62, 74);
|
||
tmpb->exploding = TRUE;
|
||
}
|
||
tmpb = tmpb1;
|
||
}
|
||
|
||
Sleep(10);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
U0 Init()
|
||
{
|
||
I64 i;
|
||
Target *tmpt;
|
||
|
||
v = 20;
|
||
x = -MAP_WIDTH >> 1;
|
||
y = -MAP_HEIGHT >> 1;
|
||
Θf = Θ = 1 * π / 4;
|
||
|
||
QueueInit(&bomb_head);
|
||
|
||
MemSet(trees, 0, sizeof(trees));
|
||
for (i = 0; i < TREES_NUM; i++)
|
||
{
|
||
trees[i].x = RandU32 % MAP_WIDTH - MAP_WIDTH >> 1;
|
||
trees[i].y = RandU32 % MAP_HEIGHT - MAP_HEIGHT >> 1;
|
||
}
|
||
|
||
MemSet(targets, 0, sizeof(targets));
|
||
for (i = 0; i < TARGETS_NUM; i++)
|
||
{
|
||
tmpt = &targets[i];
|
||
tmpt->x = RandU32 % MAP_WIDTH - MAP_WIDTH >> 1;
|
||
tmpt->y = RandU32 % MAP_HEIGHT - MAP_HEIGHT >> 1;
|
||
if (i < TARGETS_NUM / 3)
|
||
{
|
||
tmpt->type = MDF_BUNKER;
|
||
tmpt->Θ = (RandU16 & 3) * π / 2;
|
||
tmpt->alive_img = $IB,"<6>",BI=6$;
|
||
tmpt->dead_img1 = $IB,"<7>",BI=7$;
|
||
tmpt->dead_img2 = $IB,"<8>",BI=8$;
|
||
}
|
||
else
|
||
{
|
||
tmpt->type = MDF_TANK;
|
||
tmpt->Θ = Rand * 2 * π;
|
||
tmpt->alive_img = $IB,"<3>",BI=3$;
|
||
tmpt->dead_img1 = $IB,"<4>",BI=4$;
|
||
tmpt->dead_img2 = $IB,"<5>",BI=5$;
|
||
}
|
||
}
|
||
key_count = 0;
|
||
target_count = TARGETS_NUM;
|
||
}
|
||
|
||
U0 CleanUp()
|
||
{
|
||
QueueDel(&bomb_head, TRUE);
|
||
}
|
||
|
||
U0 BomberGolf()
|
||
{
|
||
I64 sc;
|
||
|
||
MenuPush( "File {"
|
||
" Abort(,CH_SHIFT_ESC);"
|
||
" Exit(,CH_ESC);"
|
||
"}"
|
||
"Play {"
|
||
" Restart(,'\n');"
|
||
" Faster(,,SC_CURSOR_UP);"
|
||
" Slower(,,SC_CURSOR_DOWN);"
|
||
" Left(,,SC_CURSOR_LEFT);"
|
||
" Right(,,SC_CURSOR_RIGHT);"
|
||
" Bomb(,CH_SPACE);"
|
||
"}"
|
||
);
|
||
SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
|
||
AutoComplete;
|
||
WinBorder;
|
||
WinMax;
|
||
DocCursor;
|
||
DocClear;
|
||
PaletteSetLight(FALSE);
|
||
Fs->animate_task = Spawn(&AnimateTask, Fs, "Animate",, Fs);
|
||
Fs->draw_it = &DrawIt;
|
||
Init;
|
||
try
|
||
{
|
||
while (TRUE)
|
||
switch (KeyGet(&sc))
|
||
{
|
||
case 0:
|
||
switch (sc.u8[0])
|
||
{
|
||
case SC_CURSOR_UP:
|
||
v += 10;
|
||
if (v > 300)
|
||
v = 300;
|
||
break;
|
||
|
||
case SC_CURSOR_DOWN:
|
||
v -= 10;
|
||
if (v < 20)
|
||
v = 20;
|
||
break;
|
||
|
||
case SC_CURSOR_LEFT:
|
||
key_count++;
|
||
Θf += 1.0 / (Abs(Wrap(Θf - Θ, -π)) + 2 * π);
|
||
break;
|
||
|
||
case SC_CURSOR_RIGHT:
|
||
key_count++;
|
||
Θf -= 1.0 / (Abs(Wrap(Θf - Θ, -π)) + 2 * π);
|
||
break;
|
||
|
||
}
|
||
break;
|
||
|
||
case CH_SPACE:
|
||
key_count++;
|
||
BombDrop(-x - 0.8 * FALL_TIME * v * Sin(Θ), -y - 0.8 * FALL_TIME * v * Cos(Θ));
|
||
break;
|
||
|
||
case '\n':
|
||
CleanUp;
|
||
Init;
|
||
break;
|
||
|
||
case CH_ESC:
|
||
case CH_SHIFT_ESC:
|
||
goto bm_done;
|
||
}
|
||
bm_done:
|
||
}
|
||
catch
|
||
PutExcept;
|
||
SettingsPop;
|
||
CleanUp;
|
||
MenuPop;
|
||
RegWrite("ZealOS/BomberGolf", "I64 best_score=%d;\n", best_score);
|
||
}
|
||
|
||
BomberGolf;
|
||
|