Commit db07689d authored by AlisterT's avatar AlisterT

Event refactoring, bug fixes.

parent 6e631c48
......@@ -8,7 +8,7 @@
* Part of the OpenJazz project
*
*
* Copyright (c) 2005-2009 Alister Thomson
* Copyright (c) 2005-2010 Alister Thomson
*
* OpenJazz is distributed under the terms of
* the GNU General Public License, version 2.0
......@@ -42,10 +42,12 @@ Anim::~Anim () {
}
void Anim::setData (int amount, signed char x, signed char y) {
void Anim::setData (int amount, signed char sX, signed char sY, signed char x, signed char y) {
frames = amount;
xOffset = x << 2;
shootX = sX;
shootY = sY;
xOffset = x;
yOffset = y;
return;
......@@ -66,7 +68,7 @@ void Anim::setFrame (int nextFrame, bool looping) {
void Anim::setFrameData (Sprite *sprite, signed char x, signed char y) {
sprites[frame] = sprite;
xOffsets[frame] = x << 2;
xOffsets[frame] = x;
yOffsets[frame] = y;
return;
......@@ -81,14 +83,28 @@ int Anim::getWidth () {
}
int Anim::getHeight() {
int Anim::getHeight () {
return sprites[frame]->getHeight();
}
void Anim::draw (int x, int y) {
fixed Anim::getShootX () {
return ITOF(shootX + xOffsets[frame] - xOffset);
}
fixed Anim::getShootY () {
return ITOF(shootY + yOffsets[frame] - yOffset);
}
void Anim::draw (fixed x, fixed y) {
sprites[frame]->draw(FTOI(x) + xOffsets[frame] - xOffset - FTOI(viewX),
FTOI(y) + yOffsets[frame] - yOffset - FTOI(viewY));
......
......@@ -8,7 +8,7 @@
* Part of the OpenJazz project
*
*
* Copyright (c) 2005-2009 Alister Thomson
* Copyright (c) 2005-2010 Alister Thomson
*
* OpenJazz is distributed under the terms of
* the GNU General Public License, version 2.0
......@@ -24,6 +24,8 @@
#define _ANIM_H
#include "OpenJazz.h"
#include <SDL/SDL.h>
......@@ -35,6 +37,8 @@ class Anim {
private:
Sprite *sprites[19];
signed char shootX;
signed char shootY;
signed char xOffset;
signed char yOffset;
signed char xOffsets[19];
......@@ -46,15 +50,17 @@ class Anim {
Anim ();
~Anim ();
void setData (int amount, signed char x, signed char y);
void setFrame (int nextFrame, bool looping);
void setFrameData (Sprite *frameSprite, signed char x, signed char y);
int getWidth ();
int getHeight ();
void draw (int x, int y);
void setPalette (SDL_Color *palette, int start, int amount);
void flashPalette (int index);
void restorePalette ();
void setData (int amount, signed char sX, signed char sY, signed char x, signed char y);
void setFrame (int nextFrame, bool looping);
void setFrameData (Sprite *frameSprite, signed char x, signed char y);
int getWidth ();
int getHeight ();
fixed getShootX ();
fixed getShootY ();
void draw (fixed x, fixed y);
void setPalette (SDL_Color *palette, int start, int amount);
void flashPalette (int index);
void restorePalette ();
};
......
......@@ -82,6 +82,8 @@ Bullet::Bullet (Player *sourcePlayer, bool lower, unsigned int ticks) {
Bullet::Bullet (Event *sourceEvent, bool facing, unsigned int ticks) {
Anim *anim;
// Properties based on the event
next = level->firstBullet;
......@@ -89,8 +91,9 @@ Bullet::Bullet (Event *sourceEvent, bool facing, unsigned int ticks) {
type = sourceEvent->getProperty(E_BULLET);
direction = facing? 1: 0;
x = sourceEvent->getX() + (sourceEvent->getWidth() >> 1);
y = sourceEvent->getY() - (sourceEvent->getHeight() >> 1);
anim = level->getAnim(sourceEvent->getProperty(facing? E_LSHOOTANIM: E_RSHOOTANIM));
x = sourceEvent->getX() + anim->getShootX();
y = sourceEvent->getY() + anim->getShootY();
dx = level->getBullet(type)[B_XSPEED + direction] * 500 * F1;
dy = level->getBullet(type)[B_YSPEED + direction] * 250 * F1;
time = ticks + T_BULLET;
......@@ -193,7 +196,7 @@ bool Bullet::step (unsigned int ticks, int msps) {
// If the time has expired, destroy the bullet
if (ticks > time) {
// If the bullet is TNT, destroy all destructible events nearby
// If the bullet is TNT, hit all destructible events nearby twice
if (type == -1) {
event = level->firstEvent;
......@@ -201,8 +204,12 @@ bool Bullet::step (unsigned int ticks, int msps) {
while (event) {
// If the event is within range, hit it
if (event->overlap(x - F160, y - F100, 2 * F160, 2 * F100))
event->hit(source, true, ticks);
if (event->overlap(x - F160, y - F100, 2 * F160, 2 * F100)) {
event->hit(source, ticks);
event->hit(source, ticks);
}
event = event->getNext();
......@@ -245,7 +252,7 @@ bool Bullet::step (unsigned int ticks, int msps) {
if (event->overlap(x, y, 0, 0)) {
// If the event is hittable, hit it and destroy the bullet
if (event->hit(source, false, ticks)) return true;
if (event->hit(source, ticks)) return true;
}
......
/*
*
* guardians.cpp
*
* 2nd March 2010: Created bridge.cpp from parts of event.cpp and eventframe.cpp
*
* Part of the OpenJazz project
*
*
* Copyright (c) 2005-2010 Alister Thomson
*
* OpenJazz is distributed under the terms of
* the GNU General Public License, version 2.0
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/*
* Provides the functions of bridge events.
*
*/
#include "../level.h"
#include "event.h"
#include "player/player.h"
Bridge::Bridge (unsigned char gX, unsigned char gY, Event *nextEvent) {
x = TTOF(gX);
y = TTOF(gY + 1);
dx = 0;
dy = 0;
next = nextEvent;
gridX = gX;
gridY = gY;
flashTime = 0;
animType = E_LEFTANIM;
x -= F2;
y += ITOF(getProperty(E_YAXIS)) - F40;
// dx and dy used to store leftmost and rightmost player on bridge
// Start with minimum values
dx = getProperty(E_MULTIPURPOSE) * F8;
dy = 0;
return;
}
bool Bridge::step (unsigned int ticks, int msps) {
signed char *set;
int count;
fixed offset;
set = prepareStep(ticks, msps);
if (!set) return true;
// Gradually stop the bridge sagging
if (dx < set[E_MULTIPURPOSE] * F8) dx += 320 * msps;
if (dx > set[E_MULTIPURPOSE] * F8) dx = set[E_MULTIPURPOSE] * F8;
if (dy > 0) dy -= 320 * msps;
if (dy < 0) dy = 0;
for (count = 0; count < nPlayers; count++) {
offset = players[count].getX() + PXO_MID;
if (players[count].overlap(x, y, set[E_MULTIPURPOSE] * F8, F8) &&
!level->checkMaskDown(offset, y - F32)) {
// Player is on the bridge
players[count].setEvent(gridX, gridY);
offset -= x;
if (offset < dx) dx = offset;
if ((offset > dy) && (offset < set[E_MULTIPURPOSE] * F8)) dy = offset;
if (offset < set[E_MULTIPURPOSE] * F4)
players[count].setPosition(players[count].getX(), y + (offset >> 3) - F8);
else
players[count].setPosition(players[count].getX(), y + (set[E_MULTIPURPOSE] * F1) - (offset >> 3) - F8);
} else players[count].clearEvent(gridX, gridY);
}
return false;
}
void Bridge::draw (unsigned int ticks, int change) {
Anim *anim;
signed char *set;
int count;
fixed bridgeLength, dipA, dipB;
// Get the event properties
set = level->getEvent(gridX, gridY);
// If the event has been removed from the grid, do not show it
if (!set) return;
// Check if the event has anything to draw
if (!animType || (set[animType] < 0)) return;
if ((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM))
frame = (ticks + T_FINISH - level->getEventTime(gridX, gridY)) / 40;
else if (set[E_ANIMSP])
frame = ticks / (set[E_ANIMSP] * 40);
else
frame = ticks / 20;
anim = level->getAnim(set[animType]);
anim->setFrame(frame + gridX + gridY, true);
// Draw the bridge
bridgeLength = set[E_MULTIPURPOSE] * F8;
if (dy >= dx) {
dipA = (dx <= (bridgeLength >> 1)) ? dx >> 3: (bridgeLength - dx) >> 3;
dipB = (dy <= (bridgeLength >> 1)) ? dy >> 3: (bridgeLength - dy) >> 3;
for (count = 0; count < bridgeLength; count += F8) {
if (count < dx)
anim->draw(x + count, y + (count * dipA / dx));
else if (count < dy)
anim->draw(x + count, y + dipA + ((count - dx) * (dipB - dipA) / (dy - dx)));
else
anim->draw(x + count, y + ((bridgeLength - count) * dipB / (bridgeLength - dy)));
}
} else {
// No players on the bridge, de-sagging in progress
dipA = (dx + dy) >> 1;
dipB = (dy < bridgeLength - dx) ? dy >> 3: (bridgeLength - dx) >> 3;
for (count = 0; count < bridgeLength; count += F8) {
if (count < dipA)
anim->draw(x + count, y + (count * dipB / dipA));
else
anim->draw(x + count, y + ((bridgeLength - count) * dipB / (bridgeLength - dipA)));
}
}
return;
}
......@@ -11,6 +11,8 @@
* 19th March 2009: Created sprite.cpp from parts of event.cpp and player.cpp
* 19th July 2009: Created eventframe.cpp from parts of events.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 bridge.cpp from parts of event.cpp and eventframe.cpp
*
* Part of the OpenJazz project
*
......@@ -41,6 +43,13 @@
#include <math.h>
Event::Event () {
return;
}
Event::Event (unsigned char gX, unsigned char gY, Event *nextEvent) {
x = TTOF(gX);
......@@ -53,8 +62,6 @@ Event::Event (unsigned char gX, unsigned char gY, Event *nextEvent) {
gridY = gY;
flashTime = 0;
// Choose initial settings
switch (getProperty(E_BEHAVIOUR)) {
case 21: // Destructible block
......@@ -74,19 +81,6 @@ Event::Event (unsigned char gX, unsigned char gY, Event *nextEvent) {
break;
case 28:
animType = E_LEFTANIM;
x -= F2;
y += ITOF(getProperty(E_YAXIS)) - F40;
// dx and dy used to store leftmost and rightmost player on bridge
// Start with minimum values
dx = getProperty(E_MULTIPURPOSE) * F8;
dy = 0;
break;
default:
animType = E_LEFTANIM;
......@@ -100,13 +94,6 @@ Event::Event (unsigned char gX, unsigned char gY, Event *nextEvent) {
}
Event::~Event () {
return;
}
Event * Event::getNext () {
return next;
......@@ -145,7 +132,7 @@ void Event::destroy (unsigned int ticks) {
}
bool Event::hit (Player *source, bool TNT, unsigned int ticks) {
bool Event::hit (Player *source, unsigned int ticks) {
int hitsRemaining;
......@@ -155,7 +142,7 @@ bool Event::hit (Player *source, bool TNT, unsigned int ticks) {
if ((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM) ||
(ticks < flashTime)) return false;
hitsRemaining = level->hitEvent(gridX, gridY, source, TNT);
hitsRemaining = level->hitEvent(gridX, gridY, source);
// If the event cannot be hit, do not register hit
if (hitsRemaining < 0) return false;
......@@ -172,6 +159,17 @@ bool Event::hit (Player *source, bool TNT, unsigned int ticks) {
}
bool Event::isEnemy () {
signed char *set;
set = level->getEvent(gridX, gridY);
return set[E_HITSTOKILL] && (set[E_MODIFIER] == 0);
}
bool Event::isFrom (unsigned char gX, unsigned char gY) {
return (gX == gridX) && (gY == gridY);
......
......@@ -7,6 +7,7 @@
* 11th February 2009: Created bullet.h from parts of events.h
* 1st March 2009: Created bird.h from parts of events.h
* 19th July 2009: Renamed events.h to event.h
* 2nd March 2010: Created guardians.h from parts of event.h
*
* Part of the OpenJazz project
*
......@@ -23,8 +24,8 @@
*/
#ifndef _EVENTS_H
#define _EVENTS_H
#ifndef _EVENT_H
#define _EVENT_H
#include "movable.h"
......@@ -68,8 +69,8 @@
#define T_SHOOT 300
// Speed factors
#define ES_SLOW 80
#define ES_FAST 240
#define ES_SLOW ITOF(80)
#define ES_FAST ITOF(240)
// Classes
......@@ -78,31 +79,42 @@ class Player;
class Event : public Movable {
private:
protected:
Event *next;
unsigned char gridX, gridY; // Grid position of the event
unsigned char animType; // E_LEFTANIM, etc, or 0
unsigned char frame;
unsigned int flashTime;
void destroy (unsigned int ticks);
Event ();
void destroy (unsigned int ticks);
fixed getWidth ();
fixed getHeight ();
signed char * prepareStep (unsigned int ticks, int msps);
public:
Event (unsigned char gX, unsigned char gY,
Event *nextEvent);
~Event ();
Event * getNext ();
void removeNext ();
bool hit (Player *source, bool TNT, unsigned int ticks);
bool isFrom (unsigned char gX, unsigned char gY);
fixed getWidth ();
fixed getHeight ();
bool overlap (fixed left, fixed top, fixed width,
fixed height);
signed char getProperty (unsigned char property);
bool step (unsigned int ticks, int msps);
void draw (unsigned int ticks, int change);
Event (unsigned char gX, unsigned char gY, Event *nextEvent);
Event * getNext ();
void removeNext ();
bool hit (Player *source, unsigned int ticks);
bool isEnemy ();
bool isFrom (unsigned char gX, unsigned char gY);
virtual bool overlap (fixed left, fixed top, fixed width, fixed height);
signed char getProperty (unsigned char property);
virtual bool step (unsigned int ticks, int msps);
virtual void draw (unsigned int ticks, int change);
};
class Bridge : public Event {
public:
Bridge (unsigned char gX, unsigned char gY, Event *nextEvent);
bool step (unsigned int ticks, int msps);
void draw (unsigned int ticks, int change);
};
......
......@@ -4,6 +4,8 @@
* eventframe.cpp
*
* 19th July 2009: Created eventframe.cpp from parts of events.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
*
* Part of the OpenJazz project
*
......@@ -20,7 +22,7 @@
*/
/*
* Provides the once-per-frame functions of events.
* Provides the once-per-frame functions of ordinary events.
*
*/
......@@ -36,13 +38,9 @@
#include <math.h>
bool Event::step (unsigned int ticks, int msps) {
signed char * Event::prepareStep (unsigned int ticks, int msps) {
fixed width, height;
signed char *set;
int count;
fixed offset;
float angle;
// Process the next event
if (next) {
......@@ -56,7 +54,7 @@ bool Event::step (unsigned int ticks, int msps) {
set = level->getEvent(gridX, gridY);
// If the event has been removed from the grid, destroy it
if (!set) return true;
if (!set) return NULL;
// If the event and its origin are off-screen, the event is not in the
......@@ -67,7 +65,7 @@ bool Event::step (unsigned int ticks, int msps) {
((gridX < FTOT(viewX) - 1) ||
(gridX > ITOT(FTOI(viewX) + viewW) + 1) ||
(gridY < FTOT(viewY) - 1) ||
(gridY > ITOT(FTOI(viewY) + viewH) + 1))) return true;
(gridY > ITOT(FTOI(viewY) + viewH) + 1))) return NULL;
// Find frame
......@@ -77,10 +75,29 @@ bool Event::step (unsigned int ticks, int msps) {
frame = (ticks + T_FINISH - level->getEventTime(gridX, gridY)) / 40;
else if (set[E_ANIMSP])
frame = ticks / (set[E_ANIMSP] * 40);
else frame = ticks / 40;
else
frame = ticks / 20;
}
return set;
}
bool Event::step (unsigned int ticks, int msps) {
fixed width, height;
signed char *set;
int count;
fixed offset;
float angle;
set = prepareStep(ticks, msps);
if (!set) return true;
// Find dimensions
width = getWidth();
......@@ -94,17 +111,15 @@ bool Event::step (unsigned int ticks, int msps) {
case 1:
// Sink down
dy = ES_FAST * msps / set[E_MOVEMENTSP];
dy = ES_FAST;
break;
case 2:
// Walk from side to side
if (animType == E_LEFTANIM)
dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dx = ES_FAST * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_FAST;
else if (animType == E_RIGHTANIM) dx = ES_FAST;
else dx = 0;
break;
......@@ -112,10 +127,8 @@ bool Event::step (unsigned int ticks, int msps) {
case 3:
// Seek jazz
if (localPlayer->getX() + PXO_R < x)
dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else if (localPlayer->getX() + PXO_L > x + width)
dx = ES_FAST * msps / set[E_MOVEMENTSP];
if (localPlayer->getX() + PXO_R < x) dx = -ES_FAST;
else if (localPlayer->getX() + PXO_L > x + width) dx = ES_FAST;
else dx = 0;
break;
......@@ -128,15 +141,13 @@ bool Event::step (unsigned int ticks, int msps) {
// Fall downwards
dx = 0;
dy = ES_FAST * msps / set[E_MOVEMENTSP];
dy = ES_FAST;
} else {
// Walk from side to side
if (animType == E_LEFTANIM)
dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dx = ES_FAST * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_FAST;
else if (animType == E_RIGHTANIM) dx = ES_FAST;
dy = 0;
......@@ -155,16 +166,16 @@ bool Event::step (unsigned int ticks, int msps) {
// Use the path from the level file
dx = TTOF(gridX) + F16 + (level->pathX[level->pathNode] << 9) - x;
dy = TTOF(gridY) + (level->pathY[level->pathNode] << 9) - y;
dx = ((dx << 10) / msps) * set[E_MOVEMENTSP];
dy = ((dy << 10) / msps) * set[E_MOVEMENTSP];
break;
case 7:
// Move back and forth horizontally with tail
if (animType == E_LEFTANIM)
dx = -ES_SLOW * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dx = ES_SLOW * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_SLOW;
else if (animType == E_RIGHTANIM) dx = ES_SLOW;
break;
......@@ -189,8 +200,7 @@ bool Event::step (unsigned int ticks, int msps) {
case 11:
// Sink to ground
if (!level->checkMaskDown(x + (width >> 1), y))
dy = ES_FAST * msps / set[E_MOVEMENTSP];
if (!level->checkMaskDown(x + (width >> 1), y)) dy = ES_FAST;
else dy = 0;
break;
......@@ -198,10 +208,8 @@ bool Event::step (unsigned int ticks, int msps) {
case 12:
// Move back and forth horizontally
if (animType == E_LEFTANIM)
dx = -ES_SLOW * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dx = ES_SLOW * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_SLOW;
else if (animType == E_RIGHTANIM) dx = ES_SLOW;
else dx = 0;
break;
......@@ -209,10 +217,8 @@ bool Event::step (unsigned int ticks, int msps) {
case 13:
// Move up and down
if (animType == E_LEFTANIM)
dy = -ES_SLOW * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dy = ES_SLOW * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dy = -ES_SLOW;
else if (animType == E_RIGHTANIM) dy = ES_SLOW;
else dy = 0;
break;
......@@ -232,8 +238,8 @@ bool Event::step (unsigned int ticks, int msps) {
case 16:
// Move across level to the left or right
if (set[E_MAGNITUDE] == 0) dx = -ES_SLOW * msps / set[E_MOVEMENTSP];
else dx = set[E_MAGNITUDE] * ES_SLOW * msps / set[E_MOVEMENTSP];
if (set[E_MAGNITUDE] == 0) dx = -ES_SLOW;
else dx = set[E_MAGNITUDE] * ES_SLOW;
break;
......@@ -287,24 +293,6 @@ bool Event::step (unsigned int ticks, int msps) {
break;
case 25:
// Float up / Belt
for (count = 0; count < nPlayers; count++) {
if (players[count].overlap(x, y - height, width, height)) {
if (set[E_YAXIS]) players[count].floatUp(set, msps);
players[count].belt(set[E_MAGNITUDE] * msps);
}
}
break;
case 26:
// TODO: Find out what this is
......@@ -317,51 +305,6 @@ bool Event::step (unsigned int ticks, int msps) {
break;
case 28:
// Bridge
// Gradually stop the bridge sagging
if (dx < set[E_MULTIPURPOSE] * F8) dx += 320 * msps;
if (dx > set[E_MULTIPURPOSE] * F8) dx = set[E_MULTIPURPOSE] * F8;
if (dy > 0) dy -= 320 * msps;
if (dy < 0) dy = 0;
for (count = 0; count < nPlayers; count++) {
if (players[count].overlap(x, y, set[E_MULTIPURPOSE] * F8,
F8)) {
offset = players[count].getX() + PXO_MID;
if (!level->checkMaskDown(offset, y - F32)) {
// Player is on the bridge
players[count].setEvent(set);
offset -= x;
if (offset < dx) dx = offset;
if ((offset > dy) &&
(offset < set[E_MULTIPURPOSE] * F8)) dy = offset;
if (offset < set[E_MULTIPURPOSE] * F4)
players[count].setPosition(players[count].getX(),
y + (offset >> 3) - F8);
else
players[count].setPosition(players[count].getX(),
y + (set[E_MULTIPURPOSE] * F1) - (offset >> 3) - F8);
} else players[count].clearEvent(set, E_BEHAVIOUR);
}
}
break;
case 29:
// Rotate
......@@ -371,6 +314,8 @@ bool Event::step (unsigned int ticks, int msps) {
dx = TTOF(gridX) + (int)(sin(angle) * offset) - x;
dy = TTOF(gridY) + (int)((cos(angle) + 1.0f) * offset) - y;
dx = ((dx << 10) / msps) * set[E_MOVEMENTSP];
dy = ((dy << 10) / msps) * set[E_MOVEMENTSP];
break;
......@@ -383,23 +328,25 @@ bool Event::step (unsigned int ticks, int msps) {
(set[E_MAGNITUDE] * ticks / 2048.0f);
dx = TTOF(gridX) + (int)(sin(angle) * offset) - x;
dy = TTOF(gridY) + (int)fabs((cos(angle) + 1.0f) * offset) - y;
dy = TTOF(gridY) + (int)((fabs(cos(angle)) + 1.0f) * offset) - y;
dx = ((dx << 10) / msps) * set[E_MOVEMENTSP];
dy = ((dy << 10) / msps) * set[E_MOVEMENTSP];
break;
case 31:
// Move horizontally
if (animType == E_LEFTANIM) dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else dx = ES_FAST * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_FAST;
else dx = ES_FAST;
break;
case 32:
// Move horizontally
if (animType == E_LEFTANIM) dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else dx = ES_FAST * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_FAST;
else dx = ES_FAST;
break;
......@@ -409,23 +356,19 @@ bool Event::step (unsigned int ticks, int msps) {
if (localPlayer->getFacing() && (x + width < localPlayer->getX())) {
dx = ES_FAST * msps / set[E_MOVEMENTSP];
dx = ES_FAST;
if (y + height < localPlayer->getY() + PYO_TOP)
dy = ES_SLOW * msps / set[E_MOVEMENTSP];
else if (y > localPlayer->getY())
dy = -ES_SLOW * msps / set[E_MOVEMENTSP];
if (y + height < localPlayer->getY() + PYO_TOP) dy = ES_SLOW;
else if (y > localPlayer->getY()) dy = -ES_SLOW;
else dy = 0;
} else if (!localPlayer->getFacing() &&
(x > localPlayer->getX() + F32)) {
dx = -ES_FAST * msps / set[E_MOVEMENTSP];
dx = -ES_FAST;
if (y + height < localPlayer->getY() + PYO_TOP)
dy = ES_SLOW * msps / set[E_MOVEMENTSP];
else if (y > localPlayer->getY())
dy = -ES_SLOW * msps / set[E_MOVEMENTSP];
if (y + height < localPlayer->getY() + PYO_TOP) dy = ES_SLOW;
else if (y > localPlayer->getY()) dy = -ES_SLOW;
else dy = 0;
} else {
......@@ -448,12 +391,17 @@ bool Event::step (unsigned int ticks, int msps) {
level->setEventTime(gridX, gridY, ticks + (set[E_MOVEMENTSP] * 1000));
dy = 0;
} else dy = -(y + (set[E_YAXIS] * F2) - TTOF(gridY)) * msps / 320;
} else dy = -(y + (set[E_YAXIS] * F2) - TTOF(gridY)) / 100;
} else {
if (y < TTOF(gridY) + F16) dy = (y + (set[E_YAXIS] * F2) - TTOF(gridY)) * msps / 320;
else dy = (TTOF(gridY) + F16) - y;
if (y < TTOF(gridY) + F16) dy = (y + (set[E_YAXIS] * F2) - TTOF(gridY)) / 100;
else {
y = TTOF(gridY) + F16;
dy = 0;
}
}
......@@ -467,15 +415,17 @@ bool Event::step (unsigned int ticks, int msps) {
if (level->checkMaskDown(x + width, y + F4) &&
!level->checkMaskDown(x + width + F4, y - (height >> 1)))
dx = ES_FAST * msps / set[E_MOVEMENTSP];
else dx = 0;
dx = ES_FAST;
else
dx = 0;
} else if (!localPlayer->getFacing() && (x > localPlayer->getX() + PXO_R + F4)) {
if (level->checkMaskDown(x, y + F4) &&
!level->checkMaskDown(x - F4, y - (height >> 1)))
dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else dx = 0;
dx = -ES_FAST;
else
dx = 0;
} else dx = 0;
......@@ -489,15 +439,13 @@ bool Event::step (unsigned int ticks, int msps) {
// Fall downwards
dx = 0;
dy = ES_FAST * msps / set[E_MOVEMENTSP];
dy = ES_FAST;
} else {
// Walk from side to side, staying on-screen
if (animType == E_LEFTANIM)
dx = -ES_FAST * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dx = ES_FAST * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_FAST;
else if (animType == E_RIGHTANIM) dx = ES_FAST;
else dx = 0;
dy = 0;
......@@ -579,10 +527,8 @@ bool Event::step (unsigned int ticks, int msps) {
if (y > level->getWaterLevel()) {
if (animType == E_LEFTANIM)
dx = -ES_SLOW * msps / set[E_MOVEMENTSP];
else if (animType == E_RIGHTANIM)
dx = ES_SLOW * msps / set[E_MOVEMENTSP];
if (animType == E_LEFTANIM) dx = -ES_SLOW;
else if (animType == E_RIGHTANIM) dx = ES_SLOW;
else dx = 0;
} else dx = 0;
......@@ -591,20 +537,20 @@ bool Event::step (unsigned int ticks, int msps) {
default:
// Do nothing for the following:
// 0: Static
// 25: Float up / Belt
// TODO: Remaining event behaviours
break;
}
// Apply movement
if (set[E_BEHAVIOUR] != 28) {
x += dx;
y += dy;
}
dx /= set[E_MOVEMENTSP];
dy /= set[E_MOVEMENTSP];
x += (dx * msps) >> 10;
y += (dy * msps) >> 10;
// Choose animation and direction
......@@ -635,7 +581,8 @@ bool Event::step (unsigned int ticks, int msps) {
case 3:
// Seek jazz
if (localPlayer->getX() + PXO_R < x) animType = E_LEFTANIM;
if (localPlayer->getX() + PXO_R < x)
animType = E_LEFTANIM;
else if (localPlayer->getX() + PXO_L > x + width)
animType = E_RIGHTANIM;
......@@ -650,13 +597,13 @@ bool Event::step (unsigned int ticks, int msps) {
// Walk from side to side
if (animType == E_LEFTANIM) {
if (level->checkMaskDown(x - F4,
y - (height >> 1) - F12)) animType = E_RIGHTANIM;
if (level->checkMaskDown(x - F4, y - (height >> 1) - F12))
animType = E_RIGHTANIM;
} else if (animType == E_RIGHTANIM) {
if (level->checkMaskDown(x + width + F4,
y - (height >> 1) - F12)) animType = E_LEFTANIM;
if (level->checkMaskDown(x + width + F4, y - (height >> 1) - F12))
animType = E_LEFTANIM;
}
......@@ -669,9 +616,11 @@ bool Event::step (unsigned int ticks, int msps) {
// Use the path from the level file
// Check movement direction
if ((level->pathNode < 3) || (level->pathX[level->pathNode] <=
level->pathX[level->pathNode - 3])) animType = E_LEFTANIM;
else animType = E_RIGHTANIM;
if ((level->pathNode < 3) ||
(level->pathX[level->pathNode] <= level->pathX[level->pathNode - 3]))
animType = E_LEFTANIM;
else
animType = E_RIGHTANIM;
break;
......@@ -733,7 +682,8 @@ bool Event::step (unsigned int ticks, int msps) {
if (localPlayer->overlap(x, y - height, width, height))
animType = E_LEFTANIM;
else animType = E_RIGHTANIM;
else
animType = E_RIGHTANIM;
break;
......@@ -761,8 +711,7 @@ bool Event::step (unsigned int ticks, int msps) {
if (x < TTOF(gridX) - (set[E_BRIDGELENGTH] << 14))
animType = E_RIGHTANIM;
else if (!animType ||
(x > TTOF(gridX + set[E_BRIDGELENGTH])))
else if (!animType || (x > TTOF(gridX + set[E_BRIDGELENGTH])))
animType = E_LEFTANIM;
break;
......@@ -794,16 +743,15 @@ bool Event::step (unsigned int ticks, int msps) {
// Walk from side to side, staying on-screen
if (animType == E_LEFTANIM) {
if (level->checkMaskDown(x - F4,
y - (height >> 1)) || (x - F4 < viewX))
if (level->checkMaskDown(x - F4, y - (height >> 1)) ||
(x - F4 < viewX))
animType = E_RIGHTANIM;
} else if (animType == E_RIGHTANIM) {
if (level->checkMaskDown(x + width + F4,
y - (height >> 1)) ||
(x + width + F4 > viewX + ITOF(viewW)))
animType = E_LEFTANIM;
if (level->checkMaskDown(x + width + F4, y - (height >> 1)) ||
(x + width + F4 > viewX + ITOF(viewW)))
animType = E_LEFTANIM;
}
......@@ -819,13 +767,13 @@ bool Event::step (unsigned int ticks, int msps) {
if (animType == E_LEFTANIM) {
if (level->checkMaskDown(x - F4,
y - (height >> 1))) animType = E_RIGHTANIM;
if (level->checkMaskDown(x - F4, y - (height >> 1)))
animType = E_RIGHTANIM;
} else if (animType == E_RIGHTANIM) {
if (level->checkMaskDown(x + width + F4,
y - (height >> 1))) animType = E_LEFTANIM;
if (level->checkMaskDown(x + width + F4, y - (height >> 1)))
animType = E_LEFTANIM;
} else animType = E_LEFTANIM;
......@@ -837,7 +785,8 @@ bool Event::step (unsigned int ticks, int msps) {
if (localPlayer->getX() + PXO_MID < x + (width >> 1))
animType = E_LEFTANIM;
else animType = E_RIGHTANIM;
else
animType = E_RIGHTANIM;
break;
......@@ -880,9 +829,6 @@ bool Event::step (unsigned int ticks, int msps) {
if ((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM)) {
// Change the water level
if (set[E_MODIFIER] == 31) level->setWaterLevel(gridY);
// The event has been destroyed, so remove it
level->clearEvent(gridX, gridY);
......@@ -923,30 +869,31 @@ bool Event::step (unsigned int ticks, int msps) {
for (count = 0; count < nPlayers; count++) {
// Check if the player is touching the event
if (set[E_MODIFIER] == 6) {
if (width && height &&
players[count].overlap(x, y - height, width, height)) {
if (width && height &&
players[count].overlap(x, y - height, width - F8, height) &&
(players[count].getY() <= y + (PYS_FALL / msps) - height) &&
!level->checkMaskDown(players[count].getX() + PXO_MID, PYO_TOP + y - height)) {
if (set[E_MODIFIER] == 6) {
// Player is on a platform
// Platform
players[count].setEvent(gridX, gridY);
players[count].setPosition(players[count].getX() + ((dx * msps) >> 10), y - height);
if ((players[count].getY() <=
y + (PYS_FALL / msps) - height)
&& !level->checkMaskDown(players[count].getX() +
PXO_MID, y - height - F20)) {
} else players[count].clearEvent(gridX, gridY);
players[count].setEvent(set);
players[count].setPosition(players[count].getX() +
dx, y - height);
} else {
} else players[count].clearEvent(set, E_MODIFIER);
// Check if the player is touching the event
if (width && height &&
players[count].overlap(x, y - height, width, height)) {
}
// If the player picks up the event, destroy it
if (players[count].touchEvent(gridX, gridY, ticks, msps))
destroy(ticks);
// If the player picks up the event, destroy it
if (players[count].touchEvent(gridX, gridY, ticks))
destroy(ticks);
}
}
......@@ -965,7 +912,6 @@ void Event::draw (unsigned int ticks, int change) {
Anim *anim;
signed char *set;
int count;
fixed bridgeLength, dipA, dipB;
// Uncomment the following to see the area of the event
......@@ -989,69 +935,22 @@ void Event::draw (unsigned int ticks, int change) {
frame = (ticks + T_FINISH - level->getEventTime(gridX, gridY)) / 40;
else if (set[E_ANIMSP])
frame = ticks / (set[E_ANIMSP] * 40);
else frame = ticks / 20;
else
frame = ticks / 20;
anim = level->getAnim(set[animType]);
anim->setFrame(frame + gridX + gridY, true);
if (ticks < flashTime) anim->flashPalette(0);
// Draw the event
if (set[E_BEHAVIOUR] == 28) {
bridgeLength = set[E_MULTIPURPOSE] * F8;
if (dy >= dx) {
dipA = (dx <= (bridgeLength >> 1)) ? dx >> 3:
(bridgeLength - dx) >> 3;
dipB = (dy <= (bridgeLength >> 1)) ? dy >> 3:
(bridgeLength - dy) >> 3;
for (count = 0; count < bridgeLength; count += F8) {
if (count < dx)
anim->draw(x + count, y + (count * dipA / dx));
else if (count < dy)
anim->draw(x + count,
y + dipA +
((count - dx) * (dipB - dipA) / (dy - dx)));
else
anim->draw(x + count,
y + ((bridgeLength - count) * dipB /
(bridgeLength - dy)));
}
} else {
// No players on the bridge, de-sagging in progress
dipA = (dx + dy) >> 1;
dipB = (dy < bridgeLength - dx) ? dy >> 3: (bridgeLength - dx) >> 3;
for (count = 0; count < bridgeLength; count += F8) {
if (count < dipA)
anim->draw(x + count, y + (count * dipB / dipA));
else
anim->draw(x + count,
y + ((bridgeLength - count) * dipB /
(bridgeLength - dipA)));
}
}
} else {
anim->draw(getDrawX(change), getDrawY(change));
if (ticks < flashTime) anim->flashPalette(0);
}
anim->draw(getDrawX(change), getDrawY(change));
if (ticks < flashTime) anim->restorePalette();
// If the event has been destroyed, draw an explosion
if (set[E_HITSTOKILL] &&
((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM))) {
......
/*
*
* guardians.cpp
*
* 2nd March 2010: Created guardians.cpp from parts of event.cpp and eventframe.cpp
*
* Part of the OpenJazz project
*
*
* Copyright (c) 2005-2010 Alister Thomson
*
* OpenJazz is distributed under the terms of
* the GNU General Public License, version 2.0
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/*
* Provides the functions of guardian events.
*
*/
#include "../level.h"
#include "guardians.h"
#include "io/gfx/video.h"
#include "player/player.h"
DeckGuardian::DeckGuardian (unsigned char gX, unsigned char gY, Event *nextEvent) {
x = TTOF(gX);
y = TTOF(gY + 1);
dx = 0;
dy = 0;
next = nextEvent;
gridX = gX;
gridY = gY;
flashTime = 0;
stage = 0;
return;
}
bool DeckGuardian::overlap (fixed left, fixed top, fixed width, fixed height) {
if (stage == 0)
return (x + F8 - F64 >= left) && (x - F64 < left + width) &&
(y + F64 >= top) && (y + F32 < top + height);
if (stage == 1)
return (x + F32 >= left) && (x + F32 - F8 < left + width) &&
(y + F64 >= top) && (y + F32 < top + height);
if (stage == 2)
return (x + F64 - F16 >= left) && (x + F32 - F8 < left + width) &&
(y + F64 >= top) && (y + F32 < top + height);
return false;
}
bool DeckGuardian::step (unsigned int ticks, int msps) {
signed char *set;
int count;
set = prepareStep(ticks, msps);
if (!set) return true;
// Handle behaviour
count = level->getEventHits(gridX, gridY);
if (count < 8) stage = 0;
else if (count < 16) stage = 1;
else if (count < 24) stage = 2;
else stage = 3;
// If the event has been destroyed, play its finishing animation and set its
// reaction time
if (set[E_HITSTOKILL] &&
(level->getEventHits(gridX, gridY) >= set[E_HITSTOKILL]) &&
(animType != E_LFINISHANIM) && (animType != E_RFINISHANIM)) {
destroy(ticks);
}
// If the reaction time has expired
if (level->getEventTime(gridX, gridY) &&
(ticks > level->getEventTime(gridX, gridY))) {
if ((animType == E_LFINISHANIM) || (animType == E_RFINISHANIM)) {
// The event has been destroyed, so remove it
level->clearEvent(gridX, gridY);
return true;
} else {
level->setEventTime(gridX, gridY, 0);
}
}
if (level->getStage() == LS_END) return false;
return false;
}
void DeckGuardian::draw (unsigned int ticks, int change) {
Anim *anim;
signed char *set;
int count;
// Get the event properties
set = level->getEvent(gridX, gridY);
// If the event has been removed from the grid, do not show it
if (!set) return;
// Draw the boss
if (stage < 3) {
// Draw unit
anim = level->getAnim(29 + stage);
if (ticks < flashTime) anim->flashPalette(0);
if (stage == 0) anim->draw(x - F64, y + F32);
else if (stage == 1) anim->draw(x + F32 - F8 - F4, y + F32);
else anim->draw(x + F8 - F64, y + F32);
if (ticks < flashTime) anim->restorePalette();
}
if (set[E_HITSTOKILL]) {
// Draw boss energy bar
count = level->getEventHits(gridX, gridY) * 100 / set[E_HITSTOKILL];
// Devan head
anim = level->getMiscAnim(1);
anim->setFrame(0, true);
if (ticks < flashTime) anim->flashPalette(0);
anim->draw(viewX + ITOF(viewW - 44), viewY + ITOF(count + 48));
if (ticks < flashTime) anim->restorePalette();
// Bar
drawRect(viewW - 40, count + 40, 12, 100 - count,
(ticks < flashTime)? 0: 32);
}
return;
}
/*
*
* guardians.h
*
* 2nd March 2010: Created guardians.h from parts of event.h
*
* Part of the OpenJazz project
*
*
* Copyright (c) 2005-2010 Alister Thomson
*
* OpenJazz is distributed under the terms of
* the GNU General Public License, version 2.0
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _GUARDIANS_H
#define _GUARDIANS_H
#include "event.h"
// Class
class DeckGuardian : public Event {
private:
int stage;
public:
DeckGuardian (unsigned char gX, unsigned char gY, Event *nextEvent);
bool overlap (fixed left, fixed top, fixed width, fixed height);
bool step (unsigned int ticks, int msps);
void draw (unsigned int ticks, int change);
};
#endif
......@@ -272,7 +272,7 @@ void Level::clearEvent (unsigned char gridX, unsigned char gridY) {
}
int Level::hitEvent (unsigned char gridX, unsigned char gridY, Player *source, bool TNT) {
int Level::hitEvent (unsigned char gridX, unsigned char gridY, Player *source) {
GridElement *ge;
unsigned char buffer[MTL_L_GRID];
......@@ -286,15 +286,14 @@ int Level::hitEvent (unsigned char gridX, unsigned char gridY, Player *source, b
if (!hitsToKill) return -1;
// Increase the hit count
if (TNT) ge->hits = hitsToKill;
else ge->hits++;
ge->hits++;
// Check if the event has been killed
if (ge->hits == hitsToKill) {
// Notify the player that shot the bullet
// If this returns false, ignore the hit
if (!source->shootEvent(gridX, gridY, ticks)) {
if (!source->takeEvent(gridX, gridY, ticks)) {
ge->hits--;
......
......@@ -155,7 +155,7 @@ class Level {
unsigned char getEventHits (unsigned char gridX, unsigned char gridY);
unsigned int getEventTime (unsigned char gridX, unsigned char gridY);
void clearEvent (unsigned char gridX, unsigned char gridY);
int hitEvent (unsigned char gridX, unsigned char gridY, Player *source, bool TNT);
int hitEvent (unsigned char gridX, unsigned char gridY, Player *source);
void setEventTime (unsigned char gridX, unsigned char gridY, unsigned int time);
signed char * getBullet (unsigned char bullet);
Sprite * getSprite (unsigned char sprite);
......
......@@ -27,6 +27,7 @@
#include "bullet.h"
#include "event/event.h"
#include "event/guardians.h"
#include "level.h"
#include "game/game.h"
......@@ -70,7 +71,31 @@ int Level::step () {
}
// If the event wasn't found, create it
if (!nextEvent) firstEvent = new Event(x, y, firstEvent);
if (!nextEvent) {
switch (getEvent(x, y)[E_BEHAVIOUR]) {
case 28:
firstEvent = new Bridge(x, y, firstEvent);
break;
case 60:
firstEvent = new DeckGuardian(x, y, firstEvent);
break;
default:
firstEvent = new Event(x, y, firstEvent);
break;
}
}
}
......
......@@ -706,15 +706,19 @@ int Level::load (char *fileName, unsigned char diff, bool checkpoint) {
for (y = 0; y < LH; y++) {
// Eliminate event references for events of too high a difficulty
if (eventSet[grid[y][x].event][E_DIFFICULTY] > difficulty)
grid[y][x].event = 0;
type = grid[y][x].event;
// If the event hurts and can be killed, it is an enemy
// Anything else that scores is an item
if ((eventSet[grid[y][x].event][E_MODIFIER] == 0) &&
eventSet[grid[y][x].event][E_HITSTOKILL]) enemies++;
else if (eventSet[grid[y][x].event][E_ADDEDSCORE]) items++;
if (type) {
// Eliminate event references for events of too high a difficulty
if (eventSet[type][E_DIFFICULTY] > difficulty) grid[y][x].event = 0;
// If the event hurts and can be killed, it is an enemy
// Anything else that scores is an item
if ((eventSet[type][E_MODIFIER] == 0) && eventSet[type][E_HITSTOKILL]) enemies++;
else if (eventSet[type][E_ADDEDSCORE]) items++;
}
}
......@@ -727,24 +731,25 @@ int Level::load (char *fileName, unsigned char diff, bool checkpoint) {
// Load animation set
buffer = file->loadRLE(ANIMS * 64);
buffer = file->loadRLE(ANIMS << 6);
// Create animation set based on that data
for (count = 0; count < ANIMS; count++) {
animSet[count].setData(buffer[(count * 64) + 6],
buffer[(count * 64) + 4], buffer[(count * 64) + 5]);
animSet[count].setData(buffer[(count << 6) + 6],
buffer[count << 6], buffer[(count << 6) + 1],
buffer[(count << 6) + 4], buffer[(count << 6) + 5]);
for (y = 0; y < buffer[(count * 64) + 6]; y++) {
for (y = 0; y < buffer[(count << 6) + 6]; y++) {
// Get frame
x = buffer[(count * 64) + 7 + y];
x = buffer[(count << 6) + 7 + y];
if (x > sprites) x = sprites;
// Assign sprite and vertical offset
animSet[count].setFrame(y, true);
animSet[count].setFrameData(spriteSet + x,
buffer[(count * 64) + 26 + y], buffer[(count * 64) + 45 + y]);
buffer[(count << 6) + 26 + y], buffer[(count << 6) + 45 + y]);
}
......
......@@ -81,7 +81,6 @@ void Bird::hit () {
bool Bird::step (unsigned int ticks, int msps) {
Event *nextEvent;
fixed eventX, eventY;
bool target;
if (fleeing) {
......@@ -161,20 +160,9 @@ bool Bird::step (unsigned int ticks, int msps) {
if (player->getFacing()) {
while (nextEvent) {
while (nextEvent && !target) {
eventX = nextEvent->getX();
eventY = nextEvent->getY() - nextEvent->getHeight();
if (nextEvent->getProperty(E_HITSTOKILL) &&
(eventX > x) && (eventX < x + F160) && (eventY > y) &&
(eventY < y + F100)) {
target = true;
break;
}
target = nextEvent->isEnemy() && nextEvent->overlap(x, y, F160, F100);
nextEvent = nextEvent->getNext();
......@@ -182,20 +170,9 @@ bool Bird::step (unsigned int ticks, int msps) {
} else {
while (nextEvent) {
eventX = nextEvent->getX();
eventY = nextEvent->getY() - nextEvent->getHeight();
if (nextEvent->getProperty(E_HITSTOKILL) &&
(eventX > x - F160) && (eventX < x) && (eventY > y) &&
(eventY < y + F100)) {
target = true;
break;
while (nextEvent && !target) {
}
target = nextEvent->isEnemy() && nextEvent->overlap(x - F160, y, F160, F100);
nextEvent = nextEvent->getNext();
......
......@@ -65,8 +65,7 @@ Player::~Player () {
}
void Player::init (char *playerName, unsigned char *playerCols,
unsigned char newTeam) {
void Player::init (char *playerName, unsigned char *playerCols, unsigned char newTeam) {
int offsets[15] = {PC_WHITE, PC_SGREEN, PC_BLUE, PC_RED, PC_LGREEN,
PC_LEVEL1, PC_YELLOW, PC_LEVEL2, PC_ORANGE, PC_LEVEL3, PC_LEVEL4,
......@@ -205,7 +204,7 @@ void Player::reset () {
if (bird) bird->reset();
event = NULL;
event = 0;
for (count = 0; count < PCONTROLS; count++) pcontrols[count] = false;
......@@ -237,15 +236,12 @@ void Player::setControl (int control, bool state) {
}
bool Player::shootEvent (unsigned char gridX, unsigned char gridY,
unsigned int ticks) {
bool Player::takeEvent (unsigned char gridX, unsigned char gridY, unsigned int ticks) {
signed char *set;
set = level->getEvent(gridX, gridY);
addScore(set[E_ADDEDSCORE]);
switch (set[E_MODIFIER]) {
case 41: // Bonus level
......@@ -257,17 +253,57 @@ bool Player::shootEvent (unsigned char gridX, unsigned char gridY,
case 8: // Boss
case 27: // End of level
if (getEnergy()) {
if (!getEnergy()) return false;
if (!gameMode) {
if (!gameMode) {
if (game) game->setCheckpoint(gridX, gridY);
if (game) game->setCheckpoint(gridX, gridY);
level->setStage(LS_END);
level->setStage(LS_END);
} else return gameMode->endOfLevel(this, gridX, gridY);
} else if (!(gameMode->endOfLevel(this, gridX, gridY))) return false;
}
break;
case 0: // Enemy
break;
case 1: // Invincibility
if (!getEnergy()) return false;
reaction = PR_INVINCIBLE;
reactionTime = ticks + PRT_INVINCIBLE;
break;
case 2:
case 3: // Health
if (energy < 4) energy++;
break;
case 4: // Extra life
if (lives < 99) lives++;
break;
case 5: // High-jump feet
jumpHeight += F16;
break;
case 7: // Used with destructible blocks
break;
case 9: // Sand timer
level->addTimer();
break;
......@@ -277,131 +313,139 @@ bool Player::shootEvent (unsigned char gridX, unsigned char gridY,
break;
case 15:
case 11: // Item
break;
case 12: // Rapid fire
fireSpeed++;
break;
case 15: // Ammo
addAmmo(0, 15);
break;
case 16:
case 16: // Ammo
addAmmo(1, 15);
break;
case 17:
case 17: // Ammo
addAmmo(2, 15);
break;
case 26:
case 18: // Ammo
fastFeetTime = ticks + T_FASTFEET;
addAmmo(0, 2);
break;
case 33:
case 19: // Ammo
if (shield < 2) shield = 2;
addAmmo(1, 2);
break;
case 34: // Bird
case 20: // Ammo
if (!bird) bird = new Bird(this, gridX, gridY);
addAmmo(2, 2);
break;
case 36:
case 26: // Fast feet box
shield = 6;
fastFeetTime = ticks + T_FASTFEET;
break;
}
case 30: // TNT
// Add to player's enemy/item tally
// If the event hurts and can be killed, it is an enemy
// Anything else that scores is an item
if ((set[E_MODIFIER] == 0) && set[E_HITSTOKILL]) enemies++;
else if (set[E_ADDEDSCORE]) items++;
addAmmo(3, 1);
return true;
break;
}
case 31: // Water level
level->setWaterLevel(gridY);
bool Player::touchEvent (unsigned char gridX, unsigned char gridY,
unsigned int ticks) {
break;
signed char *set;
case 33: // 2-hit shield
set = level->getEvent(gridX, gridY);
if (shield < 2) shield = 2;
switch (set[E_MODIFIER]) {
break;
case 0: // Hurt
case 8: // Boss
case 34: // Bird
if ((set[E_BEHAVIOUR] < 37) || (set[E_BEHAVIOUR] > 44))
hit(NULL, ticks);
if (!bird) bird = new Bird(this, gridX, gridY);
break;
case 1: // Invincibility
case 35: // Airboard, etc.
if (getEnergy()) {
floating = true;
reaction = PR_INVINCIBLE;
reactionTime = ticks + PRT_INVINCIBLE;
addScore(set[E_ADDEDSCORE]);
break;
return true;
case 36: // 4-hit shield
}
shield = 6;
break;
case 2:
case 3: // Health
case 37: // Diamond
if (energy < 4) energy++;
addScore(set[E_ADDEDSCORE]);
// Yellow flash
firstPE = new FlashPaletteEffect(255, 255, 0, 320, firstPE);
return true;
break;
case 4: // Extra life
default:
if (lives < 99) lives++;
addScore(set[E_ADDEDSCORE]);
return false;
return true;
}
case 5: // High-jump feet
addScore(set[E_ADDEDSCORE]);
jumpHeight += F16;
// Add to player's enemy/item tally
// If the event hurts and can be killed, it is an enemy
// Anything else that scores is an item
if ((set[E_MODIFIER] == 0) && set[E_HITSTOKILL]) enemies++;
else if (set[E_ADDEDSCORE]) items++;
return true;
return true;
case 9: // Sand timer
}
level->addTimer();
addScore(set[E_ADDEDSCORE]);
return true;
bool Player::touchEvent (unsigned char gridX, unsigned char gridY, unsigned int ticks, int msps) {
case 11: // Item
signed char *set;
addScore(set[E_ADDEDSCORE]);
set = level->getEvent(gridX, gridY);
return true;
switch (set[E_MODIFIER]) {
case 12: // Rapid fire
case 0: // Hurt
case 8: // Boss
fireSpeed++;
if ((set[E_BEHAVIOUR] < 37) || (set[E_BEHAVIOUR] > 44))
hit(NULL, ticks);
break;
return true;
case 7: // Used with destructible blocks, but should not destroy on contact
break;
case 13: // Warp
......@@ -419,60 +463,42 @@ bool Player::touchEvent (unsigned char gridX, unsigned char gridY,
break;
case 18: // Ammo
addAmmo(0, 2);
addScore(set[E_ADDEDSCORE]);
return true;
case 19: // Ammo
addAmmo(1, 2);
addScore(set[E_ADDEDSCORE]);
return true;
case 28: // Belt
case 20: // Ammo
addAmmo(2, 2);
addScore(set[E_ADDEDSCORE]);
x += set[E_MAGNITUDE] * 4 * msps;
return true;
break;
case 29: // Upwards spring
setEvent(set);
setEvent(gridX, gridY);
level->playSound(set[E_SOUND]);
break;
case 30: // TNT
addAmmo(3, 1);
return true;
case 31: // Water level
if (!set[E_HITSTOKILL]) level->setWaterLevel(gridY);
level->setWaterLevel(gridY);
break;
case 35: // Airboard, etc.
case 32: // Float up / sideways
floating = true;
addScore(set[E_ADDEDSCORE]);
if (set[E_YAXIS]) {
return true;
eventX = gridX;
eventY = gridY;
event = 2;
case 37: // Diamond
if (dy > set[E_MULTIPURPOSE] * -F20)
dy -= set[E_MULTIPURPOSE] * 320 * msps;
// Yellow flash
firstPE = new FlashPaletteEffect(255, 255, 0, 320, firstPE);
jumpY = y - (8 * F16);
return true;
} else x += set[E_MAGNITUDE] * 20 * msps;
break;
case 38: // Airboard, etc. off
......@@ -480,6 +506,12 @@ bool Player::touchEvent (unsigned char gridX, unsigned char gridY,
break;
default:
if (!set[E_HITSTOKILL]) return takeEvent(gridX, gridY, ticks);
break;
}
return false;
......@@ -619,8 +651,24 @@ int Player::getItems () {
bool Player::overlap (fixed left, fixed top, fixed width, fixed height) {
return (x + PXO_R >= left) && (x + PXO_L < left + width) && (y >= top) &&
(y + PYO_TOP < top + height);
return (x + PXO_R >= left) && (x + PXO_L < left + width) &&
(y >= top) && (y + PYO_TOP < top + height);
}
bool Player::isOnPlatform () {
// Check for platform event, bridge or level mask below player
return
(event >= 3) ||
level->checkMaskDown(x + PXO_ML, y + F2) ||
level->checkMaskDown(x + PXO_MID, y + F2) ||
level->checkMaskDown(x + PXO_MR, y + F2) ||
level->checkMaskDown(x + PXO_ML, y + F8) ||
level->checkMaskDown(x + PXO_MID, y + F8) ||
level->checkMaskDown(x + PXO_MR, y + F8);
}
......@@ -659,49 +707,35 @@ unsigned char Player::getTeam () {
}
void Player::floatUp (signed char *newEvent, int speed) {
event = newEvent;
if ((dy > 0) && level->checkMaskDown(x + PXO_MID, y + F4))
dy = event[E_MULTIPURPOSE] * -F40;
if (dy > event[E_MULTIPURPOSE] * -F40)
dy -= event[E_MULTIPURPOSE] * 320 * speed;
jumpY = y - (8 * F16);
return;
}
void Player::belt (int speed) {
void Player::setEvent (unsigned char gridX, unsigned char gridY) {
dx += speed * 20;
return;
signed char *set;
}
set = level->getEvent(gridX, gridY);
if (set[E_MODIFIER] == 29) {
void Player::setEvent (signed char *newEvent) {
// Upwards spring
jumpY = y + (set[E_MAGNITUDE] * (F20 + F1));
event = 1;
event = newEvent;
} else if (set[E_MODIFIER] == 6) event = 3;
else if (set[E_BEHAVIOUR] == 28) event = 4;
else return;
if (event[E_MODIFIER] == 29) // Upwards spring
jumpY = y + (event[E_MAGNITUDE] * (F20 + F1));
eventX = gridX;
eventY = gridY;
return;
}
void Player::clearEvent (signed char *newEvent, unsigned char property) {
void Player::clearEvent (unsigned char gridX, unsigned char gridY) {
// If the given property matches, clear the event
// If the location matches, clear the event
if (event && (event[property] == newEvent[property])) event = NULL;
if ((gridX == eventX) && (gridY == eventY)) event = 0;
return;
......
......@@ -160,24 +160,22 @@ class Player : public Movable {
private:
Bird *bird;
char *name;
signed char *event; /* A member of the event set (spring, float up,
belt, platform) */
char anims[PANIMS];
bool pcontrols[PCONTROLS];
SDL_Color palette[256];
unsigned char cols[4];
int ammo[4];
int ammoType; /* -1 = blaster, 0 = toaster, 1 = missiles,
2 = bouncer 3 = TNT */
int ammoType; /* -1 = blaster, 0 = toaster, 1 = missiles, 2 = bouncer 3 = TNT */
int score;
int energy;
int lives;
int shield; /* 0 = none, 1 = 1 yellow, 2 = 2 yellow,
3 = 1 orange, 4 = 2 orange, 5 = 3 orange, 6 = 4 orange */
bool floating; // false = normal, true = boarding/bird/etc.
int shield; /* 0 = none, 1 = 1 yellow, 2 = 2 yellow, 3 = 1 orange, 4 = 2 orange, 5 = 3 orange, 6 = 4 orange */
bool floating; /* false = normal, true = boarding/bird/etc. */
bool facing;
int lookTime; /* Negative if looking up, positive if looking
down, 0 if neither */
unsigned char eventX;
unsigned char eventY; /* Position of an event (spring, platform, bridge) */
int event; /* 0 = none, 1 = spring, 2 = float up, 3 = platform, 4 = bridge */
int lookTime; /* Negative if looking up, positive if looking down, 0 if neither */
int reaction;
unsigned int reactionTime;
int fireSpeed;
......@@ -190,7 +188,8 @@ class Player : public Movable {
int enemies, items;
unsigned char team;
void addAmmo (int type, int amount);
void addAmmo (int type, int amount);
bool isOnPlatform ();
public:
int teamScore;
......@@ -198,18 +197,17 @@ 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 reset ();
void setControl (int control, bool state);
bool shootEvent (unsigned char gridX, unsigned char gridY,
unsigned int ticks);
bool touchEvent (unsigned char gridX, unsigned char gridY,
unsigned int ticks);
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);
void addScore (int addedScore);
......@@ -219,17 +217,11 @@ class Player : public Movable {
int getAmmo (bool amount);
int getEnemies ();
int getItems ();
bool overlap (fixed left, fixed top, fixed width,
fixed height);
bool overlap (fixed left, fixed top, fixed width, fixed height);
void setPosition (fixed newX, fixed newY);
void setSpeed (fixed newDx, fixed newDy);
bool getFacing ();
unsigned char getTeam ();
void floatUp (signed char *newEvent, int speed);
void belt (int speed);
void setEvent (signed char *newEvent);
void clearEvent (signed char *newEvent,
unsigned char property);
void send (unsigned char *data);
void receive (unsigned char *buffer);
void control (unsigned int ticks, int msps);
......
......@@ -42,6 +42,9 @@
void Player::control (unsigned int ticks, int msps) {
int speed;
bool platform;
// Respond to controls, unless the player has been killed
// If the player has been killed, drop but otherwise do not move
......@@ -145,8 +148,8 @@ void Player::control (unsigned int ticks, int msps) {
if (event) {
if (event[E_MODIFIER] == 29) dy = event[E_MULTIPURPOSE] * -F20;
else if (event[E_BEHAVIOUR] == 25) dy = PYS_JUMP;
if (event == 1) dy = level->getEvent(eventX, eventY)[E_MULTIPURPOSE] * -F20;
else if (event == 2) dy = PYS_JUMP;
}
......@@ -172,7 +175,7 @@ void Player::control (unsigned int ticks, int msps) {
if (dx < 0) jumpY += dx >> 4;
else if (dx > 0) jumpY -= dx >> 4;
event = NULL;
event = 0;
}
......@@ -198,71 +201,50 @@ void Player::control (unsigned int ticks, int msps) {
} else {
if ((event && ((event[E_MODIFIER] == 6) ||
(event[E_BEHAVIOUR] == 28))) ||
level->checkMaskDown(x + PXO_ML, y + F2) ||
level->checkMaskDown(x + PXO_MID, y + F2) ||
level->checkMaskDown(x + PXO_MR, y + F2)) {
// Mask/platform/bridge below player
if (pcontrols[C_JUMP] && !level->checkMask(x + PXO_MID, y - F36)) {
// Jump
jumpY = y - jumpHeight;
platform = isOnPlatform();
// Increase jump height if walking/running
if (dx < 0) jumpY += dx >> 3;
else if (dx > 0) jumpY -= dx >> 3;
if (platform && pcontrols[C_JUMP] &&
!level->checkMask(x + PXO_MID, y - F36)) {
event = NULL;
// Jump
playSound(S_JUMPA);
jumpY = y - jumpHeight;
}
if (!lookTime) {
// If requested, look up or down
if (pcontrols[C_UP]) lookTime = -ticks;
else if (pcontrols[C_DOWN]) lookTime = ticks;
}
// Increase jump height if walking/running
if (dx < 0) jumpY += dx >> 3;
else if (dx > 0) jumpY -= dx >> 3;
} else {
event = 0;
// No mask/platform/bridge below player
// Cannot look up or down
lookTime = 0;
playSound(S_JUMPA);
}
// Stop jumping
if (!pcontrols[C_JUMP] &&
(!event || ((event[E_MODIFIER] != 29) &&
(event[E_BEHAVIOUR] != 25)))) jumpY = TTOF(LH);
if (!pcontrols[C_JUMP] && (event != 1) && (event != 2))
jumpY = TTOF(LH);
// If jumping, rise
if (y >= jumpY) {
// If jumping, rise
dy = (jumpY - y - F64) * 4;
// Spring speed limit
if (event && (event[E_MODIFIER] == 29)) {
// Spring/float up speed limit
if ((event == 1) || (event == 2)) {
speed = level->getEvent(eventX, eventY)[E_MULTIPURPOSE] * -F20;
if ((event[E_MULTIPURPOSE] == 0) && (dy < PYS_JUMP))
dy = PYS_JUMP;
if (speed == 0) speed = PYS_JUMP;
if ((event[E_MULTIPURPOSE] > 0) && (dy < event[E_MULTIPURPOSE] * -F20))
dy = event[E_MULTIPURPOSE] * -F20;
if (dy < speed) dy = speed;
}
// Avoid jumping too fast, unless caused by an event
if (!event && (dy < PYS_JUMP)) dy = PYS_JUMP;
} else {
} else if (!platform) {
// Fall under gravity
dy += PYA_GRAVITY * msps;
......@@ -270,22 +252,29 @@ void Player::control (unsigned int ticks, int msps) {
}
// Stop looking
if (!pcontrols[C_UP] && (lookTime < 0)) lookTime = 0;
if (!pcontrols[C_DOWN] && (lookTime > 0)) lookTime = 0;
if (platform && !lookTime) {
// If requested, look up or down
if (pcontrols[C_UP]) lookTime = -ticks;
else if (pcontrols[C_DOWN]) lookTime = ticks;
}
// Stop looking if there is no platform or the control has been released
if (!platform ||
(!pcontrols[C_UP] && (lookTime < 0)) ||
(!pcontrols[C_DOWN] && (lookTime > 0))) lookTime = 0;
}
// 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 || event[E_BEHAVIOUR] != 25)) {
if (level->checkMask(x + PXO_MID, y + PYO_TOP - F4) && (jumpY < y) && (event != 2)) {
jumpY = TTOF(LH);
if (dy < 0) dy = 0;
if (event && (event[E_MODIFIER] != 6) && (event[E_BEHAVIOUR] != 28))
event = NULL;
if ((event != 3) && (event != 4)) event = 0;
}
......@@ -294,8 +283,7 @@ void Player::control (unsigned int ticks, int msps) {
jumpY = TTOF(LH);
if (event && (event[E_MODIFIER] != 6) && (event[E_BEHAVIOUR] != 28))
event = NULL;
if ((event != 3) && (event != 4)) event = 0;
}
......@@ -303,7 +291,7 @@ void Player::control (unsigned int ticks, int msps) {
// Handle firing
if (pcontrols[C_FIRE]) {
if (ticks > fireTime) {
if ((ticks > fireTime) && (level->getBullet(ammoType + 1)[B_SPRITE] != 0)) {
// Create new bullet
level->firstBullet = new Bullet(this, false, ticks);
......@@ -395,7 +383,14 @@ void Player::move (unsigned int ticks, int msps) {
while (count > 0) {
if (level->checkMask(x + PXO_MID, y + PYO_TOP - F4)) break;
if (level->checkMask(x + PXO_MID, y + PYO_TOP - F4)) {
y &= ~4095;
dy = 0;
break;
}
y -= F4;
count--;
......@@ -404,8 +399,14 @@ void Player::move (unsigned int ticks, int msps) {
pdy = (-pdy) & 4095;
if (!level->checkMask(x + PXO_MID, y + PYO_TOP - pdy)) y -= pdy;
else y &= ~4095;
if (!level->checkMask(x + PXO_MID, y + PYO_TOP - pdy))
y -= pdy;
else {
y &= ~4095;
dy = 0;
}
} else if (pdy > 0) {
......@@ -417,7 +418,14 @@ void Player::move (unsigned int ticks, int msps) {
if (level->checkMaskDown(x + PXO_ML, y + F4) ||
level->checkMaskDown(x + PXO_MID, y + F4) ||
level->checkMaskDown(x + PXO_MR, y + F4)) break;
level->checkMaskDown(x + PXO_MR, y + F4)) {
y |= 4095;
dy = 0;
break;
}
y += F4;
count--;
......@@ -428,8 +436,14 @@ void Player::move (unsigned int ticks, int msps) {
if (!(level->checkMaskDown(x + PXO_ML, y + pdy) ||
level->checkMaskDown(x + PXO_MID, y + pdy) ||
level->checkMaskDown(x + PXO_MR, y + pdy))) y += pdy;
else y |= 4095;
level->checkMaskDown(x + PXO_MR, y + pdy)))
y += pdy;
else {
y |= 4095;
dy = 0;
}
}
......@@ -446,7 +460,13 @@ 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)) break;
if (level->checkMask(x + PXO_L - F4, y + PYO_MID)) {
x &= ~4095;
break;
}
x -= F4;
count--;
......@@ -475,7 +495,13 @@ 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)) break;
if (level->checkMask(x + PXO_R + F4, y + PYO_MID)) {
x |= 4095;
break;
}
x += F4;
count--;
......@@ -499,11 +525,10 @@ void Player::move (unsigned int ticks, int msps) {
// If using a float up event and have hit a ceiling, ignore event
if (event && (event[E_BEHAVIOUR] == 25) &&
level->checkMask(x + PXO_MID, y + PYO_TOP - F4)) {
if ((event == 2) && level->checkMask(x + PXO_MID, y + PYO_TOP - F4)) {
jumpY = TTOF(LH);
event = NULL;
event = 0;
}
......@@ -610,17 +635,7 @@ void Player::draw (unsigned int ticks, int change) {
else if (dy >= 0) {
if ((event && ((event[E_MODIFIER] == 6) ||
(event[E_BEHAVIOUR] == 28))) ||
level->checkMaskDown(x + PXO_ML, y + F2) ||
level->checkMaskDown(x + PXO_MID, y + F2) ||
level->checkMaskDown(x + PXO_MR, y + F2) ||
level->checkMaskDown(x + PXO_ML, y + F8) ||
level->checkMaskDown(x + PXO_MID, y + F8) ||
level->checkMaskDown(x + PXO_MR, y + F8)) {
drawX = x;
drawY = y;
if (isOnPlatform()) {
if (dx) {
......@@ -634,14 +649,12 @@ void Player::draw (unsigned int ticks, int change) {
if (!level->checkMaskDown(x + PXO_ML, y + F12) &&
!level->checkMaskDown(x + PXO_L, y + F2) &&
(!event || ((event[E_MODIFIER] != 6) &&
(event[E_BEHAVIOUR] != 28))))
(event != 3) && (event != 4))
anim = anims[PA_LEDGE];
else if (!level->checkMaskDown(x + PXO_MR, y + F12) &&
!level->checkMaskDown(x + PXO_R, y + F2) &&
(!event || ((event[E_MODIFIER] != 6) &&
(event[E_BEHAVIOUR] != 28))))
(event != 3) && (event != 4))
anim = anims[PA_REDGE];
else if (pcontrols[C_FIRE])
......@@ -662,7 +675,7 @@ void Player::draw (unsigned int ticks, int change) {
} else anim = anims[facing? PA_RFALL: PA_LFALL];
} else if (event && (event[E_MODIFIER] == 29))
} else if (event == 1)
anim = anims[facing? PA_RSPRING: PA_LSPRING];
else anim = anims[facing? PA_RJUMP: PA_LJUMP];
......
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