Commit bee8896d authored by alistert's avatar alistert

Event refactoring, incorporating various bug fixes.

parent 806e2402
...@@ -13,7 +13,7 @@ objects = src/bonus/bonus.o \ ...@@ -13,7 +13,7 @@ objects = src/bonus/bonus.o \
src/jj2level/jj2layer.o src/jj2level/jj2level.o \ src/jj2level/jj2layer.o src/jj2level/jj2level.o \
src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \ src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \
src/level/event/bridge.o src/level/event/guardians.o \ src/level/event/bridge.o src/level/event/guardians.o \
src/level/event/event.o src/level/event/eventframe.o \ src/level/event/event.o src/level/event/standardevent.o \
src/level/bullet.o src/level/demolevel.o src/level/level.o \ src/level/bullet.o src/level/demolevel.o src/level/level.o \
src/level/levelframe.o src/level/levelload.o src/level/movable.o \ src/level/levelframe.o src/level/levelload.o src/level/movable.o \
src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \ src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \
......
...@@ -56,7 +56,7 @@ OBJS = src/bonus/bonus.o \ ...@@ -56,7 +56,7 @@ OBJS = src/bonus/bonus.o \
src/jj2level/jj2layer.o src/jj2level/jj2level.o \ src/jj2level/jj2layer.o src/jj2level/jj2level.o \
src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \ src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \
src/level/event/bridge.o src/level/event/guardians.o \ src/level/event/bridge.o src/level/event/guardians.o \
src/level/event/event.o src/level/event/eventframe.o \ src/level/event/event.o src/level/event/standardevent.o \
src/level/bullet.o src/level/demolevel.o src/level/level.o \ src/level/bullet.o src/level/demolevel.o src/level/level.o \
src/level/levelframe.o src/level/levelload.o src/level/movable.o \ src/level/levelframe.o src/level/levelload.o src/level/movable.o \
src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \ src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \
......
...@@ -13,7 +13,7 @@ objects = src/bonus/bonus.o \ ...@@ -13,7 +13,7 @@ objects = src/bonus/bonus.o \
src/jj2level/jj2layer.o src/jj2level/jj2level.o \ src/jj2level/jj2layer.o src/jj2level/jj2level.o \
src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \ src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \
src/level/event/bridge.o src/level/event/guardians.o \ src/level/event/bridge.o src/level/event/guardians.o \
src/level/event/event.o src/level/event/eventframe.o \ src/level/event/event.o src/level/event/standardevent.o \
src/level/bullet.o src/level/demolevel.o src/level/level.o \ src/level/bullet.o src/level/demolevel.o src/level/level.o \
src/level/levelframe.o src/level/levelload.o src/level/movable.o \ src/level/levelframe.o src/level/levelload.o src/level/movable.o \
src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \ src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \
......
...@@ -17,7 +17,7 @@ objects = src/bonus/bonus.o \ ...@@ -17,7 +17,7 @@ objects = src/bonus/bonus.o \
src/jj2level/jj2layer.o src/jj2level/jj2level.o \ src/jj2level/jj2layer.o src/jj2level/jj2level.o \
src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \ src/jj2level/jj2levelframe.o src/jj2level/jj2levelload.o \
src/level/event/bridge.o src/level/event/guardians.o \ src/level/event/bridge.o src/level/event/guardians.o \
src/level/event/event.o src/level/event/eventframe.o \ src/level/event/event.o src/level/event/standardevent.o \
src/level/bullet.o src/level/demolevel.o src/level/level.o \ src/level/bullet.o src/level/demolevel.o src/level/level.o \
src/level/levelframe.o src/level/levelload.o src/level/movable.o \ src/level/levelframe.o src/level/levelload.o src/level/movable.o \
src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \ src/menu/gamemenu.o src/menu/mainmenu.o src/menu/menu.o \
......
...@@ -26,7 +26,10 @@ ...@@ -26,7 +26,10 @@
#include "level/level.h" #include "level/level.h"
/**
* Create empty animation.
*/
Anim::Anim () { Anim::Anim () {
sprites = new Sprite *[19]; sprites = new Sprite *[19];
...@@ -41,7 +44,10 @@ Anim::Anim () { ...@@ -41,7 +44,10 @@ Anim::Anim () {
} }
/**
* Delete animation.
*/
Anim::~Anim () { Anim::~Anim () {
delete[] sprites; delete[] sprites;
...@@ -52,22 +58,33 @@ Anim::~Anim () { ...@@ -52,22 +58,33 @@ Anim::~Anim () {
} }
/**
* Set overall animation data.
*
* @param length Number of frames
* @param sX Bullet generation x-coordinate
* @param sY Bullet generation y-coordinate
* @param aX Accessory animation x-coordinate
* @param aY Accessory animation y-coordinate
* @param a Accessory animation index
* @param y Vertical offset
*/
void Anim::setData (int length, signed char sX, signed char sY, signed char aX, signed char aY, unsigned char a, signed char y) {
void Anim::setData (int amount, signed char sX, signed char sY, signed char aX, signed char aY, unsigned char a, signed char y) { if (length > 19) {
if (amount > 19) {
delete[] sprites; delete[] sprites;
delete[] xOffsets; delete[] xOffsets;
delete[] yOffsets; delete[] yOffsets;
sprites = new Sprite *[amount]; sprites = new Sprite *[length];
xOffsets = new signed char[amount]; xOffsets = new signed char[length];
yOffsets = new signed char[amount]; yOffsets = new signed char[length];
} }
frames = amount; frames = length;
shootX = sX; shootX = sX;
shootY = sY; shootY = sY;
accessoryX = aX; accessoryX = aX;
...@@ -79,7 +96,13 @@ void Anim::setData (int amount, signed char sX, signed char sY, signed char aX, ...@@ -79,7 +96,13 @@ void Anim::setData (int amount, signed char sX, signed char sY, signed char aX,
} }
/**
* Set current frame.
*
* @param nextFrame The frame to use
* @param looping Whether the animation should stop at the end or loop
*/
void Anim::setFrame (int nextFrame, bool looping) { void Anim::setFrame (int nextFrame, bool looping) {
if (looping) frame = nextFrame % frames; if (looping) frame = nextFrame % frames;
...@@ -89,7 +112,14 @@ void Anim::setFrame (int nextFrame, bool looping) { ...@@ -89,7 +112,14 @@ void Anim::setFrame (int nextFrame, bool looping) {
} }
/**
* Set the data for the current frame.
*
* @param sprite Sprite to use
* @param x Horizontal offset
* @param y Vertical offset
*/
void Anim::setFrameData (Sprite *sprite, signed char x, signed char y) { void Anim::setFrameData (Sprite *sprite, signed char x, signed char y) {
sprites[frame] = sprite; sprites[frame] = sprite;
...@@ -100,7 +130,12 @@ void Anim::setFrameData (Sprite *sprite, signed char x, signed char y) { ...@@ -100,7 +130,12 @@ void Anim::setFrameData (Sprite *sprite, signed char x, signed char y) {
} }
/**
* Determine the width of the current frame.
*
* @return The width of the current frame
*/
int Anim::getWidth () { int Anim::getWidth () {
return sprites[frame]->getWidth(); return sprites[frame]->getWidth();
...@@ -108,13 +143,35 @@ int Anim::getWidth () { ...@@ -108,13 +143,35 @@ int Anim::getWidth () {
} }
/**
* Determine the height of the current frame.
*
* @return The height of the current frame
*/
int Anim::getHeight () { int Anim::getHeight () {
return sprites[frame]->getHeight(); return sprites[frame]->getHeight();
} }
/**
* Determine the length of the animation.
*
* @return The length of the animation
*/
int Anim::getLength () {
return frames;
}
/**
* Determine the bullet generation x-coordinate of the current frame.
*
* @return The bullet generation x-coordinate
*/
fixed Anim::getShootX () { fixed Anim::getShootX () {
return ITOF(shootX + (xOffsets[frame] << 2)); return ITOF(shootX + (xOffsets[frame] << 2));
...@@ -122,6 +179,11 @@ fixed Anim::getShootX () { ...@@ -122,6 +179,11 @@ fixed Anim::getShootX () {
} }
/**
* Determine the bullet generation y-coordinate of the current frame.
*
* @return The bullet generation y-coordinate
*/
fixed Anim::getShootY () { fixed Anim::getShootY () {
return ITOF(shootY + yOffsets[frame] - yOffset); return ITOF(shootY + yOffsets[frame] - yOffset);
...@@ -129,6 +191,11 @@ fixed Anim::getShootY () { ...@@ -129,6 +191,11 @@ fixed Anim::getShootY () {
} }
/**
* Determine the accessory animation x-coordinate.
*
* @return The accessory animation x-coordinate
*/
fixed Anim::getAccessoryX () { fixed Anim::getAccessoryX () {
return ITOF(accessoryX << 2); return ITOF(accessoryX << 2);
...@@ -136,6 +203,11 @@ fixed Anim::getAccessoryX () { ...@@ -136,6 +203,11 @@ fixed Anim::getAccessoryX () {
} }
/**
* Determine the accessory animation y-coordinate.
*
* @return The accessory animation y-coordinate
*/
fixed Anim::getAccessoryY () { fixed Anim::getAccessoryY () {
return ITOF(accessoryY - yOffset); return ITOF(accessoryY - yOffset);
...@@ -143,6 +215,11 @@ fixed Anim::getAccessoryY () { ...@@ -143,6 +215,11 @@ fixed Anim::getAccessoryY () {
} }
/**
* Determine the accessory bullet generation x-coordinate of the current frame.
*
* @return The accessory bullet generation x-coordinate
*/
fixed Anim::getAccessoryShootX () { fixed Anim::getAccessoryShootX () {
return ITOF(shootX + (accessoryX << 2) + xOffsets[frame]); return ITOF(shootX + (accessoryX << 2) + xOffsets[frame]);
...@@ -150,6 +227,11 @@ fixed Anim::getAccessoryShootX () { ...@@ -150,6 +227,11 @@ fixed Anim::getAccessoryShootX () {
} }
/**
* Determine the accessory bullet generation y-coordinate of the current frame.
*
* @return The accessory bullet generation y-coordinate
*/
fixed Anim::getAccessoryShootY () { fixed Anim::getAccessoryShootY () {
return ITOF(shootY + accessoryY + yOffsets[frame] - yOffset); return ITOF(shootY + accessoryY + yOffsets[frame] - yOffset);
...@@ -157,6 +239,11 @@ fixed Anim::getAccessoryShootY () { ...@@ -157,6 +239,11 @@ fixed Anim::getAccessoryShootY () {
} }
/**
* Determine the vertical offset.
*
* @return The vertical offset
*/
fixed Anim::getOffset () { fixed Anim::getOffset () {
if (!ignoreDefaultYOffset && yOffset == 0) if (!ignoreDefaultYOffset && yOffset == 0)
...@@ -167,6 +254,11 @@ fixed Anim::getOffset () { ...@@ -167,6 +254,11 @@ fixed Anim::getOffset () {
} }
/**
* Determine the accessory animation.
*
* @return The accessory animation
*/
Anim* Anim::getAccessory() { Anim* Anim::getAccessory() {
return level->getAnim(accessory); return level->getAnim(accessory);
...@@ -174,6 +266,12 @@ Anim* Anim::getAccessory() { ...@@ -174,6 +266,12 @@ Anim* Anim::getAccessory() {
} }
/**
* Draw current frame.
*
* @param x X-coordinate at which to draw
* @param y Y-coordinate at which to draw
*/
void Anim::draw (fixed x, fixed y) { void Anim::draw (fixed x, fixed y) {
// In case yOffset is zero, and the ignore default offset flag is set, // In case yOffset is zero, and the ignore default offset flag is set,
...@@ -201,6 +299,13 @@ void Anim::draw (fixed x, fixed y) { ...@@ -201,6 +299,13 @@ void Anim::draw (fixed x, fixed y) {
} }
/**
* Draw current frame scaled.
*
* @param x X-coordinate at which to draw
* @param y Y-coordinate at which to draw
* @param scale Scaling factor
*/
void Anim::drawScaled (fixed x, fixed y, fixed scale) { void Anim::drawScaled (fixed x, fixed y, fixed scale) {
// Used to draw bonus level player, so no offset // Used to draw bonus level player, so no offset
...@@ -211,13 +316,25 @@ void Anim::drawScaled (fixed x, fixed y, fixed scale) { ...@@ -211,13 +316,25 @@ void Anim::drawScaled (fixed x, fixed y, fixed scale) {
} }
/**
* Disable default vertical offset.
*/
void Anim::disableDefaultOffset() { void Anim::disableDefaultOffset() {
ignoreDefaultYOffset = true; ignoreDefaultYOffset = true;
return;
} }
/**
* Set the current frame's palette.
*
* @param palette The new palette to use
* @param start The first entry to use
* @param amount The number of entries to use
*/
void Anim::setPalette (SDL_Color *palette, int start, int amount) { void Anim::setPalette (SDL_Color *palette, int start, int amount) {
sprites[frame]->setPalette(palette, 0, 256); sprites[frame]->setPalette(palette, 0, 256);
...@@ -226,7 +343,12 @@ void Anim::setPalette (SDL_Color *palette, int start, int amount) { ...@@ -226,7 +343,12 @@ void Anim::setPalette (SDL_Color *palette, int start, int amount) {
} }
/**
* Turn the whole of the current frame a single colour.
*
* @param index The index of the colour to use
*/
void Anim::flashPalette (int index) { void Anim::flashPalette (int index) {
sprites[frame]->flashPalette(index); sprites[frame]->flashPalette(index);
...@@ -235,7 +357,10 @@ void Anim::flashPalette (int index) { ...@@ -235,7 +357,10 @@ void Anim::flashPalette (int index) {
} }
/**
* Restore the current frame's original palette.
*/
void Anim::restorePalette () { void Anim::restorePalette () {
sprites[frame]->restorePalette(); sprites[frame]->restorePalette();
......
...@@ -39,14 +39,14 @@ class Anim { ...@@ -39,14 +39,14 @@ class Anim {
private: private:
Sprite** sprites; ///< Sprite images Sprite** sprites; ///< Sprite images
signed char* xOffsets; signed char* xOffsets; ///< Horizontal offsets for each frame
signed char* yOffsets; signed char* yOffsets; ///< Vertical offsets for each frame
bool ignoreDefaultYOffset; bool ignoreDefaultYOffset;
signed char shootX; signed char shootX; ///< Bullet generation x-coordinate
signed char shootY; signed char shootY; ///< Bullet generation y-coordinate
signed char accessoryX; signed char accessoryX; ///< Accessory animation x-coordinate
signed char accessoryY; signed char accessoryY; ///< Accessory animation y-coordinate
signed char yOffset; signed char yOffset; ///< Vertical offset
unsigned char frames; ///< Number of frames unsigned char frames; ///< Number of frames
unsigned char frame; ///< Current frame unsigned char frame; ///< Current frame
unsigned char accessory; ///< Number of an animation that is an accessory to this animation unsigned char accessory; ///< Number of an animation that is an accessory to this animation
...@@ -56,11 +56,12 @@ class Anim { ...@@ -56,11 +56,12 @@ class Anim {
Anim (); Anim ();
~Anim (); ~Anim ();
void setData (int amount, signed char sX, signed char sY, signed char aX, signed char aY, unsigned char a, signed char y); void setData (int length, signed char sX, signed char sY, signed char aX, signed char aY, unsigned char a, signed char y);
void setFrame (int nextFrame, bool looping); void setFrame (int nextFrame, bool looping);
void setFrameData (Sprite *frameSprite, signed char x, signed char y); void setFrameData (Sprite *frameSprite, signed char x, signed char y);
int getWidth (); int getWidth ();
int getHeight (); int getHeight ();
int getLength ();
fixed getShootX (); fixed getShootX ();
fixed getShootY (); fixed getShootY ();
fixed getAccessoryX (); fixed getAccessoryX ();
......
...@@ -33,6 +33,13 @@ ...@@ -33,6 +33,13 @@
#include "player/levelplayer.h" #include "player/levelplayer.h"
/**
* Create a bullet fired by a player.
*
* @param sourcePlayer The player that fired the bullet
* @param lower Indicates if this the second of two bullets to be created
* @param ticks Time
*/
Bullet::Bullet (LevelPlayer* sourcePlayer, bool lower, unsigned int ticks) { Bullet::Bullet (LevelPlayer* sourcePlayer, bool lower, unsigned int ticks) {
Anim* anim; Anim* anim;
...@@ -89,33 +96,16 @@ Bullet::Bullet (LevelPlayer* sourcePlayer, bool lower, unsigned int ticks) { ...@@ -89,33 +96,16 @@ Bullet::Bullet (LevelPlayer* sourcePlayer, bool lower, unsigned int ticks) {
} }
Bullet::Bullet (Event* sourceEvent, bool facing, unsigned int ticks) { /**
* Create a bullet fired by an event.
Anim* anim; *
* @param xStart The x-coordinate of the bullet
// Properties based on the event * @param yStart The y-coordinate of the bullet
* @param bullet Type
next = level->bullets; * @param facing The direction of the bullet
source = NULL; * @param ticks Time
type = sourceEvent->getProperty(E_BULLET); */
direction = facing? 1: 0; Bullet::Bullet (fixed xStart, fixed yStart, unsigned char bullet, bool facing, unsigned int ticks) {
sprite = level->getSprite(((unsigned char *)level->getBullet(type))[B_SPRITE + direction]);
anim = level->getAnim(sourceEvent->getProperty(facing? E_LSHOOTANIM: E_RSHOOTANIM));
x = sourceEvent->getX() + anim->getShootX();
y = sourceEvent->getY() + anim->getShootY() - ITOF((sprite->getHeight() / 2) - 2);
dx = level->getBullet(type)[B_XSPEED + direction] * 500 * F1;
dy = level->getBullet(type)[B_YSPEED + direction] * 250 * F1;
time = ticks + T_BULLET;
level->playSound(level->getBullet(type)[B_STARTSOUND]);
return;
}
Bullet::Bullet (fixed xStart, fixed yStart, int bullet, bool facing, unsigned int ticks) {
// Properties based on a given bullet type and starting position // Properties based on a given bullet type and starting position
...@@ -138,6 +128,13 @@ Bullet::Bullet (fixed xStart, fixed yStart, int bullet, bool facing, unsigned in ...@@ -138,6 +128,13 @@ Bullet::Bullet (fixed xStart, fixed yStart, int bullet, bool facing, unsigned in
} }
/**
* Create a bullet fired by a bird.
*
* @param sourceBird The bird that fired the bullet
* @param lower Indicates if this the second of two bullets to be created
* @param ticks Time
*/
Bullet::Bullet (Bird* sourceBird, bool lower, unsigned int ticks) { Bullet::Bullet (Bird* sourceBird, bool lower, unsigned int ticks) {
// Properties based on the bird and its player // Properties based on the bird and its player
...@@ -172,6 +169,9 @@ Bullet::Bullet (Bird* sourceBird, bool lower, unsigned int ticks) { ...@@ -172,6 +169,9 @@ Bullet::Bullet (Bird* sourceBird, bool lower, unsigned int ticks) {
} }
/**
* Delete all bullets.
*/
Bullet::~Bullet () { Bullet::~Bullet () {
if (next) delete next; if (next) delete next;
...@@ -181,6 +181,11 @@ Bullet::~Bullet () { ...@@ -181,6 +181,11 @@ Bullet::~Bullet () {
} }
/**
* Delete this bullet.
*
* @return The next bullet
*/
Bullet* Bullet::remove () { Bullet* Bullet::remove () {
Bullet* oldNext; Bullet* oldNext;
...@@ -194,6 +199,11 @@ Bullet* Bullet::remove () { ...@@ -194,6 +199,11 @@ Bullet* Bullet::remove () {
} }
/**
* Get the player responsible for this bullet.
*
* @return The player (NULL if fired by an event)
*/
LevelPlayer* Bullet::getSource () { LevelPlayer* Bullet::getSource () {
return source; return source;
...@@ -201,6 +211,14 @@ LevelPlayer* Bullet::getSource () { ...@@ -201,6 +211,14 @@ LevelPlayer* Bullet::getSource () {
} }
/**
* Bullet iteration.
*
* @param ticks Time
* @param msps Ticks per step
*
* @return Remaining bullet
*/
Bullet* Bullet::step (unsigned int ticks, int msps) { Bullet* Bullet::step (unsigned int ticks, int msps) {
signed char* set; signed char* set;
...@@ -325,6 +343,11 @@ Bullet* Bullet::step (unsigned int ticks, int msps) { ...@@ -325,6 +343,11 @@ Bullet* Bullet::step (unsigned int ticks, int msps) {
} }
/**
* Draw the bullet.
*
* @param change Time since last iteration
*/
void Bullet::draw (int change) { void Bullet::draw (int change) {
if (next) next->draw(change); if (next) next->draw(change);
......
...@@ -59,7 +59,7 @@ class Sprite; ...@@ -59,7 +59,7 @@ class Sprite;
class Bullet : public Movable { class Bullet : public Movable {
private: private:
Bullet* next; Bullet* next; ///< The next bullet
LevelPlayer* source; ///< Source player. If NULL, was fired by an event LevelPlayer* source; ///< Source player. If NULL, was fired by an event
Sprite* sprite; ///< Sprite Sprite* sprite; ///< Sprite
int type; ///< -1 is TNT, otherwise indexes the bullet set int type; ///< -1 is TNT, otherwise indexes the bullet set
...@@ -70,9 +70,8 @@ class Bullet : public Movable { ...@@ -70,9 +70,8 @@ class Bullet : public Movable {
public: public:
Bullet (LevelPlayer* sourcePlayer, bool lower, unsigned int ticks); Bullet (LevelPlayer* sourcePlayer, bool lower, unsigned int ticks);
Bullet (Event* sourceEvent, bool facing, unsigned int ticks);
Bullet (Bird* sourceBird, bool lower, unsigned int ticks); Bullet (Bird* sourceBird, bool lower, unsigned int ticks);
Bullet (fixed xStart, fixed yStart, int bullet, bool facing, unsigned int ticks); Bullet (fixed xStart, fixed yStart, unsigned char bullet, bool facing, unsigned int ticks);
~Bullet (); ~Bullet ();
LevelPlayer* getSource (); LevelPlayer* getSource ();
......
...@@ -27,32 +27,25 @@ ...@@ -27,32 +27,25 @@
#include "../level.h" #include "../level.h"
#include "event.h" #include "event.h"
#include "player/levelplayer.h" #include "player/levelplayer.h"
Bridge::Bridge (unsigned char gX, unsigned char gY) { /**
* Create bridge.
signed char* set; *
* @param gX X-coordinate
set = level->getEvent(gX, gY); * @param gY Y-coordinate
*/
x = TTOF(gX); Bridge::Bridge (unsigned char gX, unsigned char gY) : Event(gX, gY) {
y = TTOF(gY) + ITOF(set[E_YAXIS]) - F8 - F1;
dx = 0;
dy = 0;
next = level->getEvents(); y = TTOF(gY) + ITOF(set->multiB);
gridX = gX;
gridY = gY;
animType = E_LEFTANIM;
flashTime = 0;
// Bridges should ignore the default yOffsets // Bridges should ignore the default yOffsets
dontUseAnimOffset(); noAnimOffset = true;
// leftDipX and rightDipX used to store leftmost and rightmost player on bridge // leftDipX and rightDipX used to store leftmost and rightmost player on bridge
// Start with minimum values // Start with minimum values
leftDipX = set[E_MULTIPURPOSE] * set[E_BRIDGELENGTH] * F4; leftDipX = set->multiA * set->pieceSize * F4;
rightDipX = 0; rightDipX = 0;
return; return;
...@@ -60,10 +53,17 @@ Bridge::Bridge (unsigned char gX, unsigned char gY) { ...@@ -60,10 +53,17 @@ Bridge::Bridge (unsigned char gX, unsigned char gY) {
} }
/**
* Bridge iteration.
*
* @param ticks Time
* @param msps Ticks per step
*
* @return Remaining event
*/
Event* Bridge::step (unsigned int ticks, int msps) { Event* Bridge::step (unsigned int ticks, int msps) {
LevelPlayer* levelPlayer; LevelPlayer* levelPlayer;
signed char* set;
int count; int count;
fixed bridgeLength, playerDipX, playerDipY; fixed bridgeLength, playerDipX, playerDipY;
...@@ -73,7 +73,7 @@ Event* Bridge::step (unsigned int ticks, int msps) { ...@@ -73,7 +73,7 @@ Event* Bridge::step (unsigned int ticks, int msps) {
if (!set) return remove(); if (!set) return remove();
bridgeLength = set[E_MULTIPURPOSE] * set[E_BRIDGELENGTH] * F4; bridgeLength = set->multiA * set->pieceSize * F4;
// Gradually stop the bridge sagging // Gradually stop the bridge sagging
...@@ -92,8 +92,8 @@ Event* Bridge::step (unsigned int ticks, int msps) { ...@@ -92,8 +92,8 @@ Event* Bridge::step (unsigned int ticks, int msps) {
if (playerDipX < bridgeLength >> 1) playerDipY = playerDipX >> 3; if (playerDipX < bridgeLength >> 1) playerDipY = playerDipX >> 3;
else playerDipY = (bridgeLength - playerDipX) >> 3; else playerDipY = (bridgeLength - playerDipX) >> 3;
if (levelPlayer->overlap(x, y + playerDipY - F4, bridgeLength, F8) && if (levelPlayer->overlap(x, y - F8 + playerDipY - F4, bridgeLength, F8) &&
!level->checkMaskDown(x + playerDipX, y + playerDipY - F32)) { !level->checkMaskDown(x + playerDipX, y - F8 + playerDipY - F32)) {
// Player is on the bridge // Player is on the bridge
...@@ -103,7 +103,7 @@ Event* Bridge::step (unsigned int ticks, int msps) { ...@@ -103,7 +103,7 @@ Event* Bridge::step (unsigned int ticks, int msps) {
if (playerDipX > rightDipX) rightDipX = playerDipX; if (playerDipX > rightDipX) rightDipX = playerDipX;
levelPlayer->setPosition(levelPlayer->getX(), y + playerDipY); levelPlayer->setPosition(levelPlayer->getX(), y - F8 - F1 + playerDipY);
} else levelPlayer->clearEvent(gridX, gridY); } else levelPlayer->clearEvent(gridX, gridY);
...@@ -115,52 +115,55 @@ Event* Bridge::step (unsigned int ticks, int msps) { ...@@ -115,52 +115,55 @@ Event* Bridge::step (unsigned int ticks, int msps) {
} }
/**
* Draw bridge.
*
* @param ticks Time
* @param change Time since last iteration
*/
void Bridge::draw (unsigned int ticks, int change) { void Bridge::draw (unsigned int ticks, int change) {
Anim *anim; Anim* anim;
signed char *set; unsigned char frame;
int count; int count;
fixed bridgeLength, leftDipY, rightDipY; fixed bridgeLength, anchorY, leftDipY, rightDipY;
if (next) next->draw(ticks, change); if (next) next->draw(ticks, change);
// Get the event properties
set = level->getEvent(gridX, gridY);
// If the event has been removed from the grid, do not show it // If the event has been removed from the grid, do not show it
if (!set) return; if (!set) return;
// Check if the event has anything to draw // Check if the event has anything to draw
if (!animType || (set[animType] < 0)) return; if ((animType == E_NOANIM) || ((set->anims[animType] & 0x7F) == 0)) return;
if (set[E_ANIMSP]) frame = ticks / (set[E_ANIMSP] * 40); frame = ticks / (set->animSpeed << 5);
else frame = ticks / 20;
anim = level->getAnim(set[animType]); anim = getAnim();
anim->setFrame(frame + gridX + gridY, true); anim->setFrame(frame + gridX + gridY, true);
// Draw the bridge // Draw the bridge
bridgeLength = set[E_MULTIPURPOSE] * set[E_BRIDGELENGTH] * F4; bridgeLength = set->multiA * set->pieceSize * F4;
anchorY = getDrawY(change) - F10 + anim->getOffset();
if (rightDipX >= leftDipX) { if (rightDipX >= leftDipX) {
leftDipY = (leftDipX <= (bridgeLength >> 1)) ? leftDipX >> 3: (bridgeLength - leftDipX) >> 3; leftDipY = (leftDipX <= (bridgeLength >> 1)) ? leftDipX >> 3: (bridgeLength - leftDipX) >> 3;
rightDipY = (rightDipX <= (bridgeLength >> 1)) ? rightDipX >> 3: (bridgeLength - rightDipX) >> 3; rightDipY = (rightDipX <= (bridgeLength >> 1)) ? rightDipX >> 3: (bridgeLength - rightDipX) >> 3;
for (count = 0; count < bridgeLength; count += F4 * set[E_BRIDGELENGTH]) { for (count = 0; count < bridgeLength; count += F4 * set->pieceSize) {
if (count < leftDipX) if (count < leftDipX)
anim->draw(getDrawX(change) + count, getDrawY(change) + TTOF(1) + (count * leftDipY / leftDipX)); anim->draw(getDrawX(change) + count, anchorY + (count * leftDipY / leftDipX));
else if (count < dy) else if (count < rightDipX)
anim->draw(getDrawX(change) + count, getDrawY(change) + TTOF(1) + leftDipY + ((count - leftDipX) * (rightDipY - leftDipY) / (rightDipX - leftDipX))); anim->draw(getDrawX(change) + count, anchorY + leftDipY + ((count - leftDipX) * (rightDipY - leftDipY) / (rightDipX - leftDipX)));
else else
anim->draw(getDrawX(change) + count, getDrawY(change) + TTOF(1) + ((bridgeLength - count) * rightDipY / (bridgeLength - rightDipX))); anim->draw(getDrawX(change) + count, anchorY + ((bridgeLength - count) * rightDipY / (bridgeLength - rightDipX)));
} }
...@@ -174,12 +177,12 @@ void Bridge::draw (unsigned int ticks, int change) { ...@@ -174,12 +177,12 @@ void Bridge::draw (unsigned int ticks, int change) {
// Dip // Dip
rightDipY = (rightDipX < bridgeLength - leftDipX) ? rightDipX >> 3: (bridgeLength - leftDipX) >> 3; rightDipY = (rightDipX < bridgeLength - leftDipX) ? rightDipX >> 3: (bridgeLength - leftDipX) >> 3;
for (count = 0; count < bridgeLength; count += F4 * set[E_BRIDGELENGTH]) { for (count = 0; count < bridgeLength; count += F4 * set->pieceSize) {
if (count < leftDipY) if (count < leftDipY)
anim->draw(getDrawX(change) + count, getDrawY(change) + TTOF(1) + (count * rightDipY / leftDipY)); anim->draw(getDrawX(change) + count, anchorY + (count * rightDipY / leftDipY));
else else
anim->draw(getDrawX(change) + count, getDrawY(change) + TTOF(1) + ((bridgeLength - count) * rightDipY / (bridgeLength - leftDipY))); anim->draw(getDrawX(change) + count, anchorY + ((bridgeLength - count) * rightDipY / (bridgeLength - leftDipY)));
} }
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
* 19th July 2009: Created eventframe.cpp from parts of events.cpp * 19th July 2009: Created eventframe.cpp from parts of events.cpp
* 19th July 2009: Renamed events.cpp to event.cpp * 19th July 2009: Renamed events.cpp to event.cpp
* 2nd March 2010: Created guardians.cpp from parts of event.cpp and eventframe.cpp * 2nd March 2010: Created guardians.cpp from parts of event.cpp and eventframe.cpp
* 2nd March 2010: Created bridge.cpp from parts of event.cpp and eventframe.cpp * 2nd March 2010: Created bridge.cpp from parts of event.cpp and eventframe.cpp
* 5th February 2011: Moved parts of eventframe.cpp to event.cpp
* *
* @section Licence * @section Licence
* Copyright (c) 2005-2010 Alister Thomson * Copyright (c) 2005-2010 Alister Thomson
...@@ -36,21 +37,23 @@ ...@@ -36,21 +37,23 @@
#include "../level.h" #include "../level.h"
#include "event.h" #include "event.h"
#include "io/gfx/video.h"
#include "io/sound.h" #include "io/sound.h"
#include "player/player.h" #include "player/player.h"
#include "util.h" #include "util.h"
Event::Event () { /**
* Create event
return; *
* @param gX X-coordinate
} * @param gY Y-coordinate
*/
Event::Event (unsigned char gX, unsigned char gY) { Event::Event (unsigned char gX, unsigned char gY) {
set = level->getEvent(gX, gY);
x = TTOF(gX); x = TTOF(gX);
y = TTOF(gY + 1); y = TTOF(gY + 1);
dx = 0; dx = 0;
...@@ -61,59 +64,17 @@ Event::Event (unsigned char gX, unsigned char gY) { ...@@ -61,59 +64,17 @@ Event::Event (unsigned char gX, unsigned char gY) {
gridY = gY; gridY = gY;
flashTime = 0; flashTime = 0;
onlyLAnimOffset = false; animType = E_LEFTANIM;
onlyRAnimOffset = false;
noAnimOffset = false; noAnimOffset = false;
switch (getProperty(E_BEHAVIOUR)) {
case 2: // Walk from side to side
case 4: // Walk from side to side and down hills
animType = E_LEFTANIM;
useRightAnimOffset();
break;
case 6: // Use the path from the level file
case 7: // Flying snake behavior
animType = E_LEFTANIM;
dontUseAnimOffset();
break;
case 21: // Destructible block
case 25: // Float up / Belt
case 37: // Sucker tubes
case 38: // Sucker tubes
case 40: // Monochrome
case 57: // Bubbles
animType = 0;
break;
case 26: // Flip animation
animType = E_RIGHTANIM;
useLeftAnimOffset();
break;
default:
animType = E_LEFTANIM;
break;
}
return; return;
} }
/**
* Delete all events
*/
Event::~Event () { Event::~Event () {
if (next) delete next; if (next) delete next;
...@@ -123,6 +84,11 @@ Event::~Event () { ...@@ -123,6 +84,11 @@ Event::~Event () {
} }
/**
* Delete this event
*
* @return The next event
*/
Event* Event::remove () { Event* Event::remove () {
Event *oldNext; Event *oldNext;
...@@ -136,21 +102,30 @@ Event* Event::remove () { ...@@ -136,21 +102,30 @@ Event* Event::remove () {
} }
/**
* Get the next event
*
* @return The next event
*/
Event * Event::getNext () { Event * Event::getNext () {
return next; return next;
} }
/**
* Initiate the destruction of the event
*
* @param ticks Time
*/
void Event::destroy (unsigned int ticks) { void Event::destroy (unsigned int ticks) {
level->setEventTime(gridX, gridY, ticks + T_FINISH); animType = E_LFINISHANIM | (animType & 1);
animType = ((animType == E_RIGHTANIM) || (animType == E_RSHOOTANIM)) ? level->setEventTime(gridX, gridY, ticks + (getAnim()->getLength() * set->animSpeed << 3));
E_RFINISHANIM: E_LFINISHANIM;
level->playSound(set->sound);
level->playSound(getProperty(E_SOUND));
return; return;
...@@ -170,8 +145,7 @@ bool Event::hit (LevelPlayer *source, unsigned int ticks) { ...@@ -170,8 +145,7 @@ bool Event::hit (LevelPlayer *source, unsigned int ticks) {
int hitsRemaining; int hitsRemaining;
// Check if event has already been destroyed // Check if event has already been destroyed
if ((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM) || if (((animType & ~1) == E_LFINISHANIM) || (ticks < flashTime)) return false;
(ticks < flashTime)) return false;
hitsRemaining = level->hitEvent(gridX, gridY, source); hitsRemaining = level->hitEvent(gridX, gridY, source);
...@@ -189,34 +163,45 @@ bool Event::hit (LevelPlayer *source, unsigned int ticks) { ...@@ -189,34 +163,45 @@ bool Event::hit (LevelPlayer *source, unsigned int ticks) {
} }
/**
* Determine whether or not the event is an enemy
*
* @return Whether or not the event is an enemy
*/
bool Event::isEnemy () { bool Event::isEnemy () {
signed char *set; return set->strength && (set->modifier == 0);
set = level->getEvent(gridX, gridY);
return set[E_HITSTOKILL] && (set[E_MODIFIER] == 0);
} }
/**
* Determine whether or not the event is from the given position
*
* @return Whether or not the event is from the given position
*/
bool Event::isFrom (unsigned char gX, unsigned char gY) { bool Event::isFrom (unsigned char gX, unsigned char gY) {
return (gX == gridX) && (gY == gridY); return (gX == gridX) && (gY == gridY);
} }
/**
* Get the width of the event
*
* @return The width of the event
*/
fixed Event::getWidth () { fixed Event::getWidth () {
fixed width; fixed width;
if (!animType) return F32; if (animType == E_NOANIM) return F32;
if (getProperty(animType) <= 0) return 0; if ((set->anims[animType] & 0x7F) == 0) return 0;
width = ITOF(level->getAnim(getProperty(animType))->getWidth()); width = ITOF(getAnim()->getWidth());
// Blank sprites for e.g. invisible springs // Blank sprites for e.g. invisible springs
if ((width == F1) && (getHeight() == F1)) return F32; if ((width == F1) && (getHeight() == F1)) return F32;
...@@ -226,22 +211,37 @@ fixed Event::getWidth () { ...@@ -226,22 +211,37 @@ fixed Event::getWidth () {
} }
/**
* Get the height of the event
*
* @return The height of the event
*/
fixed Event::getHeight () { fixed Event::getHeight () {
if (!animType) return F32; if (animType == E_NOANIM) return F32;
if (getProperty(animType) <= 0) return 0; if ((set->anims[animType] & 0x7F) == 0) return 0;
return ITOF(level->getAnim(getProperty(animType))->getHeight()); return ITOF(getAnim()->getHeight());
} }
/**
* Determine whether or not the event is overlapping the given area
*
* @param left The x-coordinate of the left of the area
* @param top The y-coordinate of the top of the area
* @param width The width of the area
* @param height The height of the area
*
* @return Whether or not there is an overlap
*/
bool Event::overlap (fixed left, fixed top, fixed width, fixed height) { bool Event::overlap (fixed left, fixed top, fixed width, fixed height) {
fixed offset = 0; fixed offset = 0;
if (getAnim(animType) && noAnimOffset) if (getAnim() && noAnimOffset)
offset = getAnim(animType)->getOffset(); offset = getAnim()->getOffset();
return (x + getWidth() >= left) && return (x + getWidth() >= left) &&
(x < left + width) && (x < left + width) &&
...@@ -251,42 +251,99 @@ bool Event::overlap (fixed left, fixed top, fixed width, fixed height) { ...@@ -251,42 +251,99 @@ bool Event::overlap (fixed left, fixed top, fixed width, fixed height) {
} }
signed char Event::getProperty (unsigned char property) { /**
* Get the current animation
signed char *set; *
* @return Animation
set = level->getEvent(gridX, gridY); */
Anim* Event::getAnim () {
if (set) return set[property];
if (animType == E_NOANIM) return NULL;
return 0;
// If there is no shooting animation, use the normal animation instead
} if (((animType & ~1) == E_LSHOOTANIM) && (set->anims[animType] == 0))
return level->getAnim(set->anims[animType & 1] & 0x7F);
Anim* Event::getAnim (unsigned char property) { return level->getAnim(set->anims[animType] & 0x7F);
switch (property) {
case E_LEFTANIM:
case E_RIGHTANIM:
case E_LFINISHANIM:
case E_RFINISHANIM:
case E_LSHOOTANIM:
case E_RSHOOTANIM:
if (getProperty(property) < 0)
return level->getAnim(getProperty(property) + 128);
return level->getAnim(getProperty(property));
default:
return 0;
}
} }
/**
* Functionality required by all event types on each iteration
*
* @param ticks Time
* @param msps Ticks per step
*
* @return Animation
*/
EventType* Event::prepareStep (unsigned int ticks, int msps) {
// Process the next event
if (next) next = next->step(ticks, msps);
// Get the event properties
set = level->getEvent(gridX, gridY);
// If the event has been removed from the grid, destroy it
if (!set) return NULL;
// If the event and its origin are off-screen, the event is not in the
// process of self-destruction, remove it
if (((animType & ~1) != E_LFINISHANIM) &&
((x < viewX - F192) || (x > viewX + ITOF(viewW) + F192) ||
(y < viewY - F160) || (y > viewY + ITOF(viewH) + F160)) &&
((gridX < FTOT(viewX) - 1) ||
(gridX > ITOT(FTOI(viewX) + viewW) + 1) ||
(gridY < FTOT(viewY) - 1) ||
(gridY > ITOT(FTOI(viewY) + viewH) + 1))) return NULL;
return set;
}
/**
* Draw the event's energy bar
*
* @param ticks Time
*/
void Event::drawEnergy (unsigned int ticks) {
Anim* anim;
int hits;
if (!set || set->modifier != 8) {
if (next) next->drawEnergy(ticks);
return;
} else if (set->strength) {
// Draw boss energy bar
hits = level->getEventHits(gridX, gridY) * 100 / set->strength;
// Devan head
anim = level->getMiscAnim(1);
anim->setFrame(0, true);
if (ticks < flashTime) anim->flashPalette(0);
anim->draw(ITOF(viewW - 44), ITOF(hits + 48));
if (ticks < flashTime) anim->restorePalette();
// Bar
drawRect(viewW - 40, hits + 40, 12, 100 - hits, (ticks < flashTime)? 0: 32);
}
return;
}
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define _EVENT_H #define _EVENT_H
#include "../level.h"
#include "../movable.h" #include "../movable.h"
#include "OpenJazz.h" #include "OpenJazz.h"
...@@ -37,45 +38,23 @@ ...@@ -37,45 +38,23 @@
// Constants // Constants
// Indexes for elements of the event set // Animations
/* Names taken from J1CS/JCS94 and J1E #define E_LEFTANIM 0
* ...Except of course it carries on the fine JCF tradition of changing the #define E_RIGHTANIM 1
* spelling of words such as "behavior" */ #define E_LFINISHANIM 2
#define E_DIFFICULTY 0 #define E_RFINISHANIM 3
#define E_REFLECTION 2 #define E_LSHOOTANIM 4
#define E_BEHAVIOR 4 #define E_RSHOOTANIM 5
#define E_BEHAVIOUR 4 #define E_NOANIM 6
#define E_LEFTANIM 5
#define E_RIGHTANIM 6
#define E_MAGNITUDE 8
#define E_HITSTOKILL 9
#define E_MODIFIER 10
#define E_ADDEDSCORE 11
#define E_BULLET 12
#define E_BULLETSP 13
#define E_MOVEMENTSP 15
#define E_ANIMSP 17
#define E_SOUND 21
#define E_MULTIPURPOSE 22
#define E_YAXIS 23
#define E_BRIDGELENGTH 24
#define E_CHAINLENGTH 25
#define E_CHAINANGLE 26
#define E_LFINISHANIM 28
#define E_RFINISHANIM 29
#define E_LSHOOTANIM 30
#define E_RSHOOTANIM 31
// Delays // Delays
#define T_FLASH 100 #define T_FLASH 100
#define T_FINISH 200
#define T_SHOOT 300
// Speed factors // Speed factors
#define ES_SLOW ITOF(80) #define ES_SLOW ITOF(80)
#define ES_FAST ITOF(240) #define ES_FAST ITOF(240)
// Classes // Classes
class LevelPlayer; class LevelPlayer;
...@@ -84,28 +63,25 @@ class LevelPlayer; ...@@ -84,28 +63,25 @@ class LevelPlayer;
class Event : public Movable { class Event : public Movable {
protected: protected:
Event* next; Event* next; ///< Next event
EventType* set; ///< Type
unsigned char gridX, gridY; ///< Grid position of the event unsigned char gridX, gridY; ///< Grid position of the event
unsigned char animType; ///< E_LEFTANIM, etc, or 0 unsigned char animType; ///< Animation type (E_LEFTANIM, etc.)
unsigned char frame; ///< Current animation frame unsigned int flashTime; ///< Time flash will end
unsigned int flashTime;///< Time flash will end
bool noAnimOffset; bool noAnimOffset;
bool onlyLAnimOffset;
bool onlyRAnimOffset;
Event ();
Event* remove ();
void destroy (unsigned int ticks);
fixed getWidth ();
fixed getHeight ();
signed char* prepareStep (unsigned int ticks, int msps);
void useLeftAnimOffset ();
void useRightAnimOffset ();
void dontUseAnimOffset ();
Event (unsigned char gX, unsigned char gY);
Event* remove ();
void destroy (unsigned int ticks);
Anim* getAnim ();
fixed getHeight ();
fixed getWidth ();
EventType* prepareStep (unsigned int ticks, int msps);
public: public:
Event (unsigned char gX, unsigned char gY);
virtual ~Event (); virtual ~Event ();
Event* getNext (); Event* getNext ();
...@@ -113,14 +89,31 @@ class Event : public Movable { ...@@ -113,14 +89,31 @@ class Event : public Movable {
bool isEnemy (); bool isEnemy ();
bool isFrom (unsigned char gX, unsigned char gY); bool isFrom (unsigned char gX, unsigned char gY);
virtual bool overlap (fixed left, fixed top, fixed width, fixed height); virtual bool overlap (fixed left, fixed top, fixed width, fixed height);
signed char getProperty (unsigned char property);
Anim* getAnim (unsigned char property); virtual Event* step (unsigned int ticks, int msps) = 0;
virtual Event* step (unsigned int ticks, int msps); virtual void draw (unsigned int ticks, int change) = 0;
virtual void draw (unsigned int ticks, int change); void drawEnergy (unsigned int ticks);
void drawEnergy (unsigned int ticks);
}; };
/// Standard JJ1 level event
class StandardEvent : public Event {
private:
fixed node; ///< Current event path node
bool onlyLAnimOffset;
bool onlyRAnimOffset;
void move (unsigned int ticks, int msps);
public:
StandardEvent (unsigned char gX, unsigned char gY);
Event* step (unsigned int ticks, int msps);
void draw (unsigned int ticks, int change);
};
/// JJ1 level bridge /// JJ1 level bridge
class Bridge : public Event { class Bridge : public Event {
......
...@@ -36,17 +36,13 @@ ...@@ -36,17 +36,13 @@
#include <stdlib.h> #include <stdlib.h>
Guardian::Guardian(unsigned char gX, unsigned char gY) { /**
* Create guardian.
x = TTOF(gX); *
y = TTOF(gY + 1); * @param gX X-coordinate
dx = 0; * @param gY Y-coordinate
dy = 0; */
Guardian::Guardian(unsigned char gX, unsigned char gY) : Event(gX, gY) {
next = level->getEvents();
gridX = gX;
gridY = gY;
flashTime = 0;
stage = 0; stage = 0;
...@@ -55,6 +51,12 @@ Guardian::Guardian(unsigned char gX, unsigned char gY) { ...@@ -55,6 +51,12 @@ Guardian::Guardian(unsigned char gX, unsigned char gY) {
} }
/**
* Create episode B guardian.
*
* @param gX X-coordinate
* @param gY Y-coordinate
*/
DeckGuardian::DeckGuardian (unsigned char gX, unsigned char gY) : Guardian(gX, gY) { DeckGuardian::DeckGuardian (unsigned char gX, unsigned char gY) : Guardian(gX, gY) {
return; return;
...@@ -62,6 +64,16 @@ DeckGuardian::DeckGuardian (unsigned char gX, unsigned char gY) : Guardian(gX, g ...@@ -62,6 +64,16 @@ DeckGuardian::DeckGuardian (unsigned char gX, unsigned char gY) : Guardian(gX, g
} }
/**
* Determine whether or not the guardian overlaps the given area.
*
* @param left The x-coordinate of the left of the area
* @param top The y-coordinate of the top of the area
* @param width The width of the area
* @param height The height of the area
*
* @return Whether or not there is an overlap
*/
bool DeckGuardian::overlap (fixed left, fixed top, fixed width, fixed height) { bool DeckGuardian::overlap (fixed left, fixed top, fixed width, fixed height) {
if (stage == 0) if (stage == 0)
...@@ -81,9 +93,16 @@ bool DeckGuardian::overlap (fixed left, fixed top, fixed width, fixed height) { ...@@ -81,9 +93,16 @@ bool DeckGuardian::overlap (fixed left, fixed top, fixed width, fixed height) {
} }
/**
* Episode B guardian iteration.
*
* @param ticks Time
* @param msps Ticks per step
*
* @return Remaining event
*/
Event* DeckGuardian::step (unsigned int ticks, int msps) { Event* DeckGuardian::step (unsigned int ticks, int msps) {
signed char* set;
int count; int count;
...@@ -92,8 +111,6 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) { ...@@ -92,8 +111,6 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) {
if (!set) return remove(); if (!set) return remove();
// Handle behaviour
count = level->getEventHits(gridX, gridY); count = level->getEventHits(gridX, gridY);
if (count < 8) stage = 0; if (count < 8) stage = 0;
...@@ -104,9 +121,9 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) { ...@@ -104,9 +121,9 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) {
// If the event has been destroyed, play its finishing animation and set its // If the event has been destroyed, play its finishing animation and set its
// reaction time // reaction time
if (set[E_HITSTOKILL] && if (set->strength &&
(level->getEventHits(gridX, gridY) >= set[E_HITSTOKILL]) && (level->getEventHits(gridX, gridY) >= set->strength) &&
(animType != E_LFINISHANIM) && (animType != E_RFINISHANIM)) { ((animType & ~1) != E_LFINISHANIM)) {
destroy(ticks); destroy(ticks);
...@@ -117,7 +134,7 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) { ...@@ -117,7 +134,7 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) {
if (level->getEventTime(gridX, gridY) && if (level->getEventTime(gridX, gridY) &&
(ticks > level->getEventTime(gridX, gridY))) { (ticks > level->getEventTime(gridX, gridY))) {
if ((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM)) { if ((animType & ~1) == E_LFINISHANIM) {
// The event has been destroyed, so remove it // The event has been destroyed, so remove it
level->clearEvent(gridX, gridY); level->clearEvent(gridX, gridY);
...@@ -138,18 +155,20 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) { ...@@ -138,18 +155,20 @@ Event* DeckGuardian::step (unsigned int ticks, int msps) {
} }
/**
* Draw episode B guardian.
*
* @param ticks Time
* @param change Time since last iteration
*/
void DeckGuardian::draw (unsigned int ticks, int change) { void DeckGuardian::draw (unsigned int ticks, int change) {
Anim* anim; Anim* anim;
signed char* set;
if (next) next->draw(ticks, change); if (next) next->draw(ticks, change);
// Get the event properties
set = level->getEvent(gridX, gridY);
// If the event has been removed from the grid, do not show it // If the event has been removed from the grid, do not show it
if (!set) return; if (!set) return;
...@@ -178,10 +197,14 @@ void DeckGuardian::draw (unsigned int ticks, int change) { ...@@ -178,10 +197,14 @@ void DeckGuardian::draw (unsigned int ticks, int change) {
} }
/**
* Create episode 1 guardian.
*
* @param gX X-coordinate
* @param gY Y-coordinate
*/
MedGuardian::MedGuardian(unsigned char gX, unsigned char gY) : Guardian(gX, gY) { MedGuardian::MedGuardian(unsigned char gX, unsigned char gY) : Guardian(gX, gY) {
animType = E_LEFTANIM;
stage = 0;
direction = 1; direction = 1;
shoot = false; shoot = false;
...@@ -190,23 +213,29 @@ MedGuardian::MedGuardian(unsigned char gX, unsigned char gY) : Guardian(gX, gY) ...@@ -190,23 +213,29 @@ MedGuardian::MedGuardian(unsigned char gX, unsigned char gY) : Guardian(gX, gY)
} }
/*bool MedGuardian::overlap(fixed left, fixed top, fixed width, fixed height) { /**
* Episode 1 guardian iteration.
return false; *
* @param ticks Time
}*/ * @param msps Ticks per step
*
* @return Remaining event
*/
Event* MedGuardian::step(unsigned int ticks, int msps) { Event* MedGuardian::step(unsigned int ticks, int msps) {
Anim *anim = getAnim(animType); Anim *anim = getAnim();
fixed sin = fSin(ticks / 2); fixed sin = fSin(ticks / 2);
fixed cos = fCos(ticks / 2); fixed cos = fCos(ticks / 2);
if (level->getEventHits(gridX, gridY) >= getProperty(E_HITSTOKILL) / 2) set = prepareStep(ticks, msps);
if (!set) return remove();
if (level->getEventHits(gridX, gridY) >= set->strength / 2)
stage = 1; stage = 1;
if (level->getEventHits(gridX, gridY) >= getProperty(E_HITSTOKILL)) if (level->getEventHits(gridX, gridY) >= set->strength)
stage = 2; stage = 2;
// Stage 0: Move in an eight shape and fire the occasional shot // Stage 0: Move in an eight shape and fire the occasional shot
...@@ -262,10 +291,10 @@ Event* MedGuardian::step(unsigned int ticks, int msps) { ...@@ -262,10 +291,10 @@ Event* MedGuardian::step(unsigned int ticks, int msps) {
} }
// Decide if there should be a shot // Decide if there should be a shot
if ((ticks % (getProperty(E_BULLETSP) * 25) > if ((ticks % (set->bulletPeriod * 25) >
(unsigned int)(getProperty(E_BULLETSP) * 25) - T_SHOOT)) { (unsigned int)(set->bulletPeriod * 25) - 300)) {
level->setEventTime(gridX, gridY, ticks + T_SHOOT); level->setEventTime(gridX, gridY, ticks + 300);
shoot = true; shoot = true;
} }
...@@ -275,12 +304,12 @@ Event* MedGuardian::step(unsigned int ticks, int msps) { ...@@ -275,12 +304,12 @@ Event* MedGuardian::step(unsigned int ticks, int msps) {
(ticks > level->getEventTime(gridX, gridY)) && (ticks > level->getEventTime(gridX, gridY)) &&
shoot) { shoot) {
if ((getProperty(E_BULLET) < 32) && if ((set->bullet < 32) &&
(level->getBullet(getProperty(E_BULLET))[B_SPRITE] != 0)) (level->getBullet(set->bullet)[B_SPRITE] != 0))
level->bullets = new Bullet( level->bullets = new Bullet(
x + anim->getAccessoryShootX(), x + anim->getAccessoryShootX(),
y + anim->getAccessoryShootY(), y + anim->getAccessoryShootY(),
getProperty(E_BULLET), (animType != E_LEFTANIM), ticks); set->bullet, (animType != E_LEFTANIM), ticks);
shoot = false; shoot = false;
...@@ -368,7 +397,7 @@ Event* MedGuardian::step(unsigned int ticks, int msps) { ...@@ -368,7 +397,7 @@ Event* MedGuardian::step(unsigned int ticks, int msps) {
level->setTile( level->setTile(
FTOT(x + ITOF((anim->getWidth() / 2))), FTOT(x + ITOF((anim->getWidth() / 2))),
FTOT(y) + 1, FTOT(y) + 1,
getProperty(E_MAGNITUDE)); set->magnitude);
direction = 8; direction = 8;
...@@ -397,10 +426,17 @@ Event* MedGuardian::step(unsigned int ticks, int msps) { ...@@ -397,10 +426,17 @@ Event* MedGuardian::step(unsigned int ticks, int msps) {
} }
/**
* Draw episode 1 guardian.
*
* @param ticks Time
* @param change Time since last iteration
*/
void MedGuardian::draw(unsigned int ticks, int change) { void MedGuardian::draw(unsigned int ticks, int change) {
Anim *anim; Anim *anim;
Anim *accessory; Anim *accessory;
unsigned char frame;
if (next) next->draw(ticks, change); if (next) next->draw(ticks, change);
...@@ -408,20 +444,22 @@ void MedGuardian::draw(unsigned int ticks, int change) { ...@@ -408,20 +444,22 @@ void MedGuardian::draw(unsigned int ticks, int change) {
fixed yChange = getDrawY(change); fixed yChange = getDrawY(change);
if (getProperty(E_ANIMSP)) frame = ticks / (set->animSpeed << 5);
frame = ticks / (getProperty(E_ANIMSP) * 40);
else
frame = ticks / 20;
if (stage == 0) if (stage == 0)
anim = getAnim(animType); anim = getAnim();
else else
anim = getAnim(animType == E_LEFTANIM ? E_LFINISHANIM : E_RFINISHANIM); anim = level->getAnim(set->anims[E_LFINISHANIM | (animType & 1)] & 0x7F);
anim->setFrame(frame + gridX + gridY, true); anim->setFrame(frame + gridX + gridY, true);
if (ticks < flashTime) anim->flashPalette(0);
anim->draw(xChange, yChange); anim->draw(xChange, yChange);
if (ticks < flashTime) anim->restorePalette();
accessory = anim->getAccessory(); accessory = anim->getAccessory();
accessory->setFrame(frame + gridX + gridY, true); accessory->setFrame(frame + gridX + gridY, true);
......
...@@ -36,7 +36,6 @@ class Guardian : public Event { ...@@ -36,7 +36,6 @@ class Guardian : public Event {
protected: protected:
int stage; int stage;
public:
Guardian (unsigned char gX, unsigned char gY); Guardian (unsigned char gX, unsigned char gY);
}; };
......
...@@ -57,6 +57,9 @@ ...@@ -57,6 +57,9 @@
#include <string.h> #include <string.h>
/**
* Base constructor for DemoLevel sub-class.
*/
Level::Level () { Level::Level () {
// Do nothing // Do nothing
...@@ -66,6 +69,14 @@ Level::Level () { ...@@ -66,6 +69,14 @@ Level::Level () {
} }
/**
* Create a level.
*
* @param fileName Name of the file containing the level data.
* @param diff Difficulty level
* @param checkpoint Whether or not the player(s) will start at a checkpoint
* @param multi Whether or not the level will be multi-player
*/
Level::Level (char* fileName, unsigned char diff, bool checkpoint, bool multi) { Level::Level (char* fileName, unsigned char diff, bool checkpoint, bool multi) {
int ret; int ret;
...@@ -83,6 +94,9 @@ Level::Level (char* fileName, unsigned char diff, bool checkpoint, bool multi) { ...@@ -83,6 +94,9 @@ Level::Level (char* fileName, unsigned char diff, bool checkpoint, bool multi) {
} }
/**
* Delete HUD graphical data.
*/
void Level::deletePanel () { void Level::deletePanel () {
SDL_FreeSurface(panel); SDL_FreeSurface(panel);
...@@ -96,7 +110,10 @@ void Level::deletePanel () { ...@@ -96,7 +110,10 @@ void Level::deletePanel () {
} }
/**
* Delete the level.
*/
Level::~Level () { Level::~Level () {
int count; int count;
...@@ -129,7 +146,15 @@ Level::~Level () { ...@@ -129,7 +146,15 @@ Level::~Level () {
} }
/**
* Determine whether or not the given point is solid when travelling upwards.
*
* @param x X-coordinate
* @param y Y-coordinate
*
* @return Solidity
*/
bool Level::checkMaskUp (fixed x, fixed y) { bool Level::checkMaskUp (fixed x, fixed y) {
GridElement *ge; GridElement *ge;
...@@ -149,6 +174,14 @@ bool Level::checkMaskUp (fixed x, fixed y) { ...@@ -149,6 +174,14 @@ bool Level::checkMaskUp (fixed x, fixed y) {
} }
/**
* Determine whether or not the given point is solid when travelling downwards.
*
* @param x X-coordinate
* @param y Y-coordinate
*
* @return Solidity
*/
bool Level::checkMaskDown (fixed x, fixed y) { bool Level::checkMaskDown (fixed x, fixed y) {
// Anything off the edge of the map is solid // Anything off the edge of the map is solid
...@@ -161,6 +194,14 @@ bool Level::checkMaskDown (fixed x, fixed y) { ...@@ -161,6 +194,14 @@ bool Level::checkMaskDown (fixed x, fixed y) {
} }
/**
* Determine whether or not the given point should cause damage to the player.
*
* @param x X-coordinate
* @param y Y-coordinate
*
* @return Painful solidity
*/
bool Level::checkSpikes (fixed x, fixed y) { bool Level::checkSpikes (fixed x, fixed y) {
GridElement *ge; GridElement *ge;
...@@ -180,13 +221,24 @@ bool Level::checkSpikes (fixed x, fixed y) { ...@@ -180,13 +221,24 @@ bool Level::checkSpikes (fixed x, fixed y) {
} }
/**
* Determine the level's world number.
*
* @return World number
*/
int Level::getWorld() { int Level::getWorld() {
return worldNum; return worldNum;
} }
/**
* Set which level will come next.
*
* @param nextLevel Next level number
* @param nextWorld Next level's world number
*/
void Level::setNext (int nextLevel, int nextWorld) { void Level::setNext (int nextLevel, int nextWorld) {
unsigned char buffer[MTL_L_PROP]; unsigned char buffer[MTL_L_PROP];
...@@ -210,7 +262,14 @@ void Level::setNext (int nextLevel, int nextWorld) { ...@@ -210,7 +262,14 @@ void Level::setNext (int nextLevel, int nextWorld) {
} }
/**
* Set the tile at the given location.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
* @param tile The new tile
*/
void Level::setTile (unsigned char gridX, unsigned char gridY, unsigned char tile) { void Level::setTile (unsigned char gridX, unsigned char gridY, unsigned char tile) {
unsigned char buffer[MTL_L_GRID]; unsigned char buffer[MTL_L_GRID];
...@@ -234,7 +293,12 @@ void Level::setTile (unsigned char gridX, unsigned char gridY, unsigned char til ...@@ -234,7 +293,12 @@ void Level::setTile (unsigned char gridX, unsigned char gridY, unsigned char til
} }
/**
* Get the active events.
*
* @return The first active event
*/
Event* Level::getEvents () { Event* Level::getEvents () {
return events; return events;
...@@ -242,17 +306,33 @@ Event* Level::getEvents () { ...@@ -242,17 +306,33 @@ Event* Level::getEvents () {
} }
signed char* Level::getEvent (unsigned char gridX, unsigned char gridY) { /**
* Get the event data for the event from the given tile.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
*
* @return Event data
*/
EventType* Level::getEvent (unsigned char gridX, unsigned char gridY) {
int event = grid[gridY][gridX].event; int event = grid[gridY][gridX].event;
if (event) return eventSet[grid[gridY][gridX].event]; if (event) return eventSet + event;
return NULL; return NULL;
} }
/**
* Get the hits incurred by the event from the given tile.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
*
* @return Number of hits
*/
unsigned char Level::getEventHits (unsigned char gridX, unsigned char gridY) { unsigned char Level::getEventHits (unsigned char gridX, unsigned char gridY) {
return grid[gridY][gridX].hits; return grid[gridY][gridX].hits;
...@@ -260,6 +340,14 @@ unsigned char Level::getEventHits (unsigned char gridX, unsigned char gridY) { ...@@ -260,6 +340,14 @@ unsigned char Level::getEventHits (unsigned char gridX, unsigned char gridY) {
} }
/**
* Get the set time for the event from the given tile.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
*
* @return Time
*/
unsigned int Level::getEventTime (unsigned char gridX, unsigned char gridY) { unsigned int Level::getEventTime (unsigned char gridX, unsigned char gridY) {
return grid[gridY][gridX].time; return grid[gridY][gridX].time;
...@@ -267,13 +355,19 @@ unsigned int Level::getEventTime (unsigned char gridX, unsigned char gridY) { ...@@ -267,13 +355,19 @@ unsigned int Level::getEventTime (unsigned char gridX, unsigned char gridY) {
} }
/**
* Remove the event from the given tile.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
*/
void Level::clearEvent (unsigned char gridX, unsigned char gridY) { void Level::clearEvent (unsigned char gridX, unsigned char gridY) {
unsigned char buffer[MTL_L_GRID]; unsigned char buffer[MTL_L_GRID];
// Ignore if the event has been un-destroyed // Ignore if the event has been un-destroyed
if (!grid[gridY][gridX].hits && if (!grid[gridY][gridX].hits &&
eventSet[grid[gridY][gridX].event][E_HITSTOKILL]) return; eventSet[grid[gridY][gridX].event].strength) return;
grid[gridY][gridX].event = 0; grid[gridY][gridX].event = 0;
...@@ -295,6 +389,15 @@ void Level::clearEvent (unsigned char gridX, unsigned char gridY) { ...@@ -295,6 +389,15 @@ void Level::clearEvent (unsigned char gridX, unsigned char gridY) {
} }
/**
* Register a hit on the event from the given tile.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
* @param source The player that fired the bullet that hit the event
*
* @return The remaining number of hits until the event is destroyed
*/
int Level::hitEvent (unsigned char gridX, unsigned char gridY, LevelPlayer* source) { int Level::hitEvent (unsigned char gridX, unsigned char gridY, LevelPlayer* source) {
GridElement* ge; GridElement* ge;
...@@ -303,7 +406,7 @@ int Level::hitEvent (unsigned char gridX, unsigned char gridY, LevelPlayer* sour ...@@ -303,7 +406,7 @@ int Level::hitEvent (unsigned char gridX, unsigned char gridY, LevelPlayer* sour
ge = grid[gridY] + gridX; ge = grid[gridY] + gridX;
hitsToKill = eventSet[ge->event][E_HITSTOKILL]; hitsToKill = eventSet[ge->event].strength;
// If the event cannot be hit, return negative // If the event cannot be hit, return negative
if (!hitsToKill) return -1; if (!hitsToKill) return -1;
...@@ -339,12 +442,18 @@ int Level::hitEvent (unsigned char gridX, unsigned char gridY, LevelPlayer* sour ...@@ -339,12 +442,18 @@ int Level::hitEvent (unsigned char gridX, unsigned char gridY, LevelPlayer* sour
} }
// Return the number of hits remaining until the event is destroyed
return hitsToKill - ge->hits; return hitsToKill - ge->hits;
} }
/**
* Set the time of the event from the given tile.
*
* @param gridX X-coordinate of the tile
* @param gridY Y-coordinate of the tile
* @param time Time
*/
void Level::setEventTime (unsigned char gridX, unsigned char gridY, unsigned int time) { void Level::setEventTime (unsigned char gridX, unsigned char gridY, unsigned int time) {
grid[gridY][gridX].time = time; grid[gridY][gridX].time = time;
...@@ -354,6 +463,13 @@ void Level::setEventTime (unsigned char gridX, unsigned char gridY, unsigned int ...@@ -354,6 +463,13 @@ void Level::setEventTime (unsigned char gridX, unsigned char gridY, unsigned int
} }
/**
* Get the bullet data for the given bullet type.
*
* @param bullet Bullet type
*
* @return Bullet data
*/
signed char* Level::getBullet (unsigned char bullet) { signed char* Level::getBullet (unsigned char bullet) {
return bulletSet[bullet]; return bulletSet[bullet];
...@@ -361,6 +477,13 @@ signed char* Level::getBullet (unsigned char bullet) { ...@@ -361,6 +477,13 @@ signed char* Level::getBullet (unsigned char bullet) {
} }
/**
* Get a sprite.
*
* @param sprite Sprite number
*
* @return Sprite
*/
Sprite* Level::getSprite (unsigned char sprite) { Sprite* Level::getSprite (unsigned char sprite) {
return spriteSet + sprite; return spriteSet + sprite;
...@@ -368,6 +491,13 @@ Sprite* Level::getSprite (unsigned char sprite) { ...@@ -368,6 +491,13 @@ Sprite* Level::getSprite (unsigned char sprite) {
} }
/**
* Get an animation.
*
* @param anim Animation number
*
* @return Animation
*/
Anim* Level::getAnim (unsigned char anim) { Anim* Level::getAnim (unsigned char anim) {
return animSet + anim; return animSet + anim;
...@@ -375,6 +505,13 @@ Anim* Level::getAnim (unsigned char anim) { ...@@ -375,6 +505,13 @@ Anim* Level::getAnim (unsigned char anim) {
} }
/**
* Get a "miscellaneous" animation.
*
* @param anim Animation number
*
* @return Animation
*/
Anim* Level::getMiscAnim (unsigned char anim) { Anim* Level::getMiscAnim (unsigned char anim) {
return animSet + miscAnims[anim]; return animSet + miscAnims[anim];
...@@ -382,6 +519,11 @@ Anim* Level::getMiscAnim (unsigned char anim) { ...@@ -382,6 +519,11 @@ Anim* Level::getMiscAnim (unsigned char anim) {
} }
/**
* Set the water level.
*
* @param gridY New water level y-coordinate
*/
void Level::setWaterLevel (unsigned char gridY) { void Level::setWaterLevel (unsigned char gridY) {
unsigned char buffer[MTL_L_PROP]; unsigned char buffer[MTL_L_PROP];
...@@ -405,6 +547,11 @@ void Level::setWaterLevel (unsigned char gridY) { ...@@ -405,6 +547,11 @@ void Level::setWaterLevel (unsigned char gridY) {
} }
/**
* Determine the water level.
*
* @return The y-coordinate of the water level
*/
fixed Level::getWaterLevel () { fixed Level::getWaterLevel () {
return waterLevel; return waterLevel;
...@@ -412,6 +559,11 @@ fixed Level::getWaterLevel () { ...@@ -412,6 +559,11 @@ fixed Level::getWaterLevel () {
} }
/**
* Play a sound.
*
* @param sound Number of the sound to play
*/
void Level::playSound (int sound) { void Level::playSound (int sound) {
if (sound > 0) ::playSound(soundMap[sound - 1]); if (sound > 0) ::playSound(soundMap[sound - 1]);
...@@ -421,6 +573,14 @@ void Level::playSound (int sound) { ...@@ -421,6 +573,14 @@ void Level::playSound (int sound) {
} }
/**
* Start a flash palette effect.
*
* @param red Red component of flash colour
* @param green Green component of flash colour
* @param blue Blue component of flash colour
* @param duration Duration of the flash effect
*/
void Level::flash (unsigned char red, unsigned char green, unsigned char blue, int duration) { void Level::flash (unsigned char red, unsigned char green, unsigned char blue, int duration) {
paletteEffects = new FlashPaletteEffect(red, green, blue, duration, paletteEffects); paletteEffects = new FlashPaletteEffect(red, green, blue, duration, paletteEffects);
...@@ -430,6 +590,11 @@ void Level::flash (unsigned char red, unsigned char green, unsigned char blue, i ...@@ -430,6 +590,11 @@ void Level::flash (unsigned char red, unsigned char green, unsigned char blue, i
} }
/**
* Play the bonus level.
*
* @return Error code
*/
int Level::playBonus () { int Level::playBonus () {
Bonus *bonus; Bonus *bonus;
...@@ -519,6 +684,11 @@ void Level::receive (unsigned char* buffer) { ...@@ -519,6 +684,11 @@ void Level::receive (unsigned char* buffer) {
} }
/**
* Play the level.
*
* @return Error code
*/
int Level::play () { int Level::play () {
LevelPlayer* levelPlayer; LevelPlayer* levelPlayer;
......
...@@ -75,13 +75,35 @@ typedef struct { ...@@ -75,13 +75,35 @@ typedef struct {
} GridElement; } GridElement;
/// JJ1 level event type
typedef struct {
unsigned char anims[6]; ///< Indices of animations
signed char reflection; ///< Whether or not to show a reflection
signed char movement; ///< Movement type
signed char magnitude; ///< Usage depends on event type
signed char strength; ///< Number of hits required to destroy the event
signed char modifier; ///< Modifier
unsigned char points; ///< Points obtained by getting/destroying the event
unsigned char bullet; ///< Type of bullet the event fires
unsigned char bulletPeriod; ///< The time between successive bullet shots
unsigned char speed; ///< The speed at which the event moves
unsigned char animSpeed; ///< The speed of the event's animation
unsigned char sound; ///< The sound played on the appropriate trigger
signed char multiA; ///< Usage depends on event type
signed char multiB; ///< Usage depends on event type
signed char pieceSize; ///< Size of pieces in bridges, swinging balls chains, etc.
signed char pieces; ///< Number of pieces in bridges, swinging ball chains, etc.
signed char angle; ///< Initial angle of swinging balls, etc.
} EventType;
/// Pre-defined JJ1 event movement path /// Pre-defined JJ1 event movement path
typedef struct { typedef struct {
short int* x; ///< X-coordinates for each node short int* x; ///< X-coordinates for each node
short int* y; ///< Y-coordinates for each node short int* y; ///< Y-coordinates for each node
unsigned char length; ///< Number of nodes unsigned char length; ///< Number of nodes
unsigned char node; ///< Current node
} EventPath; } EventPath;
...@@ -108,17 +130,17 @@ class Level : public BaseLevel { ...@@ -108,17 +130,17 @@ class Level : public BaseLevel {
Anim animSet[ANIMS]; ///< Animations Anim animSet[ANIMS]; ///< Animations
char miscAnims[4]; ///< Further animations char miscAnims[4]; ///< Further animations
signed char bulletSet[BULLETS][BLENGTH]; ///< Bullet types signed char bulletSet[BULLETS][BLENGTH]; ///< Bullet types
signed char eventSet[EVENTS][ELENGTH]; ///< Event types EventType eventSet[EVENTS]; ///< Event types
char mask[240][64]; ///< Tile masks. At most 240 tiles, all with 8 * 8 masks char mask[240][64]; ///< Tile masks. At most 240 tiles, all with 8 * 8 masks
GridElement grid[LH][LW]; ///< Level grid. All levels are the same size GridElement grid[LH][LW]; ///< Level grid. All levels are the same size
int soundMap[32]; ///< Maps event sound effect numbers to actual sound effect indices int soundMap[32]; ///< Maps event sound effect numbers to actual sound effect indices
SDL_Color skyPalette[256]; ///< Full palette for sky background SDL_Color skyPalette[256]; ///< Full palette for sky background
bool sky; ///< Whether or not to use sky background bool sky; ///< Whether or not to use sky background
unsigned char skyOrb; ///< The tile to use as the background sun/moon/etc. unsigned char skyOrb; ///< The tile to use as the background sun/moon/etc.
int levelNum; ///< int levelNum; ///< Number of current level
int worldNum; ///< int worldNum; ///< Number of current world
int nextLevelNum; ///< int nextLevelNum; ///< Number of next level
int nextWorldNum; ///< int nextWorldNum; ///< Number of next world
unsigned char difficulty; ///< Difficulty setting (0 = easy, 1 = medium, 2 = hard, 3 = turbo) unsigned char difficulty; ///< Difficulty setting (0 = easy, 1 = medium, 2 = hard, 3 = turbo)
int enemies; ///< Number of enemies to kill int enemies; ///< Number of enemies to kill
fixed waterLevel; ///< Height of water fixed waterLevel; ///< Height of water
...@@ -136,6 +158,8 @@ class Level : public BaseLevel { ...@@ -136,6 +158,8 @@ class Level : public BaseLevel {
protected: protected:
Font* font; ///< On-screen message font Font* font; ///< On-screen message font
Level ();
int load (char* fileName, unsigned char diff, bool checkpoint); int load (char* fileName, unsigned char diff, bool checkpoint);
int step (); int step ();
void draw (); void draw ();
...@@ -144,7 +168,6 @@ class Level : public BaseLevel { ...@@ -144,7 +168,6 @@ class Level : public BaseLevel {
Bullet* bullets; ///< Active bullets Bullet* bullets; ///< Active bullets
EventPath path[PATHS]; ///< Pre-defined event movement paths EventPath path[PATHS]; ///< Pre-defined event movement paths
Level ();
Level (char* fileName, unsigned char diff, bool checkpoint, bool multi); Level (char* fileName, unsigned char diff, bool checkpoint, bool multi);
virtual ~Level (); virtual ~Level ();
...@@ -155,7 +178,7 @@ class Level : public BaseLevel { ...@@ -155,7 +178,7 @@ class Level : public BaseLevel {
void setNext (int nextLevel, int nextWorld); void setNext (int nextLevel, int nextWorld);
void setTile (unsigned char gridX, unsigned char gridY, unsigned char tile); void setTile (unsigned char gridX, unsigned char gridY, unsigned char tile);
Event* getEvents (); Event* getEvents ();
signed char* getEvent (unsigned char gridX, unsigned char gridY); EventType* getEvent (unsigned char gridX, unsigned char gridY);
unsigned char getEventHits (unsigned char gridX, unsigned char gridY); unsigned char getEventHits (unsigned char gridX, unsigned char gridY);
unsigned int getEventTime (unsigned char gridX, unsigned char gridY); unsigned int getEventTime (unsigned char gridX, unsigned char gridY);
void clearEvent (unsigned char gridX, unsigned char gridY); void clearEvent (unsigned char gridX, unsigned char gridY);
......
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#include "util.h" #include "util.h"
/**
* Level iteration.
*
* @return Error code
*/
int Level::step () { int Level::step () {
Event *event; Event *event;
...@@ -75,7 +80,7 @@ int Level::step () { ...@@ -75,7 +80,7 @@ int Level::step () {
// If the event wasn't found, create it // If the event wasn't found, create it
if (!event) { if (!event) {
switch (getEvent(x, y)[E_BEHAVIOUR]) { switch (getEvent(x, y)->movement) {
case 28: case 28:
...@@ -97,7 +102,7 @@ int Level::step () { ...@@ -97,7 +102,7 @@ int Level::step () {
default: default:
events = new Event(x, y); events = new StandardEvent(x, y);
break; break;
...@@ -118,8 +123,6 @@ int Level::step () { ...@@ -118,8 +123,6 @@ int Level::step () {
// Process active events // Process active events
for (x = 0; x < PATHS; x++) path[x].node = (ticks >> 5) % path[x].length;
if (events) events = events->step(ticks, msps); if (events) events = events->step(ticks, msps);
...@@ -179,6 +182,9 @@ int Level::step () { ...@@ -179,6 +182,9 @@ int Level::step () {
/**
* Draw the level.
*/
void Level::draw () { void Level::draw () {
GridElement *ge; GridElement *ge;
...@@ -260,7 +266,7 @@ void Level::draw () { ...@@ -260,7 +266,7 @@ void Level::draw () {
// If this is not a foreground tile, draw it // If this is not a foreground tile, draw it
if ((eventSet[ge->event][E_BEHAVIOUR] != 38) && if ((eventSet[ge->event].movement != 38) &&
((ge->event < 124) || (ge->event > 125)) ) { ((ge->event < 124) || (ge->event > 125)) ) {
dst.x = TTOI(x) - (vX & 31); dst.x = TTOI(x) - (vX & 31);
...@@ -306,15 +312,15 @@ void Level::draw () { ...@@ -306,15 +312,15 @@ void Level::draw () {
dst.x = TTOI(x) - (vX & 31); dst.x = TTOI(x) - (vX & 31);
dst.y = TTOI(y) - (vY & 31); dst.y = TTOI(y) - (vY & 31);
if (ticks & 64) src.y = TTOI(eventSet[ge->event][E_YAXIS]); if (ticks & 64) src.y = TTOI(eventSet[ge->event].multiB);
else src.y = TTOI(eventSet[ge->event][E_MULTIPURPOSE]); else src.y = TTOI(eventSet[ge->event].multiA);
SDL_BlitSurface(tileSet, &src, canvas, &dst); SDL_BlitSurface(tileSet, &src, canvas, &dst);
} }
// If this is a foreground tile, draw it // If this is a foreground tile, draw it
if ((ge->event == 124) || (ge->event == 125) || if ((ge->event == 124) || (ge->event == 125) ||
(eventSet[ge->event][E_BEHAVIOUR] == 38) ) { (eventSet[ge->event].movement == 38) ) {
dst.x = TTOI(x) - (vX & 31); dst.x = TTOI(x) - (vX & 31);
dst.y = TTOI(y) - (vY & 31); dst.y = TTOI(y) - (vY & 31);
......
...@@ -50,6 +50,11 @@ ...@@ -50,6 +50,11 @@
#define SKEY 254 /* Sprite colour key */ #define SKEY 254 /* Sprite colour key */
/**
* Load the HUD graphical data.
*
* @return Error code
*/
int Level::loadPanel () { int Level::loadPanel () {
File* file; File* file;
...@@ -139,6 +144,12 @@ int Level::loadPanel () { ...@@ -139,6 +144,12 @@ int Level::loadPanel () {
} }
/**
* Load a sprite.
*
* @param file File from which to load the sprite data
* @param sprite Sprite that will receive the loaded data
*/
void Level::loadSprite (File* file, Sprite* sprite) { void Level::loadSprite (File* file, Sprite* sprite) {
unsigned char* pixels; unsigned char* pixels;
...@@ -194,6 +205,13 @@ void Level::loadSprite (File* file, Sprite* sprite) { ...@@ -194,6 +205,13 @@ void Level::loadSprite (File* file, Sprite* sprite) {
} }
/**
* Load sprites.
*
* @param fileName Name of the file containing the level-specific sprites
*
* @return Error code
*/
int Level::loadSprites (char * fileName) { int Level::loadSprites (char * fileName) {
File* mainFile = NULL; File* mainFile = NULL;
...@@ -318,6 +336,13 @@ int Level::loadSprites (char * fileName) { ...@@ -318,6 +336,13 @@ int Level::loadSprites (char * fileName) {
} }
/**
* Load the tileset.
*
* @param fileName Name of the file containing the tileset
*
* @return The number of tiles loaded
*/
int Level::loadTiles (char* fileName) { int Level::loadTiles (char* fileName) {
File* file; File* file;
...@@ -409,13 +434,22 @@ int Level::loadTiles (char* fileName) { ...@@ -409,13 +434,22 @@ int Level::loadTiles (char* fileName) {
} }
/**
* Load the level.
*
* @param fileName Name of the file containing the level data
* @param diff Difficulty level
* @param checkpoint Whether or not the player(s) will start at a checkpoint
*
* @return Error code
*/
int Level::load (char* fileName, unsigned char diff, bool checkpoint) { int Level::load (char* fileName, unsigned char diff, bool checkpoint) {
Anim* pAnims[PANIMS]; Anim* pAnims[PANIMS];
File* file; File* file;
unsigned char* buffer; unsigned char* buffer;
const char* ext; const char* ext;
char* string; char* string = NULL;
int tiles; int tiles;
int count, x, y, type; int count, x, y, type;
unsigned char startX, startY; unsigned char startX, startY;
...@@ -705,7 +739,6 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) { ...@@ -705,7 +739,6 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) {
for (type = 0; type < PATHS; type++) { for (type = 0; type < PATHS; type++) {
path[type].length = buffer[type << 9] + (buffer[(type << 9) + 1] << 8); path[type].length = buffer[type << 9] + (buffer[(type << 9) + 1] << 8);
path[type].node = 0;
if (path[type].length < 1) path[type].length = 1; if (path[type].length < 1) path[type].length = 1;
path[type].x = new short int[path[type].length]; path[type].x = new short int[path[type].length];
path[type].y = new short int[path[type].length]; path[type].y = new short int[path[type].length];
...@@ -729,14 +762,31 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) { ...@@ -729,14 +762,31 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) {
// Fill event set with data // Fill event set with data
for (count = 0; count < EVENTS; count++) { for (count = 0; count < EVENTS; count++) {
memcpy(eventSet[count], buffer + (count * ELENGTH), ELENGTH); eventSet[count].anims[0] = buffer[(count * ELENGTH) + 5];
eventSet[count][E_MOVEMENTSP]++; eventSet[count].anims[1] = buffer[(count * ELENGTH) + 6];
eventSet[count].anims[2] = buffer[(count * ELENGTH) + 28];
eventSet[count].anims[3] = buffer[(count * ELENGTH) + 29];
eventSet[count].anims[4] = buffer[(count * ELENGTH) + 30];
eventSet[count].anims[5] = buffer[(count * ELENGTH) + 31];
eventSet[count].reflection = buffer[(count * ELENGTH) + 2];
eventSet[count].movement = buffer[(count * ELENGTH) + 4];
eventSet[count].magnitude = buffer[(count * ELENGTH) + 8];
eventSet[count].strength = buffer[(count * ELENGTH) + 9];
eventSet[count].modifier = buffer[(count * ELENGTH) + 10];
eventSet[count].points = buffer[(count * ELENGTH) + 11];
eventSet[count].bullet = buffer[(count * ELENGTH) + 12];
eventSet[count].bulletPeriod = buffer[(count * ELENGTH) + 13];
eventSet[count].speed = buffer[(count * ELENGTH) + 15] + 1;
eventSet[count].animSpeed = buffer[(count * ELENGTH) + 17] + 1;
eventSet[count].sound = buffer[(count * ELENGTH) + 21];
eventSet[count].multiA = buffer[(count * ELENGTH) + 22];
eventSet[count].multiB = buffer[(count * ELENGTH) + 23];
eventSet[count].pieceSize = buffer[(count * ELENGTH) + 24];
eventSet[count].pieces = buffer[(count * ELENGTH) + 25];
eventSet[count].angle = buffer[(count * ELENGTH) + 26];
} }
delete[] buffer;
// Process grid // Process grid
enemies = items = 0; enemies = items = 0;
...@@ -750,12 +800,12 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) { ...@@ -750,12 +800,12 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) {
if (type) { if (type) {
// Eliminate event references for events of too high a difficulty // Eliminate event references for events of too high a difficulty
if (eventSet[type][E_DIFFICULTY] > difficulty) grid[y][x].event = 0; if (buffer[type * ELENGTH] > difficulty) grid[y][x].event = 0;
// If the event hurts and can be killed, it is an enemy // If the event hurts and can be killed, it is an enemy
// Anything else that scores is an item // Anything else that scores is an item
if ((eventSet[type][E_MODIFIER] == 0) && eventSet[type][E_HITSTOKILL]) enemies++; if ((eventSet[type].modifier == 0) && eventSet[type].strength) enemies++;
else if (eventSet[type][E_ADDEDSCORE]) items++; else if (eventSet[type].points) items++;
} }
...@@ -763,6 +813,8 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) { ...@@ -763,6 +813,8 @@ int Level::load (char* fileName, unsigned char diff, bool checkpoint) {
} }
delete[] buffer;
// Yet more doubtless essential data // Yet more doubtless essential data
file->skipRLE(); file->skipRLE();
......
This diff is collapsed.
...@@ -43,7 +43,10 @@ ...@@ -43,7 +43,10 @@
/** /**
* Respond to controls, unless the player has been killed * Respond to controls, unless the player has been killed.
*
* @param ticks Time
* @param msps Ticks per step
*/ */
void LevelPlayer::control (unsigned int ticks, int msps) { void LevelPlayer::control (unsigned int ticks, int msps) {
...@@ -159,7 +162,7 @@ void LevelPlayer::control (unsigned int ticks, int msps) { ...@@ -159,7 +162,7 @@ void LevelPlayer::control (unsigned int ticks, int msps) {
if (event != LPE_NONE) { if (event != LPE_NONE) {
if (event == LPE_SPRING) dy = level->getEvent(eventX, eventY)[E_MULTIPURPOSE] * -F20; if (event == LPE_SPRING) dy = level->getEvent(eventX, eventY)->multiA * -F20;
else if (event == LPE_FLOAT) dy = PYS_JUMP; else if (event == LPE_FLOAT) dy = PYS_JUMP;
} }
...@@ -241,7 +244,7 @@ void LevelPlayer::control (unsigned int ticks, int msps) { ...@@ -241,7 +244,7 @@ void LevelPlayer::control (unsigned int ticks, int msps) {
// Spring/float up speed limit // Spring/float up speed limit
if ((event == LPE_SPRING) || (event == LPE_FLOAT)) { if ((event == LPE_SPRING) || (event == LPE_FLOAT)) {
speed = level->getEvent(eventX, eventY)[E_MULTIPURPOSE] * -F20; speed = level->getEvent(eventX, eventY)->multiA * -F20;
if (speed >= 0) speed = PYS_JUMP; if (speed >= 0) speed = PYS_JUMP;
...@@ -412,7 +415,13 @@ void LevelPlayer::control (unsigned int ticks, int msps) { ...@@ -412,7 +415,13 @@ void LevelPlayer::control (unsigned int ticks, int msps) {
} }
/**
* Move the player.
*
* @param ticks Time
* @param msps Ticks per step
*/
void LevelPlayer::move (unsigned int ticks, int msps) { void LevelPlayer::move (unsigned int ticks, int msps) {
fixed pdx, pdy; fixed pdx, pdy;
...@@ -621,7 +630,10 @@ void LevelPlayer::move (unsigned int ticks, int msps) { ...@@ -621,7 +630,10 @@ void LevelPlayer::move (unsigned int ticks, int msps) {
/** /**
* Calculate viewport * Calculate viewport.
*
* @param ticks Time
* @param mspf Ticks per frame
*/ */
void LevelPlayer::view (unsigned int ticks, int mspf) { void LevelPlayer::view (unsigned int ticks, int mspf) {
...@@ -669,7 +681,13 @@ void LevelPlayer::view (unsigned int ticks, int mspf) { ...@@ -669,7 +681,13 @@ void LevelPlayer::view (unsigned int ticks, int mspf) {
return; return;
} }
/**
* Draw the player.
*
* @param ticks Time
* @param change Time since last step
*/
void LevelPlayer::draw (unsigned int ticks, int change) { void LevelPlayer::draw (unsigned int ticks, int change) {
Anim *an; Anim *an;
......
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