|
|
// |
|
|
// 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);
|
|
|
|