Commit b03fa295 authored by alistert's avatar alistert

More JJ2 events, with animations.

parent cccf9189
......@@ -30,7 +30,7 @@
#include "baselevel.h"
JJ2Event::JJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char* properties) {
JJ2Event::JJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType, int newProperties) {
x = TTOF(gridX);
y = TTOF(gridY);
......@@ -39,15 +39,12 @@ JJ2Event::JJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY,
next = newNext;
type = properties[0];
data[0] = properties[1];
data[1] = properties[2];
data[2] = properties[3];
type = newType;
properties = newProperties;
hits = 0;
endTime = 0;
facing = true;
flipped = false;
return;
......@@ -60,9 +57,81 @@ JJ2Event::~JJ2Event () {
}
PickupJJ2Event::PickupJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType, int newProperties) : JJ2Event(newNext, gridX, gridY, newType, newProperties) {
floating = true;
return;
}
PickupJJ2Event::~PickupJJ2Event () {
return;
}
AmmoJJ2Event::AmmoJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType) : PickupJJ2Event(newNext, gridX, gridY, newType, 0) {
return;
}
AmmoJJ2Event::~AmmoJJ2Event () {
return;
}
CoinGemJJ2Event::CoinGemJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType) : PickupJJ2Event(newNext, gridX, gridY, newType, 0) {
return;
}
CoinGemJJ2Event::~CoinGemJJ2Event () {
return;
}
FoodJJ2Event::FoodJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType) : PickupJJ2Event(newNext, gridX, gridY, newType, 0) {
return;
}
FoodJJ2Event::~FoodJJ2Event () {
return;
}
OtherJJ2Event::OtherJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType, int newProperties) : JJ2Event(newNext, gridX, gridY, newType, newProperties) {
return;
}
OtherJJ2Event::~OtherJJ2Event () {
return;
}
void JJ2Event::destroy (unsigned int ticks) {
endTime = ticks + 1000;
endTime = ticks + 500;
return;
......
......@@ -29,30 +29,90 @@
// Classes
class Anim;
class JJ2Event : public Movable {
private:
JJ2Event* next;
JJ2Event* next;
protected:
unsigned char type;
unsigned char data[3];
unsigned char hits; // Number of times the event has been shot
int endTime; // Point at which the event will terminate
unsigned char anim;
unsigned char frame;
unsigned int flashTime;
bool facing;
int properties;
unsigned int endTime; // Point at which the event will terminate
bool flipped;
JJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType, int newProperties);
void destroy (unsigned int ticks);
bool prepareStep (unsigned int ticks, int msps);
bool prepareDraw (unsigned int ticks, int change);
JJ2Event* remove ();
public:
virtual ~JJ2Event ();
unsigned char getType ();
virtual JJ2Event* step (unsigned int ticks, int msps) = 0;
virtual void draw (unsigned int ticks, int change) = 0;
};
class PickupJJ2Event : public JJ2Event {
private:
bool floating;
protected:
PickupJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType, int newProperties);
virtual ~PickupJJ2Event ();
JJ2Event* step (unsigned int ticks, int msps);
};
class AmmoJJ2Event : public PickupJJ2Event {
JJ2Event* remove ();
void destroy (unsigned int ticks);
public:
AmmoJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType);
~AmmoJJ2Event ();
void draw (unsigned int ticks, int change);
};
class CoinGemJJ2Event : public PickupJJ2Event {
private:
void mapPalette (Anim* anim, int start);
public:
CoinGemJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType);
~CoinGemJJ2Event ();
void draw (unsigned int ticks, int change);
};
class FoodJJ2Event : public PickupJJ2Event {
public:
JJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char* properties);
~JJ2Event ();
FoodJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType);
~FoodJJ2Event ();
void draw (unsigned int ticks, int change);
unsigned char getType ();
};
class OtherJJ2Event : public JJ2Event {
public:
OtherJJ2Event (JJ2Event* newNext, unsigned char gridX, unsigned char gridY, unsigned char newType, int newProperties);
~OtherJJ2Event ();
JJ2Event* step (int ticks, int msps);
void draw (unsigned int ticks, int change);
JJ2Event* step (unsigned int ticks, int msps);
void draw (unsigned int ticks, int change);
};
......
......@@ -34,44 +34,264 @@
#include "player/jj2levelplayer.h"
JJ2Event* JJ2Event::step (int ticks, int msps) {
// Look-up table for ammo animations (in animSet 1)
const unsigned char ammoAnims[] = {
28, // Ice
24, // Bouncer
33, // Seeker
48, // RF
56, // Toaster
58, // TNT
61, // Pellets
67 // Sparks
};
// Look-up table for food etc. animations (in animSet 67)
const unsigned char pickupAnims[] = {
0, // 0
0, // 1
0, // 2
0, // 3
0, // 4
0, // 5
0, // 6
0, // 7
0, // 8
0, // 9
0, // 10
0, // 11
0, // 12
0, // 13
0, // 14
0, // 15
0, // 16
0, // 17
0, // 18
0, // 19
0, // 20
0, // 21
0, // 22
0, // 23
0, // 24
0, // 25
0, // 26
0, // 27
0, // 28
0, // 29
0, // 30
0, // 31
0, // 32
0, // 33
0, // 34
0, // 35
0, // 36
0, // 37
0, // 38
0, // 39
0, // 40
0, // 41
0, // 42
0, // 43
84, // Silver coin
37, // Gold coin
0, // 46
0, // 47
0, // 48
0, // 49
0, // 50
0, // 51
0, // 52
55, // Ice crate
54, // Bouncer crate
56, // Seeker crate
57, // RF crate
58, // Toaster crate
90, // Armed TNT
36, // Board
0, // 60
29, // Rapid fire (can also be 30)
0, // 62
35, // Red gem
35, // Green gem
35, // Blue gem
35, // Purple gem
34, // Large red gem
0, // 68
3, // Ammo barrel
0, // 70
0, // 71
82, // Energy
72, // Full energy
31, // Fire shield
10, // Bubble shield
51, // Plasma shield
0, // 77
0, // 78
33, // High jump
0, // 1-up
28, // exit signpost
0, // 82
14, // Checkpoint
0, // 84
0, // 85
0, // 86
0, // 87
0, // 88
87, // Extra time
42, // Freeze
0, // 91
0, // 92
0, // 93
0, // 94
52, // Trigger crate
0, // 96
0, // 97
0, // 98
0, // 99
0, // 100
0, // 101
0, // 102
0, // 103
0, // 104
0, // 105
0, // 106
0, // 107
0, // 108
0, // 109
0, // 110
0, // 111
0, // 112
0, // 113
0, // 114
0, // 115
0, // 116
0, // 117
0, // 118
0, // 119
0, // 120
0, // 121
0, // 122
0, // 123
0, // 124
0, // 125
0, // 126
0, // 127
0, // 128
0, // 129
0, // 130
60, // Blaster PU (can also be 83)
61, // Bouncer PU
62, // Ice PU
63, // Seeker PU
64, // RF PU
65, // Toaster PU
0, // 137
0, // 138
0, // 139
0, // 140
1, // Apple
2, // Banana
16, // Cherry
71, // Orange
74, // Pear
79, // Pretzel
81, // Strawberry
0, // 148
0, // 149
0, // 150
0, // 151
0, // 152
0, // 153
48, // Lemon
50, // Lime
89, // Thing
92, // Watermelon
73, // Peach
38, // Grapes
49, // Lettuce
26, // Aubergine
23, // Cucumber
75, // Jazzade
20, // Cola
53, // Milk
76, // Tart
12, // Cake
25, // Doughnut
24, // Cupcake
18, // Crisps
13, // Sweet
19, // Chocolate
43, // Ice cream
11, // Burger
77, // Pizza
32, // Chips
17, // Chicken drumstick
80, // Sandwich
88, // Taco
91, // Hot dog
39, // Ham
15, // Cheese
0, // 183
0, // 184
0, // 185
0, // 186
0, // 187
0, // 188
0, // 189
0, // 190
0, // 191
0, // 192
0, // 193
0, // 194
0, // 195
0, // 196
0, // 197
0, // 198
0, // 199
0, // 200
0, // 201
0, // 202
0, // 203
0, // 204
0, // 205
0, // 206
0, // 207
0, // 208
0, // 209
0, // 210
0, // 211
0, // 212
0, // 213
0, // 214
0, // 215
0, // 216
0, // 217
0, // 218
0, // 219
66, // Pellet PU
67, // Sparks PU
};
bool JJ2Event::prepareStep (unsigned int ticks, int msps) {
JJ2LevelPlayer *levelPlayer;
int count;
if (next) next = next->step(ticks, msps);
// Handle behaviour
switch (type) {
case 60: // Frozen green spring
case 62: // Spring crate
case 83: // Checkpoint
case 85: // Red spring
case 86: // Green spring
case 87: // Blue spring
if (!jj2Level->checkMaskDown(x, y + F1, true)) y += F1;
break;
default:
break;
}
// Process next event(s)
if (next) next = next->step(ticks, msps);
// If the reaction time has expired
if (endTime && (ticks > endTime)) {
return remove();
return true;
}
if (endTime) return this;
if (endTime) return false;
// Handle contact with player
......@@ -84,82 +304,282 @@ JJ2Event* JJ2Event::step (int ticks, int msps) {
if (levelPlayer->overlap(x, y, F32, F32)) {
// If the player picks up the event, destroy it
if (levelPlayer->touchEvent(this, ticks, msps))
destroy(ticks);
if (levelPlayer->touchEvent(this, ticks, msps)) destroy(ticks);
}
}
return false;
}
bool JJ2Event::prepareDraw (unsigned int ticks, int change) {
// Draw next event(s)
if (next) next->draw(ticks, change);
// Don't draw if too far off-screen
if ((x < viewX - F64) || (y < viewY - F64) ||
(x > viewX + ITOF(canvasW) + F64) || (y > viewY + ITOF(canvasH) + F64)) return true;
return false;
}
JJ2Event* PickupJJ2Event::step (unsigned int ticks, int msps) {
if (prepareStep(ticks, msps)) return remove();
if (!floating) {
if (jj2Level->checkMaskDown(x, y + F4, false)) {
dy += 1000 / msps;
} else {
dy = 0;
}
} else {
// TODO: Check for bullet overlap
// floating = false;
}
return this;
}
void JJ2Event::draw (unsigned int ticks, int change) {
void AmmoJJ2Event::draw (unsigned int ticks, int change) {
Anim* an;
int drawX, drawY;
if (next) next->draw(ticks, change);
if (prepareDraw(ticks, change)) return;
// Don't draw if too far off-screen
if ((x < viewX - F64) || (y < viewY - F64) ||
(x > viewX + ITOF(canvasW) + F64) || (y > viewY + ITOF(canvasH) + F64)) return;
drawX = getDrawX(change);
drawY = getDrawY(change);
// TODO: Check if ammo is powered up
if (!endTime)an = jj2Level->getAnim(0, ammoAnims[type - 33] + 1, flipped);
else an = jj2Level->getAnim(67, 86, flipped);
an->setFrame((int)ticks / 60, true);
an->draw(drawX + F16, drawY + F16 + F32);
return;
}
void CoinGemJJ2Event::mapPalette (Anim* anim, int start) {
SDL_Color palette[256];
int count;
for (count = 0; count < 112; count++)
palette[count + 128].r = palette[count + 128].g = palette[count + 128].b = start + 6 - (count >> 4);
for (; count < 128; count++)
palette[count + 128].r = palette[count + 128].g = palette[count + 128].b = 255;
anim->setPalette(palette, 128, 128);
return;
}
void CoinGemJJ2Event::draw (unsigned int ticks, int change) {
Anim* an;
int drawX, drawY;
if (prepareDraw(ticks, change)) return;
drawX = getDrawX(change);
drawY = getDrawY(change);
if (endTime) {
an = jj2Level->getAnim(67, 86, flipped);
an->setFrame((int)ticks / 60, true);
an->draw(drawX + F16, drawY + F16 + F32);
}
if (type == 44) an = jj2Level->getAnim(67, 84, flipped); // Silver coin
else if (type == 45) an = jj2Level->getAnim(67, 37, flipped); // Gold coin
else an = jj2Level->getAnim(67, 35, flipped); // Gem
an->setFrame((int)ticks / 60, true);
switch (type) {
case 60: // Frozen green spring
case 63: // Red gem
an = jj2Level->getAnim(92, 5, !facing);
mapPalette(an, 48);
break;
case 62: // Spring crate
case 64: // Green gem
mapPalette(an, 80);
break;
case 65: // Blue gem
an = jj2Level->getAnim(92, 0, !facing);
mapPalette(an, 32);
break;
case 66: // Purple gem
mapPalette(an, 88);
break;
}
if (endTime) {
drawX += (ticks + 500 - endTime) << 8;
drawY += (ticks + 500 - endTime) << 10;
}
an->draw(drawX + F16, drawY + F16 + F32);
return;
}
void FoodJJ2Event::draw (unsigned int ticks, int change) {
Anim* an;
int drawX, drawY;
if (prepareDraw(ticks, change)) return;
drawX = getDrawX(change);
drawY = getDrawY(change);
// Use look-up table
if (!endTime) an = jj2Level->getAnim(67, pickupAnims[type], flipped);
else an = jj2Level->getAnim(67, 86, flipped);
an->setFrame((int)ticks / 60, true);
an->draw(drawX + F16, drawY + F16 + F32);
return;
}
JJ2Event* OtherJJ2Event::step (unsigned int ticks, int msps) {
if (prepareStep(ticks, msps)) return remove();
switch (type) {
case 60: // Frozen green spring
case 62: // Spring crate
case 83: // Checkpoint
case 85: // Red spring
case 86: // Green spring
case 87: // Blue spring
if (!jj2Level->checkMaskDown(x, y + F1, true)) y += F1;
break;
default:
break;
}
return this;
}
void OtherJJ2Event::draw (unsigned int ticks, int change) {
Anim* an;
int drawX, drawY;
if (prepareDraw(ticks, change)) return;
an = jj2Level->getAnim(67, 14, !facing);
drawX = getDrawX(change);
drawY = getDrawY(change);
switch (type) {
case 60: // Frozen green spring
an = jj2Level->getAnim(92, 5, flipped);
an->setFrame(0, true);
break;
case 62: // Spring crate
an = jj2Level->getAnim(92, 0, flipped);
an->setFrame(0, true);
break;
case 85: // Red spring
an = jj2Level->getAnim(92, 7, !facing);
an = jj2Level->getAnim(92, 7, flipped);
an->setFrame(0, true);
break;
case 86: // Green spring
an = jj2Level->getAnim(92, 5, !facing);
an = jj2Level->getAnim(92, 5, flipped);
an->setFrame(0, true);
break;
case 87: // Blue spring
an = jj2Level->getAnim(92, 0, !facing);
an = jj2Level->getAnim(92, 0, flipped);
an->setFrame(0, true);
break;
default:
if (!endTime) drawRect(FTOI(drawX) + 8, FTOI(drawY) + 8, 16, 16, type);
if ((type <= 221) && pickupAnims[type]) {
an = jj2Level->getAnim(67, pickupAnims[type], flipped);
an->setFrame((int)ticks / 60, true);
an->draw(drawX + F16, drawY + F16 + F32);
} else if (!endTime) {
drawRect(FTOI(drawX) + 8, FTOI(drawY) + 8, 16, 16, type);
}
panelBigFont->showNumber(type, FTOI(drawX) + 24, FTOI(drawY) + 12);
return;
}
an->setFrame((int)ticks / 60, true);
an->draw(drawX, drawY);
an->draw(drawX + F16, drawY + F16);
return;
......
......@@ -212,11 +212,13 @@ Anim* JJ2Level::getAnim (int set, int anim, bool flipped) {
}
void JJ2Level::setWaterLevel (unsigned char gridY) {
void JJ2Level::setWaterLevel (unsigned char gridY, bool instant) {
unsigned char buffer[MTL_L_PROP];
waterLevelTarget = TTOF(gridY);
if (instant) waterLevel = waterLevelTarget - F8;
if (gameMode) {
......
......@@ -119,10 +119,11 @@ class JJ2Level : public BaseLevel {
fixed waterLevelTarget;
fixed waterLevelSpeed;
void createEvent (int x, int y, unsigned char* data);
int load (char* fileName, unsigned char diff, bool checkpoint);
void loadSprite (unsigned char* parameters, unsigned char* compressedPixels, Sprite* sprite, Sprite* flippedSprite);
int loadSprites ();
int loadTiles (char* fileName);
int load (char* fileName, unsigned char diff, bool checkpoint);
int step ();
void draw ();
......@@ -139,7 +140,7 @@ class JJ2Level : public BaseLevel {
fixed getWaterLevel ();
void setFrame (unsigned char gridX, unsigned char gridY, unsigned char frame);
void setNext (char* fileName);
void setWaterLevel (unsigned char gridY);
void setWaterLevel (unsigned char gridY, bool instant);
void warp (JJ2LevelPlayer *player, int id);
void receive (unsigned char* buffer);
......
......@@ -433,6 +433,84 @@ int JJ2Level::loadTiles (char* fileName) {
}
void JJ2Level::createEvent (int x, int y, unsigned char* data) {
unsigned char type;
int properties;
type = *data;
properties = (data[1] >> 4) + (data[2] << 4) + (data[3] << 12);
if ((type < 33) || ((type >= 206) && (type <= 208)) || (type == 230) || (type == 240) || (type == 245)) {
mods[y][x].type = type;
mods[y][x].properties = properties;
return;
}
mods[y][x].type = 0;
if (type < 41) {
events = new AmmoJJ2Event(events, x, y, type);
} else if (type < 44) {
events = new OtherJJ2Event(events, x, y, type, properties);
} else if (type < 46) {
events = new CoinGemJJ2Event(events, x, y, type);
} else if (type < 63) {
events = new OtherJJ2Event(events, x, y, type, properties);
} else if (type < 67) {
events = new CoinGemJJ2Event(events, x, y, type);
} else if (type < 72) {
events = new OtherJJ2Event(events, x, y, type, properties);
} else if (type < 74) {
events = new FoodJJ2Event(events, x, y, type);
} else if (type == 80) {
events = new FoodJJ2Event(events, x, y, type);
} else if (type < 141) {
events = new OtherJJ2Event(events, x, y, type, properties);
} else if (type < 148) {
events = new FoodJJ2Event(events, x, y, type);
} else if (type < 154) {
events = new OtherJJ2Event(events, x, y, type, properties);
} else if (type < 183) {
events = new FoodJJ2Event(events, x, y, type);
} else {
events = new OtherJJ2Event(events, x, y, type, properties);
}
return;
}
int JJ2Level::load (char *fileName, unsigned char diff, bool checkpoint) {
Anim* pAnims[2];
......@@ -617,30 +695,15 @@ int JJ2Level::load (char *fileName, unsigned char diff, bool checkpoint) {
for (x = 0; x < width; x++) {
count = bBuffer[((y * width) + x) << 2];
if ((count < 33) || (count == 206) || (count == 230) || (count == 240)) {
mods[y][x].type = count;
mods[y][x].properties =
(bBuffer[(((y * width) + x) << 2) + 1] >> 4) +
(bBuffer[(((y * width) + x) << 2) + 2] << 4) +
(bBuffer[(((y * width) + x) << 2) + 3] << 12);
if (count == 29) {
// Jazz start pos
startX = x;
startY = y;
}
// Create event or assign modifier
createEvent(x, y, bBuffer + (((y * width) + x) << 2));
} else {
if (mods[y][x].type == 29) {
mods[y][x].type = 0;
// Jazz start pos
events = new JJ2Event(events, x, y, bBuffer + (((y * width) + x) << 2));
startX = x;
startY = y;
}
......
......@@ -141,6 +141,16 @@ void JJ2LevelPlayer::modify (JJ2Modifier* nextMod, unsigned int ticks) {
break;
case 207: // Text
break;
case 208: // Water level
jj2Level->setWaterLevel(nextMod->properties & 0xFF, nextMod->properties & 0x100);
break;
case 230: // Warp
if (!stopTime) {
......@@ -822,10 +832,10 @@ void JJ2LevelPlayer::draw (unsigned int ticks, int change) {
if ((reaction != JJ2PR_HURT) || ((ticks / 30) & 2)) {
// Draw "motion blur"
if (fastFeetTime > ticks) an->draw(drawX - (dx >> 6), drawY);
if (fastFeetTime > ticks) an->draw(drawX + F16 - (dx >> 6), drawY + F16);
// Draw player
an->draw(drawX, drawY);
an->draw(drawX + F16, drawY + F16);
}
......
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