|
|
// // Bomber By Kazys Stepanas //
//-------------------------------------------------------------------------------------------------- // Globals. //-------------------------------------------------------------------------------------------------- global bgCol = CA.B_BLACK; global quit = false; global lastTouchedBlock = -1; global player;
global gameLevel = 1;
global blocks = table(count = 0); global powerups = table(count = 0); global enemies = table(count = 0); global blockDeadZone = table(x1 = 31, y1 = 8, x2 = 39, y2 = 14); global enemyDeadZone = table(x1 = 22, y1 = 7, x2 = 45, y2 = 16);
// Thing types. global T_Space = 0; global T_Player = 1; global T_Bomb = 2; global T_Explosion = 3; global T_Block = 4; global T_Grid = 5; global T_Powerup = 6; global T_Enemy = 7;
// Powerup types. global PT_Bomb = 1; global PT_Size = 2; global PT_Life = 3;
// Dead zone types. global DT_None = 0; global DT_Block = 1; global DT_Enemy = 2;
//-------------------------------------------------------------------------------------------------- // Grid control. //-------------------------------------------------------------------------------------------------- global grid = table(startX = 0, startY = 0, spaceX = 1, spaceY = 1, rows = 0, cols = 0);
//-------------------------------------------------------------------------------------------------- // Constants //-------------------------------------------------------------------------------------------------- global screen = table(w = 80, h = 23); global statusY = 24;
global bombFuse = 1.25; global explodeTime = 0.75; global explodeCycle = 0.05; global maxPlayerBombs = 10; global maxPlayerSize = 5; global maxPowerups = 20; global maxLives = 5; global startLives = 3;
global scoreBlock = 10; global scoreNME = 50;
global nmeMoveTime = 1.0; global powerupChance = 40; global maxLevel = 10; global maxBlockHits = 3;
//-------------------------------------------------------------------------------------------------- // Graphics //-------------------------------------------------------------------------------------------------- global playerPix = "\2"; global playerDeadPix = "\5"; global bombPix = "\15"; global expPix = "+"; global gridPix = "\178"; global block1Pix = "\176"; global block2Pix = "\177"; global block3Pix = "\219"; global nmePix = "\232"; global lifePix = "\3"; global bombSizePix = "#"; global bombExtraPix = "*"; global spacePix = " ";
//-------------------------------------------------------------------------------------------------- // Colours //-------------------------------------------------------------------------------------------------- global bgColour = 0; global fgColour = CA.F_RED | CA.F_GREEN;
global playerColour = CA.F_GREEN | CA.F_BLUE;// | CA.F_INTENSITY; global gridColour = CA.F_RED; global blockColour = CA.F_RED | CA.F_GREEN | CA.F_INTENSITY; global nmeColour = CA.F_RED | CA.F_BLUE; global powerupColour = CA.F_GREEN | CA.F_INTENSITY; global puLifeColour = CA.F_RED;
global statusColour = CA.F_RED | CA.F_GREEN;
global bombColour = CA.F_BLUE | CA.F_INTENSITY; global expColourCount = 5; global expColours = array(expColourCount);
global readyColour = CA.F_RED;
expColours[0] = CA.F_RED | CA.F_INTENSITY; expColours[1] = CA.F_BLUE|CA.F_RED; expColours[2] = CA.F_RED|CA.F_GREEN | CA.F_INTENSITY; expColours[3] = CA.F_RED; expColours[4] = CA.F_RED|CA.F_GREEN;
//-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- global IsPointWithin = function(a_ptx, a_pty, a_rx1, a_ry1, a_rx2, a_ry2) { return (a_ptx >= a_rx1 and a_ptx <= a_rx2 and a_pty >= a_ry1 and a_pty <= a_ry2); };
global OverlapRect = function(a_r1x1, a_r1y1, a_r1x2, a_r1y2, a_r2x1, a_r2y1, a_r2x2, a_r2y2) { // Test one rect against the other. if (IsPointWithin(a_r2x1, a_r2y1, a_r1x1, a_r1y1, a_r1x2, a_r1y2) or IsPointWithin(a_r2x1, a_r2y2, a_r1x1, a_r1y1, a_r1x2, a_r1y2) or IsPointWithin(a_r2x2, a_r2y2, a_r1x1, a_r1y1, a_r1x2, a_r1y2) or IsPointWithin(a_r2x2, a_r2y1, a_r1x1, a_r1y1, a_r1x2, a_r1y2)) { return true; }
// Test the other rect. if (IsPointWithin(a_r1x1, a_r1y1, a_r2x1, a_r2y1, a_r2x2, a_r2y2) or IsPointWithin(a_r1x1, a_r1y2, a_r2x1, a_r2y1, a_r2x2, a_r2y2) or IsPointWithin(a_r1x2, a_r1y2, a_r2x1, a_r2y1, a_r2x2, a_r2y2) or IsPointWithin(a_r1x2, a_r1y1, a_r2x1, a_r2y1, a_r2x2, a_r2y2)) { return true; }
return false; };
global ScreenClampX = function(a_x) { if (a_x < 0) { return 0; } else if (a_x >= screen.w) { return screen.w-1; }
return a_x; };
global ScreenClampY = function(a_y) { if (a_y < 0) { return 0; } else if (a_y >= screen.h) { return screen.h-1; }
return a_y; };
global ScreenClamp = function() { .x = ScreenClampX(.x); .y = ScreenClampY(.y); };
global BombAt = function(a_x, a_y) { for (i = 0; i < player.nextBomb; i=i+1) { bomb = player.bombs[i]; if (bomb.x == a_x and bomb.y == a_y) { return true; } } return false; };
global PointOverlap = function(a_x1, a_y1, a_x2, a_y2) { return IsPointWithin(.x, .y, a_x1, a_y1, a_x2, a_y2); };
//-------------------------------------------------------------------------------------------------- // Player object. //-------------------------------------------------------------------------------------------------- global Player = function() { newPlayer = table(x = -1, y = -1); newPlayer.bombSize = 1; newPlayer.bombFuse = bombFuse; newPlayer.bombs = array(maxPlayerBombs); newPlayer.maxBombs = 1; newPlayer.nextBomb = 0; newPlayer.threadId = -1; newPlayer.lastCanMoveThing = null; newPlayer.dead = false; newPlayer.lives = startLives; newPlayer.score = 0; newPlayer.threadId = -1;
//------------------------------------ //------------------------------------ newPlayer.Draw = function() { CATTRIB(bgColour | playerColour); if (!.dead) { XYTEXT(.x, .y, playerPix); } else { XYTEXT(.x, .y, playerDeadPix); } };
//------------------------------------ //------------------------------------ newPlayer.DrawStatus = function() { CATTRIB(bgColour | puLifeColour | CA.F_INTENSITY); XYTEXT(0, statusY, format("%s : %d ", lifePix, .lives)); CATTRIB(bgColour | powerupColour); XYTEXT(10, statusY, format("%s : %d ", bombExtraPix, .maxBombs)); XYTEXT(20, statusY, format("%s : %d ", bombSizePix, .bombSize)); CATTRIB(bgColour | statusColour); XYTEXT(50, statusY, format("Score : %d ", .score)); };
newPlayer.AddScore = function(a_add) { .score = .score + a_add; .DrawStatus(); };
//------------------------------------ //------------------------------------ newPlayer.CanMove = function(a_x, a_y) { thing = GetThingAt(a_x, a_y, false); .lastCanMoveThing = thing; return thing.type == T_Space or thing.type == T_Explosion or thing.type == T_Powerup or thing.type == T_Enemy; };
//------------------------------------ //------------------------------------ newPlayer.Move = function(a_dx, a_dy) { if (!.dead) { oldX = .x; oldY = .y; newX = ScreenClampX(.x + a_dx); newY = ScreenClampY(.y + a_dy);
if (.CanMove(newX, newY)) { .x = newX; .y = newY; if (.lastCanMoveThing.type == T_Powerup) { .lastCanMoveThing.thing.Pickup(); } else if (.lastCanMoveThing.type == T_Explosion or .lastCanMoveThing.type == T_Enemy) { .Kill(); }
RefreshXY(oldX, oldY); RefreshXY(.x, .y); } } };
//------------------------------------ //------------------------------------ newPlayer.Kill = function() { .dead = true; RefreshXY(.x, .y); };
//------------------------------------ //------------------------------------ newPlayer.DropBomb = function() { if (!.dead and .nextBomb < .maxBombs and !BombAt(.x, .y)) { newBomb = Bomb(.x, .y, .bombSize, .bombFuse, this); .bombs[.nextBomb] = newBomb; .nextBomb = .nextBomb + 1; newBomb.Draw(); } };
//------------------------------------ //------------------------------------ newPlayer.FreeBomb = function(a_bomb) { found = false; limit = .nextBomb; for (i = 0; i < limit; i=i+1) { if (.bombs[i] == a_bomb) { found = true; .nextBomb = .nextBomb - 1; } if (found) { if (i+1 < limit) { .bombs[i] = .bombs[i+1]; } else { .bombs[i] = null; } } } };
//------------------------------------ //------------------------------------ newPlayer.StartThread = function() { this:stateSet(.IdleState); };
//------------------------------------ //------------------------------------ newPlayer.IdleState = function() { while (!quit) { pressed = false; if (ISPRESSED(38)) { .Move(0, -1); pressed = true; } else if (ISPRESSED(40)) { .Move(0, 1); pressed = true; } else if (ISPRESSED(39)) { .Move(1, 0); pressed = true; } else if (ISPRESSED(37)) { .Move(-1, 0); pressed = true; } else if (ISPRESSED(' ')) { .DropBomb(); pressed = true; }
if (pressed) { sleep(0.075); } else if (.dead) { this:stateSet(.DeadState); } else { yield(); } } };
//------------------------------------ //------------------------------------ newPlayer.DeadState = function() { sleep(explodeTime); if (.lives > 0) { .lives = .lives - 1; } if (.maxBombs > 1) { .maxBombs = .maxBombs - 1; } if (.bombSize > 1) { .bombSize = .bombSize - 1; } .DrawStatus();
while (!quit) { if (.lives > 0 and ISPRESSED(' ')) { while (!quit) { pos = .GetStartPos(); thing = GetThingAt(pos.x, pos.y, false); if (thing.type == T_Enemy) { thing.thing.Kill(); } sleep(0.2);
oldX = .x; oldY = .y; .x = pos.x; .y = pos.y;
.dead = false; RefreshXY(oldX, oldY); RefreshXY(.x, .y); this:stateSet(.IdleState); } } yield(); } };
//------------------------------------ //------------------------------------ newPlayer.Overlap = PointOverlap;
//------------------------------------ //------------------------------------ newPlayer.Cheat = function() { .lives = 5; .maxBombs = 10; .bombSize = 5; .DrawStatus(); };
newPlayer.GetStartPos = function() { // Position near centre. ptx = grid.startX + (grid.rows/2)*grid.spaceX; pty = grid.startY + (grid.cols/2)*grid.spaceY; return table(x = ptx, y = pty); };
pos = newPlayer.GetStartPos(); newPlayer.x = pos.x; newPlayer.y = pos.y;
newPlayer.Start = function() { .threadId = this:thread(.StartThread); };
newPlayer.Stop = function() { threadKill(.threadId); };
return newPlayer; };
//-------------------------------------------------------------------------------------------------- // Bomb object. //-------------------------------------------------------------------------------------------------- global Bomb = function(a_x, a_y, a_size, a_fuse, a_owner) { newBomb = table(x = a_x, y = a_y, size = a_size, fuse = a_fuse, owner = a_owner); newBomb.explode = false; newBomb.expMinX = 0; newBomb.expMaxX = 0; newBomb.expMinY = 0; newBomb.expMaxY = 0; newBomb.visible = true; newBomb.threadId = -1;
newBomb.CountDown = function() { this:stateSet(.FuseState); };
newBomb.Explode = function() { this:stateSetOnThread(.threadId, .ExplodeState); };
newBomb.FuseState = function() { sleep(.fuse); this:stateSet(.ExplodeState); };
newBomb.ExplodeState = function() { .expMinX = ScreenClampX(.x - .size); .expMaxX = ScreenClampX(.x + .size); .expMinY = ScreenClampY(.y - .size); .expMaxY = ScreenClampY(.y + .size);
.explode = true; .visible = false; .KillStuff(); .visible = true; .Draw(); count = 1+g_count;
inc = explodeCycle/explodeTime; for (i = 0; i < explodeTime; i = i + inc) { sleep(explodeCycle); .Draw(); }
.visible = false; RefreshRect(.expMinX, .expMinY, .expMaxX - .expMinX + 1, .expMaxY - .expMinY + 1); if (.owner != null) { .owner.FreeBomb(this); } exit(); };
newBomb.KillStuff = function() { // Kill stuff. for (x = .x; x >= .expMinX; x=x-1) { if (!.TryKill(GetThingAt(x, .y, true))) { .expMinX = x; break; } } for (x = .x+1; x <= .expMaxX; x=x+1) { if (!.TryKill(GetThingAt(x, .y, true))) { .expMaxX = x; break; } }
for (y = .y; y >= .expMinY; y=y-1) { if (!.TryKill(GetThingAt(.x, y, true))) { .expMinY = y; break; } } for (y = .y+1; y <= .expMaxY; y=y+1) { if (!.TryKill(GetThingAt(.x, y, true))) { .expMaxY = y; break; } } };
newBomb.TryKill = function(a_thing) { if (a_thing.type == T_Block) { a_thing.thing.Kill(); return false; } else if (a_thing.type == T_Bomb and a_thing.thing != this) { a_thing.thing.Explode(); } else if (a_thing.type == T_Player or a_thing.type == T_Enemy) { a_thing.thing.Kill(); } return true; };
newBomb.Draw = function() { if (.visible) { if (.explode) { CATTRIB(bgColour | expColours[randint(0, expColourCount)]); for (x = .expMinX; x <= .expMaxX; x=x+1) { if (IsSpaceOnGrid(x, .y)) { XYTEXT(x, .y, expPix); } }
for (y = .expMinY; y <= .expMaxY; y=y+1) { if (IsSpaceOnGrid(.x, y)) { XYTEXT(.x, y, expPix); } } } else { CATTRIB(bgColour | bombColour); XYTEXT(.x, .y, bombPix); } } };
newBomb.Overlap = function(a_x1, a_y1, a_x2, a_y2) { if (.explode) { return OverlapRect(.expMinX, .y, .expMaxX, .y+1, a_x1, a_y1, a_x2, a_y2) and OverlapRect(.x, .expMinY, .x+1, .expMaxY, a_x1, a_y1, a_x2, a_y2); } return IsPointWithin(.x, .y, a_x1, a_y1, a_x2, a_y2); };
newBomb.FuseThread = function() { sleep(.fuse); .Explode(); };
newBomb.threadId = newBomb:thread(newBomb.CountDown); newBomb:thread(newBomb.FuseThread); return newBomb; };
//-------------------------------------------------------------------------------------------------- // Block code. //-------------------------------------------------------------------------------------------------- global Block = function(a_x, a_y) { newBlock = table(x = a_x, y = a_y, visible = true); newBlock.hits = 1;
newBlock.Draw = function() { if (.visible) { CATTRIB(bgColour | blockColour); if (.hits == 3) { XYTEXT(.x, .y, block3Pix); } else if (.hits == 2) { XYTEXT(.x, .y, block2Pix); } else { XYTEXT(.x, .y, block1Pix); } } };
newBlock.Overlap = PointOverlap;
newBlock.KillThread = function() { yield(); yield(); if (.visible) { .visible = false; player.AddScore(scoreBlock); if (randint(0, 100) < powerupChance) { AddPowerup(.x, .y); } } };
newBlock.Kill = function() { .hits = .hits - 1; if (.hits == 0) { this:thread(.KillThread); } RefreshXY(.x, .y); };
return newBlock; };
global CreateBlocks = function(a_num) { global maxBlockHits; global blocks = table(count = 0, blocks = array(a_num)); for (i = 0; i < a_num; i=i+1) { pos = GetRandomFreePos(DT_Block, true); if (pos.x != -1 and pos.y != -1) { thing = GetThingAt(pos.x, pos.y, false); if (thing.type == DT_Block) { if (thing.thing.hits < maxBlockHits) { thing.thing.hits = thing.thing.hits + 1; } } else { blocks.blocks[i] = Block(pos.x, pos.y); blocks.count = i; } } } blocks.count = a_num; };
//-------------------------------------------------------------------------------------------------- // Powerup. //-------------------------------------------------------------------------------------------------- global Powerup = function(a_x, a_y, a_type) { newPu = table(x = a_x, y = a_y, type = a_type);
if (a_type == PT_Bomb) { newPu.Draw = function() { CATTRIB(bgColour | powerupColour); XYTEXT(.x, .y, bombExtraPix); };
newPu.Pickup = function() { if (player.maxBombs < maxPlayerBombs) { player.maxBombs = player.maxBombs + 1; } player.DrawStatus(); RemovePowerup(this); }; } else if (a_type == PT_Size) { newPu.Draw = function() { CATTRIB(bgColour | powerupColour); XYTEXT(.x, .y, bombSizePix); };
newPu.Pickup = function() { if (player.bombSize < maxPlayerSize) { player.bombSize = player.bombSize + 1; } player.DrawStatus(); RemovePowerup(this); }; } else if (a_type == PT_Life) { newPu.Draw = function() { CATTRIB(bgColour | puLifeColour); XYTEXT(.x, .y, lifePix); };
newPu.Pickup = function() { if (player.lives < maxLives) { player.lives = player.lives + 1; } player.DrawStatus(); RemovePowerup(this); }; } else { newPu.Draw = function() { };
newPu.Pickup = function() { RemovePowerup(this); }; }
newPu.Overlap = PointOverlap;
return newPu; };
//-------------------------------------------------------------------------------------------------- // Powerup management. //-------------------------------------------------------------------------------------------------- global RandomPowerupType = function() { int = randint(0, 100);
if (int < 49) { return PT_Bomb; } if (int < 98) { return PT_Size; }
return PT_Life; };
global AddPowerup = function(a_x, a_y) { if (powerups.count < maxPowerups) { powerups.powerups[powerups.count] = Powerup(a_x, a_y, RandomPowerupType()); powerups.count = powerups.count + 1; RefreshXY(a_x, a_y); } };
global RemovePowerup = function(a_pu) { found = false; count = powerups.count; for (i = 0; i < count; i = i + 1) { if (powerups.powerups[i] == a_pu) { found = true; powerups.powerups[i] = null; powerups.count = powerups.count - 1; } if (found) { if (i+1 < count) { powerups.powerups[i] = powerups.powerups[i+1]; } else { powerups.powerups[i] = null; } } } };
global InitPowerups = function() { global powerups = table(count = 0, powerups = array(maxPowerups)); };
//-------------------------------------------------------------------------------------------------- // Enemies. //-------------------------------------------------------------------------------------------------- global CreateEnemies = function(a_num) { global enemies = table(count = 0, enemies = array(a_num));
for (i = 0; i < a_num; i=i+1) { pos = GetRandomFreePos(DT_Enemy, false); if (pos.x != -1 and pos.y != -1) { enemies.enemies[i] = Enemy(pos.x, pos.y); enemies.count = i+1; } } };
global Enemy = function(a_x, a_y) { newEnemy = table(x = a_x, y = a_y, dead = false); newEnemy.lastCanMoveThing = null; newEnemy.lastPos = table(x = a_x, y = a_y); newEnemy.threadId = -1;
//------------------------------------ //------------------------------------ newEnemy.Draw = function() { if (!.dead) { CATTRIB(bgColour | nmeColour); XYTEXT(.x, .y, nmePix); } };
//------------------------------------ //------------------------------------ newEnemy.Kill = function() { player.AddScore(scoreNME); .dead = true; if (randint(0, 100) < powerupChance) { AddPowerup(.x, .y); } RefreshXY(.x, .y); };
//------------------------------------ //------------------------------------ newEnemy.Overlap = PointOverlap;
//------------------------------------ // Movement. //------------------------------------ newEnemy.CanMove = function(a_x, a_y) { if (a_x < 0 or a_x >= screen.w or a_y < 0 or a_y > screen.h) { return false; }
thing = GetThingAt(a_x, a_y, false); .lastCanMoveThing = thing; return thing.type == T_Space or thing.type == T_Exlposion or thing.type == T_Powerup or thing.type == T_Player; };
//------------------------------------ //------------------------------------ newEnemy.MoveX = function() { // Is the player on the same column? if (.y == player.y) { // Are we within a grid spacing? if (player.x - .x <= grid.spaceX + 1) { if (.x < player.x) { start = .x+1; end = player.x+1; moveX = start; } else { start = player.x+1; end = .x; moveX = end-1; } // Do we have a clear path. moveOk = true; for (x = start; moveOk and x < end; x=x+1) { if (!.CanMove(x, .y)) { moveOk = false; } } if (moveOk and .CanMove(moveX, .y)) { .MoveTo(moveX, .y); return true; } } }
mx = 1; if (player.x < .x) { mx = -1; } if ((.x+mx != .lastPos.x or .y != .lastPos.y) and .CanMove(.x+mx, .y)) { .MoveTo(.x+mx, .y); return true; } return false; };
//------------------------------------ //------------------------------------ newEnemy.MoveY = function() { // Is the player on the same row? if (.x == player.x) { // Are we within a grid spacing? if (player.y - .y <= grid.spaceY + 1) { if (.y < player.y) { start = .y+1; end = player.y+1; moveY = start; } else { start = player.y+1; end = .y; moveY = end-1; } // Do we have a clear path. moveOk = true; for (y = start; moveOk and y < end; y=y+1) { if (!.CanMove(.x, y)) { moveOk = false; } } if (moveOk and .CanMove(.x, moveY)) { .MoveTo(.x, moveY); return true; } } }
my = 1; if (player.y < .y) { my = -1; } if ((.x != .lastPos.x or .y+my != .lastPos.y) and .CanMove(.x, .y+my)) { .MoveTo(.x, .y+my); return true; } return false; };
//------------------------------------ //------------------------------------ newEnemy.MoveTo = function(a_x, a_y) { .lastPos.x = .x; .lastPos.y = .y;
thing = GetThingAt(a_x, a_y, false);
.x = a_x; .y = a_y;
if (thing.type == T_Player) { player.Kill(); } else if (thing.type == T_Explosion) { .Kill(); }
RefreshXY(.lastPos.x, .lastPos.y); RefreshXY(.x, .y); };
//------------------------------------ //------------------------------------ newEnemy.Move = function() { moved = false; if (!player.dead) { // Try move towards the player. preferX = abs(player.x - .x) > abs(player.y - .y); if (preferX) { moved = .MoveX(); if (!moved) { moved = .MoveY(); } } else { moved = .MoveY(); if (!moved) { moved = .MoveX(); } }
// Try move away from the last position. if (!moved) { testX = 2*.x - .lastPos.x; testY = 2*.y - .lastPos.y; if (.CanMove(testX, testY)) { .MoveTo(testX, testY); moved = true; } } }
if (!moved and (.lastPos.x != .x or .lastPos.y != .y) and .CanMove(.lastPos.x, .lastPos.y)) { .MoveTo(.lastPos.x, .lastPos.y); } };
//------------------------------------ // Thread functions and states. //------------------------------------ newEnemy.Start = function() { .threadId = this:thread(.IdleState); };
//------------------------------------ //------------------------------------ newEnemy.IdleState = function() { while (!quit and !.dead) { sleep(nmeMoveTime); .Move(); } };
newEnemy.Start();
return newEnemy; };
//-------------------------------------------------------------------------------------------------- // Refresh functions. //-------------------------------------------------------------------------------------------------- global Refresh = function() { CATTRIB(bgColour | fgColour); CLS();
// Draw blocks. for (b = 0; b < blocks.count; b=b+1) { blocks.blocks[b].Draw(); }
// Draw powerups. for (p = 0; p < powerups.count; p=p+1) { powerups.powerups[p].Draw(); }
// Draw enemies. for (e = 0; e < enemies.count; e=e+1) { enemies.enemies[e].Draw(); }
// Draw bombs. for (b = 0; b < player.nextBomb; b=b+1) { player.bombs[b].Draw(); }
player.Draw(); player.DrawStatus();
DrawGrid(); };
global RefreshXY = function(a_x, a_y) { RefreshRect(a_x, a_y, 1, 1); };
global RefreshRect = function(a_x, a_y, a_w, a_h) { // Clear the area. xLimit = a_x + a_w; yLimit = a_y + a_h; CATTRIB(bgColour | fgColour); for (x = a_x; x < xLimit; x=x+1) { for (y = a_y; y < yLimit; y=y+1) { XYTEXT(x, y, spacePix); } }
// Draw blocks. for (b = 0; b < blocks.count; b=b+1) { blk = blocks.blocks[b]; if (blk.Overlap(a_x, a_y, xLimit, yLimit)) { blk.Draw(); } }
// Draw powerups. for (p = 0; p < powerups.count; p=p+1) { pu = powerups.powerups[p]; if (pu.Overlap(a_x, a_y, xLimit, yLimit)) { pu.Draw(); } }
// Draw enemies. for (e = 0; e < enemies.count; e=e+1) { nme = enemies.enemies[e]; if (nme.Overlap(a_x, a_y, xLimit, yLimit)) { nme.Draw(); } }
// Draw bombs. for (b = 0; b < player.nextBomb; b=b+1) { bomb = player.bombs[b]; if (bomb.Overlap(a_x, a_y, xLimit, yLimit)) { bomb.Draw(); } }
if (player.Overlap(a_x, a_y, xLimit, yLimit)) { player.Draw(); }
DrawGridRect(a_x, a_y, a_w, a_h); };
//-------------------------------------------------------------------------------------------------- // Grid control. //-------------------------------------------------------------------------------------------------- global Grid = function(a_startX, a_startY, a_spaceX, a_spaceY) { grid.startX = a_startX; grid.startY = a_startY; grid.spaceX = a_spaceX; grid.spaceY = a_spaceY;
grid.rows = (screen.w-grid.startX) / (grid.spaceX + 1); grid.cols = (screen.h-grid.startY) / (grid.spaceY + 1);
if ((screen.w-grid.startX) % (grid.spaceX + 1) != 0) { grid.rows = grid.rows + 1; }
if ((screen.h-grid.startY) % (grid.spaceY + 1) != 0) { grid.cols = grid.cols + 1; } };
global DrawGrid = function() { DrawGridRect(0, 0, screen.w, screen.h); };
global DrawGridRect = function(a_startX, a_startY, a_w, a_h) { xLimit = a_startX + a_w; yLimit = a_startY + a_h; CATTRIB(bgColour | gridColour); for (x = a_startX; x < xLimit; x=x+1) { for (y = a_startY; y < yLimit; y=y+1) { if (!IsSpaceOnGrid(x, y)) { XYTEXT(x, y, gridPix); } } } };
global IsSpaceOnGrid = function(a_x, a_y) { return (a_x - grid.startX) % (grid.spaceX+1) == 0 or (a_y - grid.startY) % (grid.spaceY+1) == 0; };
global IsFreePos = function(a_x, a_y, a_allowBlocks) { thing = GetThingAt(a_x, a_y, true); return thing.type == T_Space or (a_allowBlocks and thing.type == T_Block); };
global GetThingAt = function(a_x, a_y, a_ignoreExplosion) { if (!IsSpaceOnGrid(a_x, a_y)) { return table(thing = grid, type = T_Grid); }
// Test blocks for (b = 0; b < blocks.count; b=b+1) { blk = blocks.blocks[b]; if (blk.visible and blk.x == a_x and blk.y == a_y) { return table(thing = blk, type = T_Block); } }
// Test enemies. for (e = 0; e < enemies.count; e=e+1) { nme = enemies.enemies[e]; if (!nme.dead and nme.x == a_x and nme.y == a_y) { return table(thing = nme, type = T_Enemy); } }
// Test player pos. if (!player.dead and a_x == player.x and a_y == player.y) { return table(thing = player, type = T_Player); }
// Test bombs. for (b = 0; b < player.nextBomb; b=b+1) { bomb = player.bombs[b]; if (!bomb.explode) { if (bomb.x == a_x and bomb.y == a_y) { return table(thing = bomb, type = T_Bomb); } } else if (!a_ignoreExplosion and bomb.Overlap(a_x, a_y, a_x+1, a_y+1)) { return table(thing = bomb, type = T_Explosion); } }
// Test powerups. for (p = 0; p < powerups.count; p=p+1) { pu = powerups.powerups[p]; if (pu.x == a_x and pu.y == a_y) { return table(thing = pu, type = T_Powerup); } }
return table(thing = null, type = T_Space); };
global InDeadZone = function(a_dtType, a_x, a_y) { if (a_dtType == DT_Block) { return IsPointWithin(a_x, a_y, blockDeadZone.x1, blockDeadZone.y1, blockDeadZone.x2, blockDeadZone.y2); } if (a_dtType == DT_Enemy) { return IsPointWithin(a_x, a_y, enemyDeadZone.x1, enemyDeadZone.y1, enemyDeadZone.x2, enemyDeadZone.y2); } return false; };
global GetRandomFreePos1 = function(a_deadZoneType, a_allowBlocks, a_tries) { row = randint(0, grid.rows); col = randint(0, grid.cols);
px = row*grid.spaceX + grid.startX; py = col*grid.spaceY + grid.startY;
if (a_deadZoneType != DT_None and InDeadZone(a_deadZoneType, px, py)) { return GetRandomFreePos1(a_deadZoneType, a_tries); }
if (IsFreePos(px, py)) { return table(x = px, y = py); }
while (py < screen.h) { py=py+1; if ((a_deadZoneType == DT_None or !InDeadZone(a_deadZoneType, px, py)) and IsFreePos(px, py)) { return table(x = px, y = py); } }
if (tries < 5) { return GetRandomFreePos1(a_tries+1); } return table(x = -1, y = -1); };
global GetRandomFreePos = function(a_deadZoneType, a_allowBlocks) { return GetRandomFreePos1(a_deadZoneType, a_allowBlocks, 0); };
//-------------------------------------------------------------------------------------------------- // Initialisation. //-------------------------------------------------------------------------------------------------- RenderRect = function(a_rect) { CATTRIB(bgColour | gridColour); for (i = a_rect.x1; i <= a_rect.x2; i=i+1) { for (j = a_rect.y1; j <= a_rect.y2; j=j+1) { XYTEXT(i, j, "o"); } } };
MemThread = function() { while (!quit) { CATTRIB(bgColour | statusColour); XYTEXT(65, statusY, format("Mem: %d ", sysGetMemoryUsage())); sleep(1.0); } };
//-------------------------------------------------------------------------------------------------- // Level thread. //-------------------------------------------------------------------------------------------------- global GameOver = function() { CATTRIB(bgColour | statusColour); CLS();
local score = player.score; KillAll();
sleep(0.3);
global quit; while (!quit) { CATTRIB(bgColour | expColours[randint(0, expColourCount)]); x = 8; y = 8; XYTEXT(x, y, "__________________________________________________________"); y=y+1; XYTEXT(x, y, " __ __ "); y=y+1; XYTEXT(x, y, " / ) / ) "); y=y+1; XYTEXT(x, y, " / __ _ _ __ / / __ )__ "); y=y+1; XYTEXT(x, y, " / --, / ) / / ) /___) / / | / /___) / )"); y=y+1; XYTEXT(x, y, "_(____/___(___(_/_/__/_(___ ____(____/____|/__(___ _/_____"); y=y+1;
CATTRIB(bgColour | statusColour); XYTEXT(0, statusY, format("Score : %d", score));
if (threadTime() < 1000 and ISPRESSED(' ')) { stateSet(TitleScreenState); } else if (ISPRESSED(27)) { quit = true; }
sleep(randfloat(0.03, 0.3)); }
global player = null; global blocks = null; global enemies = null;
stateSet(TitleScreenState); };
global GameState = function() { global maxLevel; global player; global blocks; global enemies; global gameLevel; Grid(3, 2, 5, 5); if (player == null or player.lives <= 0) { player = Player(); } pos = player.GetStartPos(); player.x = pos.x; player.y = pos.y;
global nmeMoveTime = 1.0 - gameLevel*0.1;
InitPowerups(); CreateBlocks(min(10 + 10*gameLevel, 99)); CreateEnemies(5*gameLevel); yield(); Refresh();
yield(); player.Start();
local done = false; while (!quit and !done) { local count;
done = true; if (ISPRESSED(27)) { global quit = true; break; } /* // Check blocks. count = blocks.count; for (i = 0; done and i < count; i=i+1) { blk = blocks.blocks[i]; if (blk.visible) { done = false; } } */ // Check enemies. count = enemies.count; for (i = 0; done and i < count; i=i+1) { nme = enemies.enemies[i]; if (!nme.dead) { done = false; } }
// Check bombs. done = done and player.nextBomb == 0;
// Check for lives. done = done or player.lives <= 0;
sleep(0.3); }
player.Stop();
if (!quit) { if (player.lives <= 0) { stateSet(GameOver); } global gameLevel; gameLevel=gameLevel+1; stateSet(LevelState); }
KillAll(); };
global LevelState = function() { global maxLevel; global gameLevel;
if (gameLevel > maxLevel) { gameLevel = maxLevel; }
CATTRIB(bgColour | statusColour); CLS();
sleep(0.3);
global quit; while (!quit) { CATTRIB(bgColour | expColours[randint(0, expColourCount)]); x = 17; y = 8; XYTEXT(x, y, "___________________________________________"); y=y+1; XYTEXT(x, y, " ____ ___ "); y=y+1; XYTEXT(x, y, " / ) / ( ) "); y=y+1; XYTEXT(x, y, " /___ / __ __ __ / / "); y=y+1; XYTEXT(x, y, " / | /___) / ) / / / / / "); y=y+1; XYTEXT(x, y, "_/_____|__(___ _(___(_(___/___(___/__o_____"); y=y+1; XYTEXT(x, y, " / "); y=y+1; XYTEXT(x, y, " (_ / "); y=y+1;
if (threadTime() > 1000 and ISPRESSED(' ')) { CLS(); sleep(0.5); stateSet(GameState); } else if (ISPRESSED(27)) { quit = true; }
sleep(randfloat(0.03, 0.3)); }
KillAll(); };
global KillAll = function() { // Kill all threads. global player; global enemies; global blocks;
if (player) { local count = player.nextBomb; for (i = 0; i < count; i=i+1) { threadKill(player.bombs[i].threadId); } threadKill(player.threadId); }
if (enemies) { count = enemies.count; for (i = 0; i < count; i=i+1) { threadKill(enemies.enemies[i].threadId); } } };
global TitleScreenState = function() { CATTRIB(bgColour | statusColour); CLS(); sleep(0.3); while (!quit) { CATTRIB(bgColour | expColours[randint(0, expColourCount)]); x = 17; y = 8; XYTEXT(x, y, "_________________________________________"); y=y+1; XYTEXT(x, y, " ____ "); y=y+1; XYTEXT(x, y, " / ) / "); y=y+1; XYTEXT(x, y, " /__ / __ _ _ /__ __ )__ "); y=y+1; XYTEXT(x, y, " / ) / ) / / ) / ) /___) / )"); y=y+1; XYTEXT(x, y, "_/____/___(___/_/_/__/_(___/_(___ _/_____"); y=y+1; XYTEXT(x, y, "_________________________________________"); y=y+1;
if (ISPRESSED(27)) { global quit = true; break; } else if (ISPRESSED(' ')) { global gameLevel = 1; stateSet(LevelState); } sleep(randfloat(0.03, 0.3)); }
KillAll(); exit(); };
CURSOR(0, 0); // bool visible, percentage visible CATTRIB(fgColour | bgColour);
thread(MemThread);
quit = false; CLS();
stateSet(TitleScreenState);
|