Commit 105d65c6 authored by alistert's avatar alistert

Bonus levels are now "3D", and have working collision.

parent e1248b96
......@@ -41,13 +41,15 @@
#include <math.h>
#include <string.h>
#define PI 3.141592f
int Bonus::loadTiles (char *fileName) {
File *file;
unsigned char *pixels;
unsigned char *sorted;
int count;
int count, x, y;
try {
......@@ -74,7 +76,28 @@ int Bonus::loadTiles (char *fileName) {
file->loadPalette(palette);
// Load tile graphics
tileSet = file->loadSurface(32, 32 * 60);
pixels = file->loadRLE(1024 * 60);
tileSet = createSurface(pixels, 32, 32 * 60);
// Create mask
for (count = 0; count < 60; count++) {
memset(mask[count], 0, 64);
for (y = 0; y < 32; y++) {
for (x = 0; x < 32; x++) {
if ((pixels[(count << 10) + (y << 5) + x] & 240) == 192)
mask[count][((y << 1) & 56) + ((x >> 2) & 7)] = 1;
}
}
}
delete[] pixels;
delete file;
......@@ -130,9 +153,9 @@ Bonus::Bonus (char * fileName, unsigned char diff) {
for (x = 0; x < BLW; x++) {
tiles[y][x] = buffer[x + (y * BLW)];
grid[y][x].tile = buffer[x + (y * BLW)];
if (tiles[y][x] > 59) tiles[y][x] = 59;
if (grid[y][x].tile > 59) grid[y][x].tile = 59;
}
......@@ -152,7 +175,7 @@ Bonus::Bonus (char * fileName, unsigned char diff) {
for (x = 0; x < BLH; x++) {
events[y][x] = buffer[x + (y * BLW)];
grid[y][x].event = buffer[x + (y * BLW)];
}
......@@ -206,7 +229,7 @@ Bonus::Bonus (char * fileName, unsigned char diff) {
paletteEffects = new RotatePaletteEffect(192, 16, F32, paletteEffects);
// Bouncy things
paletteEffects = new RotatePaletteEffect(240, 16, -F32, paletteEffects);
paletteEffects = new RotatePaletteEffect(240, 16, F32, paletteEffects);
// Adjust fontsFont to use bonus level palette
......@@ -237,6 +260,29 @@ Bonus::~Bonus () {
}
bool Bonus::isEvent (fixed x, fixed y) {
return ((x & 32767) > F12) && ((x & 32767) < F20) &&
((y & 32767) > F12) && ((y & 32767) < F20);
}
bool Bonus::checkMask (fixed x, fixed y) {
BonusGridElement *ge;
ge = grid[FTOT(y) & 255] + (FTOT(x) & 255);
// Hand
if ((ge->event == 3) && isEvent(x, y)) return true;
// Check the mask in the tile in question
return mask[ge->tile][((y >> 9) & 56) + ((x >> 12) & 7)];
}
int Bonus::step () {
fixed playerX, playerY;
......@@ -260,33 +306,29 @@ int Bonus::step () {
// Process players
for (count = 0; count < nPlayers; count++) {
players[count].bonusStep(ticks, msps);
playerX = players[count].getX();
playerY = players[count].getY();
gridX = FTOT(playerX);
gridY = FTOT(playerY);
players[count].bonusStep(ticks, msps, this);
if ((playerX > TTOF(gridX) + F12) && (playerX < TTOF(gridX) + F20) &&
(playerY > TTOF(gridY) + F12) && (playerY < TTOF(gridY) + F20)) {
if (isEvent(playerX, playerY)) {
while (gridX < 0) gridX += BLW;
while (gridY < 0) gridY += BLH;
gridX = FTOT(playerX) & 255;
gridY = FTOT(playerY) & 255;
switch (events[gridY][gridX]) {
switch (grid[gridY][gridX].event) {
case 1: // Extra time
addTimer();
events[gridY][gridX] = 0;
grid[gridY][gridX].event = 0;
break;
case 2: // Gem
players[count].addItem();
events[gridY][gridX] = 0;
grid[gridY][gridX].event = 0;
if (players[count].getItems() >= items) {
......@@ -298,12 +340,6 @@ int Bonus::step () {
break;
case 3: // Hand
players[count].setSpeed(0, 0);
break;
case 4: // Exit
return LOST;
......@@ -320,6 +356,8 @@ int Bonus::step () {
}
direction = localPlayer->getDirection();
return E_NONE;
}
......@@ -327,96 +365,130 @@ int Bonus::step () {
void Bonus::draw () {
SDL_Rect src, dst;
SDL_Rect dst;
fixed playerX, playerY, playerSin, playerCos;
fixed distance, opposite, adjacent;
int levelX, levelY;
int spriteW, spriteH;
int x, y;
// Draw the background
for (x = -(localPlayer->getDirection() & 1023); x < canvasW; x += background->w) {
dst.x = x;
dst.y = (canvasH >> 1) - 4;
SDL_BlitSurface(background, NULL, canvas, &dst);
}
x = 171;
for (y = (canvasH >> 1) - 5; (y >= 0) && (x > 128); y--) drawRect(0, y, canvasW, 1, x--);
if (y > 0) drawRect(0, 0, canvasW, y + 1, 128);
// Draw the ground
src.x = 0;
src.w = 32;
src.h = 32;
playerX = localPlayer->getX();
playerY = localPlayer->getY();
playerSin = fixed(1024.0f * sinf(PI * float(direction) / 512.0f));
playerCos = fixed(1024.0f * cosf(PI * float(direction) / 512.0f));
int vX = FTOI(localPlayer->getX()) - (canvasW >> 1);
int vY = FTOI(localPlayer->getY()) - (canvasH >> 2);
if (SDL_MUSTLOCK(canvas)) SDL_LockSurface(canvas);
for (y = 0; y <= ITOT((canvasH >> 1) - 1) + 1; y++) {
for (y = 1; y <= (canvasH >> 1) - 15; y++) {
for (x = 0; x <= ITOT(canvasW - 1) + 1; x++) {
distance = fixed(1024.0f * tanf((float(y) / float(canvasH >> 1)) + ((PI / 2.0f) - 1.0f)) * 20.0f);
opposite = MUL(distance, playerSin);
adjacent = MUL(distance, playerCos);
src.y = TTOI(tiles[(y + ITOT(vY) + BLH) % BLH][(x + ITOT(vX) + BLW) % BLW]);
dst.x = TTOI(x) - (vX & 31);
dst.y = (canvasH >> 1) + TTOI(y) - (vY & 31);
for (x = 0; x < canvasW; x++) {
SDL_BlitSurface(tileSet, &src, canvas, &dst);
fixed nX = ITOF(x - (canvasW >> 1)) / canvasW;
dst.x = 12 + TTOI(x) - (vX & 31);
dst.y = (canvasH >> 1) + 12 + TTOI(y) - (vY & 31);
levelX = FTOI(playerX + opposite + MUL(nX, adjacent));
levelY = FTOI(playerY - adjacent + MUL(nX, opposite));
switch (events[(y + ITOT(vY) + BLH) % BLH][(x + ITOT(vX) + BLW) % BLW]) {
((unsigned char *)(canvas->pixels))[(canvas->pitch * (canvasH - y)) + x] =
((unsigned char *)(tileSet->pixels))
[(grid[ITOT(levelY) & 255][ITOT(levelX) & 255].tile * 1024) +
((levelY & 31) * tileSet->pitch) + (levelX & 31)];
case 0: // No event
}
break;
}
case 1: // Extra time
if (SDL_MUSTLOCK(canvas)) SDL_UnlockSurface(canvas);
drawRect(dst.x, dst.y, 8, 8, 60);
break;
// Draw the events
case 2: // Gem
for (y = -7; y < 8; y++) {
drawRect(dst.x, dst.y, 8, 8, 67);
fixed sY = TTOF(y) + F16 - (playerY & 32767);
break;
for (x = -7; x < 8; x++) {
case 3: // Hand
fixed sX = TTOF(x) + F16 - (playerX & 32767);
drawRect(dst.x, dst.y, 8, 8, 15);
fixed divisor = MUL(sX, playerSin) - MUL(sY, playerCos);
break;
if (FTOI(divisor) > 0) {
case 4: // Exit
spriteW = 1000 / FTOI(divisor);
spriteH = 1000 / FTOI(divisor);
drawRect(dst.x, dst.y, 8, 8, 45);
fixed nX = DIV(MUL(sX, playerCos) + MUL(sY, playerSin), divisor);
break;
dst.x = FTOI(nX * canvasW) + ((canvasW - spriteW) >> 1);
dst.y = (canvasH - spriteH) >> 1;
default:
switch (grid[(y + FTOT(playerY)) & 255][(x + FTOT(playerX)) & 255].event) {
drawRect(dst.x, dst.y, 8, 8, 0);
case 0: // No event
break;
break;
}
case 1: // Extra time
}
drawRect(dst.x, dst.y, spriteW, spriteH, 60);
}
break;
case 2: // Gem
// Draw the background
drawRect(dst.x, dst.y, spriteW, spriteH, 67);
for (x = -(localPlayer->getDirection() & 1023); x < canvasW; x += background->w) {
break;
dst.x = x;
dst.y = (canvasH >> 1) - 4;
SDL_BlitSurface(background, NULL, canvas, &dst);
case 3: // Hand
}
drawRect(dst.x, dst.y, spriteW, spriteH, 15);
x = 171;
break;
for (y = (canvasH >> 1) - 5; (y >= 0) && (x > 128); y--) drawRect(0, y, canvasW, 1, x--);
case 4: // Exit
if (y > 0) drawRect(0, 0, canvasW, y + 1, 128);
drawRect(dst.x, dst.y, spriteW, spriteH, 45);
break;
// Draw the "player"
drawRect(
(canvasW >> 1) + fixed(sin(localPlayer->getDirection() * 6.283185 / 1024.0) * 3) - 4,
((canvasH * 3) >> 2) - fixed(cos(localPlayer->getDirection() * 6.283185 / 1024.0) * 3) - 4, 8, 8, 0);
drawRect((canvasW >> 1) - 4, ((canvasH * 3) >> 2) - 4, 8, 8, 22);
default:
drawRect(dst.x, dst.y, spriteW, spriteH, 0);
break;
}
}
}
}
// Show gem count
......@@ -562,6 +634,8 @@ int Bonus::play () {
// Draw the graphics
if (ticks < returnTime) direction += (ticks - prevTicks) * T_BONUS_END / (returnTime - ticks);
draw();
......
......@@ -34,7 +34,17 @@
#define BLW 256 /* Bonus level width */
#define BLH 256 /* Bonus level height */
#define T_BONUS_END 1500
#define T_BONUS_END 2000
// Datatype
typedef struct {
unsigned char tile; // Indexes the tile set
unsigned char event;
} BonusGridElement;
// Class
......@@ -42,19 +52,22 @@
class Bonus : public BaseLevel {
private:
SDL_Surface *background;
unsigned char tiles[BLH][BLW];
unsigned char events[BLH][BLW];
SDL_Surface* background;
BonusGridElement grid[BLH][BLW];
char mask[60][64]; // At most 60 tiles, all with 8 * 8 masks
fixed direction;
int loadTiles (char *fileName);
int step ();
void draw ();
int loadTiles (char* fileName);
bool isEvent (fixed x, fixed y);
int step ();
void draw ();
public:
Bonus (char * fileName, unsigned char diff);
~Bonus ();
int play ();
Bonus (char* fileName, unsigned char diff);
~Bonus ();
bool checkMask (fixed x, fixed y);
int play ();
};
......
......@@ -165,6 +165,8 @@ Font::Font (unsigned char* pixels, bool big) {
characters[count] = createSurface(chrPixels, 8, lineHeight);
if (big) SDL_SetColorKey(characters[count], SDL_SRCCOLORKEY, 0);
}
nCharacters= 40;
......
......@@ -268,7 +268,7 @@ Bullet* Bullet::step (unsigned int ticks, int msps) {
set = level->getBullet(type);
// If the scenery has been hit and this is not a bouncer, destroy the bullet
if (level->checkMask(x, y) && (set[B_BEHAVIOUR] != 4)) {
if (level->checkMaskUp(x, y) && (set[B_BEHAVIOUR] != 4)) {
level->playSound(set[B_FINISHSOUND]);
......
......@@ -123,17 +123,21 @@ Level::~Level () {
}
bool Level::checkMask (fixed x, fixed y) {
bool Level::checkMaskUp (fixed x, fixed y) {
GridElement *ge;
// Anything off the edge of the map is solid
if ((x < 0) || (y < 0) || (x > TTOF(LW)) || (y > TTOF(LH)))
return true;
ge = grid[FTOT(y)] + FTOT(x);
// Event 122 is one-way
if (grid[FTOT(y)][FTOT(x)].event == 122) return false;
if (ge->event == 122) return false;
// Check the mask in the tile in question
return mask[grid[FTOT(y)][FTOT(x)].tile][((y >> 9) & 56) + ((x >> 12) & 7)];
return mask[ge->tile][((y >> 9) & 56) + ((x >> 12) & 7)];
}
......@@ -152,15 +156,19 @@ bool Level::checkMaskDown (fixed x, fixed y) {
bool Level::checkSpikes (fixed x, fixed y) {
GridElement *ge;
// Anything off the edge of the map is not spikes
// Ignore the bottom, as it is deadly anyway
if ((x < 0) || (y < 0) || (x > TTOF(LW))) return false;
ge = grid[FTOT(y)] + FTOT(x);
// Event 126 is spikes
if (grid[FTOT(y)][FTOT(x)].event != 126) return false;
if (ge->event != 126) return false;
// Check the mask in the tile in question
return mask[grid[FTOT(y)][FTOT(x)].tile][((y >> 9) & 56) + ((x >> 12) & 7)];
return mask[ge->tile][((y >> 9) & 56) + ((x >> 12) & 7)];
}
......
......@@ -68,8 +68,7 @@ typedef struct {
unsigned char bg; // 0 = Effect background, 1 = Black background
unsigned char event; // Indexes the event set
unsigned char hits; // Number of times the event has been shot
int time; /* Point at which the event will do something, e.g.
terminate */
int time; /* Point at which the event will do something, e.g. terminate */
} GridElement;
......@@ -131,8 +130,8 @@ class Level : public BaseLevel {
Level (char* fileName, unsigned char diff, bool checkpoint);
virtual ~Level ();
bool checkMask (fixed x, fixed y);
bool checkMaskDown (fixed x, fixed y);
bool checkMaskUp (fixed x, fixed y);
bool checkMaskDown (fixed x, fixed y);
bool checkSpikes (fixed x, fixed y);
void setNext (int nextLevel, int nextWorld);
void setTile (unsigned char gridX, unsigned char gridY, unsigned char tile);
......
......@@ -161,13 +161,14 @@ enum PlayerReaction {
// Classes
class Anim;
class Bird;
class Bird;
class Bonus;
class Player : public Movable {
private:
Bird *bird;
char *name;
Bird* bird;
char* name;
char anims[PANIMS];
bool pcontrols[PCONTROLS];
SDL_Color palette[256];
......@@ -206,19 +207,19 @@ class Player : public Movable {
Player ();
~Player ();
void init (char *playerName, unsigned char *cols, unsigned char newTeam);
void init (char* playerName, unsigned char* cols, unsigned char newTeam);
void deinit ();
void setAnims (char *newAnims);
char * getName ();
unsigned char * getCols ();
void setAnims (char* newAnims);
char* getName ();
unsigned char* getCols ();
void reset ();
void setControl (int control, bool state);
bool takeEvent (unsigned char gridX, unsigned char gridY, unsigned int ticks);
bool touchEvent (unsigned char gridX, unsigned char gridY, unsigned int ticks, int msps);
void setEvent (unsigned char gridX, unsigned char gridY);
void clearEvent (unsigned char gridX, unsigned char gridY);
bool hit (Player *source, unsigned int ticks);
void kill (Player *source, unsigned int ticks);
bool hit (Player* source, unsigned int ticks);
void kill (Player* source, unsigned int ticks);
void addItem ();
void addLife ();
void addScore (int addedScore);
......@@ -232,14 +233,14 @@ class Player : public Movable {
void setPosition (fixed newX, fixed newY);
void setSpeed (fixed newDx, fixed newDy);
bool getFacing ();
fixed getDirection ();
Anim * getAnim ();
fixed getDirection ();
Anim* getAnim ();
unsigned char getTeam ();
void send (unsigned char *data);
void receive (unsigned char *buffer);
void send (unsigned char* data);
void receive (unsigned char* buffer);
void control (unsigned int ticks, int msps);
void move (unsigned int ticks, int msps);
void bonusStep (unsigned int ticks, int msps);
void bonusStep (unsigned int ticks, int msps, Bonus* bonus);
void view (unsigned int ticks, int mspf);
void draw (unsigned int ticks, int change);
PlayerReaction reacted (unsigned int ticks);
......@@ -249,13 +250,13 @@ class Player : public Movable {
// Variables
EXTERN Player *players;
EXTERN Player *localPlayer;
EXTERN Player* players;
EXTERN Player* localPlayer;
EXTERN int nPlayers;
// Configuration data
EXTERN char *characterName;
EXTERN unsigned char characterCols[4];
EXTERN char* characterName;
EXTERN unsigned char characterCols[4];
#endif
......@@ -28,6 +28,7 @@
#include "bird.h"
#include "player.h"
#include "bonus/bonus.h"
#include "game/gamemode.h"
#include "io/controls.h"
#include "io/gfx/font.h"
......@@ -179,7 +180,7 @@ void Player::control (unsigned int ticks, int msps) {
// Prepare to jump upon leaving the water
if (!level->checkMask(x + PXO_MID, y - F36)) {
if (!level->checkMaskUp(x + PXO_MID, y - F36)) {
jumpY = y - jumpHeight;
......@@ -213,7 +214,7 @@ void Player::control (unsigned int ticks, int msps) {
} else {
if (platform && pcontrols[C_JUMP] &&
!level->checkMask(x + PXO_MID, y - F36)) {
!level->checkMaskUp(x + PXO_MID, y - F36)) {
// Jump
......@@ -281,7 +282,7 @@ void Player::control (unsigned int ticks, int msps) {
// If there is an obstacle above and the player is not floating up, stop
// rising
if (level->checkMask(x + PXO_MID, y + PYO_TOP - F4) && (jumpY < y) && (event != 2)) {
if (level->checkMaskUp(x + PXO_MID, y + PYO_TOP - F4) && (jumpY < y) && (event != 2)) {
jumpY = TTOF(LH);
if (dy < 0) dy = 0;
......@@ -452,7 +453,7 @@ void Player::move (unsigned int ticks, int msps) {
while (count > 0) {
if (level->checkMask(x + PXO_MID, y + PYO_TOP - F4)) {
if (level->checkMaskUp(x + PXO_MID, y + PYO_TOP - F4)) {
y &= ~4095;
dy = 0;
......@@ -468,7 +469,7 @@ void Player::move (unsigned int ticks, int msps) {
pdy = (-pdy) & 4095;
if (!level->checkMask(x + PXO_MID, y + PYO_TOP - pdy))
if (!level->checkMaskUp(x + PXO_MID, y + PYO_TOP - pdy))
y -= pdy;
else {
......@@ -529,7 +530,7 @@ void Player::move (unsigned int ticks, int msps) {
while (count > 0) {
// If there is an obstacle, stop
if (level->checkMask(x + PXO_L - F4, y + PYO_MID)) {
if (level->checkMaskUp(x + PXO_L - F4, y + PYO_MID)) {
x &= ~4095;
......@@ -541,19 +542,19 @@ void Player::move (unsigned int ticks, int msps) {
count--;
// If on an uphill slope, push the player upwards
if (level->checkMask(x + PXO_ML, y) &&
!level->checkMask(x + PXO_ML, y - F4)) y -= F4;
if (level->checkMaskUp(x + PXO_ML, y) &&
!level->checkMaskUp(x + PXO_ML, y - F4)) y -= F4;
}
pdx = (-pdx) & 4095;
if (!level->checkMask(x + PXO_L - pdx, y + PYO_MID)) x -= pdx;
if (!level->checkMaskUp(x + PXO_L - pdx, y + PYO_MID)) x -= pdx;
else x &= ~4095;
// If on an uphill slope, push the player upwards
while (level->checkMask(x + PXO_ML, y) &&
!level->checkMask(x + PXO_ML, y - F4)) y -= F1;
while (level->checkMaskUp(x + PXO_ML, y) &&
!level->checkMaskUp(x + PXO_ML, y - F4)) y -= F1;
} else if (pdx > 0) {
......@@ -564,7 +565,7 @@ void Player::move (unsigned int ticks, int msps) {
while (count > 0) {
// If there is an obstacle, stop
if (level->checkMask(x + PXO_R + F4, y + PYO_MID)) {
if (level->checkMaskUp(x + PXO_R + F4, y + PYO_MID)) {
x |= 4095;
......@@ -576,25 +577,25 @@ void Player::move (unsigned int ticks, int msps) {
count--;
// If on an uphill slope, push the player upwards
if (level->checkMask(x + PXO_MR, y) &&
!level->checkMask(x + PXO_MR, y - F4)) y -= F4;
if (level->checkMaskUp(x + PXO_MR, y) &&
!level->checkMaskUp(x + PXO_MR, y - F4)) y -= F4;
}
pdx &= 4095;
if (!level->checkMask(x + PXO_R + pdx, y + PYO_MID)) x += pdx;
if (!level->checkMaskUp(x + PXO_R + pdx, y + PYO_MID)) x += pdx;
else x |= 4095;
// If on an uphill slope, push the player upwards
while (level->checkMask(x + PXO_MR, y) &&
!level->checkMask(x + PXO_MR, y - F4)) y -= F1;
while (level->checkMaskUp(x + PXO_MR, y) &&
!level->checkMaskUp(x + PXO_MR, y - F4)) y -= F1;
}
// If using a float up event and have hit a ceiling, ignore event
if ((event == 2) && level->checkMask(x + PXO_MID, y + PYO_TOP - F4)) {
if ((event == 2) && level->checkMaskUp(x + PXO_MID, y + PYO_TOP - F4)) {
jumpY = TTOF(LH);
event = 0;
......@@ -621,7 +622,9 @@ void Player::move (unsigned int ticks, int msps) {
}
void Player::bonusStep (unsigned int ticks, int msps) {
void Player::bonusStep (unsigned int ticks, int msps, Bonus* bonus) {
fixed cdx, cdy;
// Bonus stages use polar coordinates for movement (but not position)
// Treat dx as change in radius
......@@ -664,14 +667,17 @@ void Player::bonusStep (unsigned int ticks, int msps) {
}
if (pcontrols[C_LEFT]) direction -= msps >> 1;
if (pcontrols[C_LEFT]) direction -= msps >> 2;
if (pcontrols[C_RIGHT]) direction += msps >> 1;
if (pcontrols[C_RIGHT]) direction += msps >> 2;
// Apply trajectory
x += fixed(sin(direction * 6.283185 / 1024.0) * dx * msps) >> 10;
y -= fixed(cos(direction * 6.283185 / 1024.0) * dx * msps) >> 10;
cdx = fixed(sin(direction * 6.283185f / 1024.0f) * dx * msps) >> 10;
cdy = fixed(-cos(direction * 6.283185f / 1024.0f) * dx * msps) >> 10;
if (!bonus->checkMask(x + cdx, y)) x += cdx;
if (!bonus->checkMask(x, y + cdy)) y += cdy;
return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment