Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Anniversary Bash 21 Levels | Jazz2Online | Multiple | N/A |
#include "MLLE-Include-1.4.asc"
const bool MLLESetupSuccessful = MLLE::Setup();
#pragma require "ab21btl11.j2l"
#pragma require "Castle2N.j2t"
#pragma require "ab21btl11-MLLE-Data-1.j2l"
#pragma require "Sirius1.j2t"
#pragma require "SwampsD.j2t"
#pragma require "LaserBlaster.j2a"
#pragma require "f_laser1.wav"
#pragma require "f_laser2.wav"
#pragma require "f_laser3.wav"
#pragma require "f_laser4.wav"
#pragma require "bow_fire_arrow.wav"
#pragma require "floorslide.wav"
#pragma require "floorslideclose.wav"
#pragma require "expmine.wav"
#pragma require "meteor.j2a"
#pragma require "ArrowGun.j2a"
#pragma require "SEroller.asc"
#include "SEroller.asc"
enum PacketType {
trapPacket,
weaponPacket
}
enum ProjectileDrawingMethod {
simple,
angled,
rotating
}
const int quitTrapSelectionKey = 0x08;
se::DefaultWeaponHook weaponHook(weaponPacket);
array<PlayerData> playerData(jjLocalPlayerCount);
array<Trap> traps;
interface TrapBehavior {
bool isActive() const;
void activate(jjPLAYER@ player);
void process();
}
class PlayerData {
int trapSelection = -1;
int trapPrice = 0;
bool prevKeyFire = false;
bool prevKeyLeft = false;
bool prevKeyRight = false;
}
class Trap {
string name;
string description;
float x;
float y;
TrapBehavior@ behavior;
}
mixin class TimedTrapBehavior : TrapBehavior {
bool isActive() const override {
return timer != 0;
}
private int timer = 0;
}
class SpikeTrap : TimedTrapBehavior {
SpikeTrap(int xTile, int yTile, int width, int xorTile) {
x1 = xTile;
x2 = xTile + width;
y = yTile;
mask = xorTile;
}
void activate(jjPLAYER@ player) override {
auto@ data = playerData[player.localPlayerID];
if (!isActive()) {
switchTiles();
if (data.trapSelection >= 0) {
jjSample(73*32, 57*32, SOUND::COMMON_COLLAPS, 0, 0);
} else {
jjSample(37*32, 80*32, SOUND::COMMON_COLLAPS, 0, 0);
}
}
@activator = player;
timer = 210;
if (!player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Crystal Spike Trap", true, STRING::SMALL);
if (jjIsServer && player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Crystal Spike Trap", false, STRING::SMALL);
}
void process() override {
for (int i = 0; i < jjLocalPlayerCount; i++) {
auto@ player = jjLocalPlayers[i];
auto@ data = playerData[player.localPlayerID];
if (isActive()) {
timer--;
if (!isActive()) {
switchTiles();
if (data.trapSelection >= 0) {
jjSample(73*32, 57*32, SOUND::CATERPIL_RIDOE, 0, 0);
} else {
jjSample(37*32, 80*32, SOUND::CATERPIL_RIDOE, 0, 0);
}
}
}
if (player.isInGame && player.xPos >= x1 << 5 && player.xPos < x2 << 5 && player.yPos > y << 5)
killLocalPlayerWithTrap(player, activator);
}
}
protected void switchTiles() const {
for (int i = x1; i < x2; i++) {
jjTileSet(4, i, y, jjTileGet(4, i, y) ^ mask);
}
}
private int x1;
private int x2;
private int y;
private int mask;
private jjPLAYER@ activator;
}
class FireTrap : TimedTrapBehavior {
FireTrap(int xTile, int yTile, int height) {
x = xTile << 5;
y = yTile << 5 | 16;
count = height;
}
void activate(jjPLAYER@ player) override {
@activator = player;
timer = 210;
if (!player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Fire Trap", true, STRING::SMALL);
if (jjIsServer && player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Fire Trap", false, STRING::SMALL);
}
void process() override {
if (isActive()) {
timer--;
for (int i = 0; i < 4; i++) {
sampleSource = jjSampleLooped(x, y + (i*32), SOUND::COMMON_FLAMER, sampleSource, 0, 0);
if (activator.isLocal) sampleActivator = jjSampleLooped(75*32, 58*32, SOUND::COMMON_FLAMER, sampleActivator, 0, 0);
}
if (timer & 1 == 0) {
int id = jjAddObject(OBJECT::BULLET, x, y + ((timer >> 1) % count << 5), activator.playerID, CREATOR::PLAYER);
if (id > 0) {
auto@ obj = jjObjects[id];
obj.age = 4;
obj.behavior = Projectile(simple);
obj.counterEnd = 36;
obj.determineCurAnim(ANIM::AMMO, 55);
obj.determineCurFrame();
obj.playerHandling = HANDLING::SPECIAL;
obj.scriptedCollisions = true;
obj.xSpeed = 9.f;
}
}
}
}
private float x;
private float y;
private int count;
private int sampleSource, sampleActivator;
private jjPLAYER@ activator;
}
class VolcanoTrap : TimedTrapBehavior {
VolcanoTrap(int xTile, int yTile) {
x = xTile << 5;
y = yTile << 5;
}
void activate(jjPLAYER@ player) override {
@activator = player;
timer = 49;
if (!player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Volcano Trap", true, STRING::SMALL);
if (jjIsServer && player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Volcano Trap", false, STRING::SMALL);
}
void process() override {
if (isActive()) {
timer--;
if (timer & 7 == 0) {
for (int i = timer != 0 ? -1 : 0; i <= 1; i += 2) {
int id = jjAddObject(OBJECT::BULLET, x, y, activator.playerID, CREATOR::PLAYER);
if (id > 0) {
auto@ obj = jjObjects[id];
jjSample(x, y - 64, jjRandom()%2 > 0? SOUND::AMMO_FIREGUN1A : SOUND::AMMO_FIREGUN2A, 0, 0);
if (activator.isLocal) jjSample(75*32, 58*32, jjRandom()%2 > 0? SOUND::AMMO_FIREGUN1A : SOUND::AMMO_FIREGUN2A, 0, 0);
obj.age = 7;
obj.behavior = Projectile(angled);
obj.determineCurAnim(ANIM::BILSBOSS, 3);
obj.determineCurFrame();
obj.killAnim = jjAnimSets[ANIM::AMMO] + 5;
obj.playerHandling = HANDLING::SPECIAL;
obj.scriptedCollisions = true;
obj.xSpeed = (timer >> 3) * i * 0.55f;
obj.ySpeed = -13.f;
obj.yAcc = 0.25f;
obj.var[1] = 1;
if (activator.isLocal) obj.var[2] = 1;
}
}
}
}
}
private float x;
private float y;
private int sampleSource, sampleActivator;
private jjPLAYER@ activator;
}
class DartTrap : TimedTrapBehavior {
DartTrap(int xTile, int yTile) {
x = xTile << 5;
y = yTile << 5;
}
void activate(jjPLAYER@ player) override {
@activator = player;
timer = 1;
if (!player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Dart Trap", true, STRING::SMALL);
if (jjIsServer && player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Dart Trap", false, STRING::SMALL);
}
void process() override {
if (isActive()) {
timer--;
if (timer < 1) {
for (int i = 0; i < 4; i++) {
jjSample(x, y + (i*32), SOUND::P2_PTOEI, 0, 0);
if (activator.isLocal) jjSample(75*32, 58*32, SOUND::P2_PTOEI, 0, 0);
}
}
if (timer & 1 == 0) {
for (int i = 0; i < 4; i++) {
int id = jjAddObject(OBJECT::BULLET, x, (y - 16) + (i*32), activator.playerID, CREATOR::PLAYER);
if (id > 0) {
auto@ obj = jjObjects[id];
obj.age = 7;
obj.behavior = Projectile(simple);
obj.determineCurAnim(ANIM::CUSTOM[2], 0);
obj.determineCurFrame();
obj.killAnim = jjAnimSets[ANIM::AMMO] + 4;
obj.playerHandling = HANDLING::SPECIAL;
obj.scriptedCollisions = true;
obj.xSpeed = -12;
obj.ySpeed = 0.5;
obj.direction = -1;
obj.var[1] = 2;
if (activator.isLocal) obj.var[2] = 1;
}
}
}
}
}
private float x;
private float y;
private jjPLAYER@ activator;
}
class RockTrap : TimedTrapBehavior {
RockTrap(int xTile, int yTile, int width) {
int x = xTile << 5 | 16;
y = yTile << 5;
order.resize(width);
for (int i = 0; i < width; i++) {
order[i] = x + (i << 5);
}
shuffle(order, jjRNG());
}
void activate(jjPLAYER@ player) override {
@activator = player;
timer = 64;
if (!player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Rock Trap", true, STRING::SMALL);
if (jjIsServer && player.isLocal) jjAlert(""+player.nameUnformatted + " activated the |||Rock Trap", false, STRING::SMALL);
if (activator.isLocal) jjSample(75*32, 58*32, SOUND::ORANGE_BOEMR, 0, 0);
for (int i = 0; i < 8; i++) {
jjSample((79*32 + (i*5)), y + 96, SOUND::ORANGE_BOEMR, 0, 0);
}
}
void process() override {
if (isActive()) {
timer--;
if (timer & 1 == 0) {
int xCur = order[timer >> 1];
int yCur = y;
while (!jjMaskedPixel(xCur, yCur)) {
yCur--;
}
int id = jjAddObject(OBJECT::BULLET, xCur, yCur, activator.playerID, CREATOR::PLAYER);
if (id > 0) {
auto@ obj = jjObjects[id];
obj.age = 4;
obj.behavior = Projectile(rotating);
obj.determineCurAnim(ANIM::CUSTOM[1], 2);
obj.determineCurFrame();
obj.killAnim = jjAnimSets[ANIM::AMMO] + 72;
obj.playerHandling = HANDLING::SPECIAL;
obj.scriptedCollisions = true;
obj.ySpeed = 1.f;
obj.yAcc = 0.25f;
obj.var[1] = 3;
if (activator.isLocal) obj.var[2] = 1;
}
}
}
}
private int y;
private jjPLAYER@ activator;
private array<int> order;
}
class BladeTrap : TrapBehavior {
bool isActive() const override {
// TODO
return false;
}
void activate(jjPLAYER@ player) override {
@activator = player;
// TODO
}
void process() override {
// TODO
}
private jjPLAYER@ activator;
}
class Projectile : jjBEHAVIORINTERFACE {
Projectile(ProjectileDrawingMethod method) {
drawingMethod = method;
}
void onBehave(jjOBJ@ obj) override {
if (obj.state == STATE::START) {
obj.state = STATE::FLY;
obj.direction = obj.xSpeed < 0.f ? -1 : 1;
}
obj.counter++;
if (obj.state == STATE::FLY) {
obj.xPos += obj.xSpeed += obj.xAcc;
obj.yPos += obj.ySpeed += obj.yAcc;
if (uint(obj.counter) == obj.counterEnd || jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
if (obj.var[2] == 1) {
switch (obj.var[1]) {
case 1: jjSamplePriority(SOUND::BILSBOSS_FIRE); break;
case 2: jjSamplePriority(SOUND::COMMON_LANDCAN1); break;
case 3: jjSamplePriority(SOUND::COMMON_BENZIN1); break;
default: break;
}
} else {
switch (obj.var[1]) {
case 1: jjSample(obj.xPos, obj.yPos, SOUND::BILSBOSS_FIRE, 0, 0); break;
case 2: jjSample(obj.xPos, obj.yPos, SOUND::COMMON_LANDCAN1, 0, 0); break;
case 3: jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BENZIN1, 0, 0); break;
default: break;
}
}
obj.state = STATE::KILL;
obj.curAnim = obj.killAnim;
obj.frameID = 0;
obj.determineCurFrame();
}
}
if (obj.counter % obj.age == 0) {
const auto@ anim = jjAnimations[obj.curAnim];
obj.frameID++;
if (obj.frameID == int(anim.frameCount)) {
if (obj.state == STATE::KILL) {
obj.delete();
return;
} else {
obj.frameID = 0;
}
}
obj.determineCurFrame();
}
}
void onDraw(jjOBJ@ obj) {
if (obj.state == STATE::FLY) {
switch (drawingMethod) {
case simple:
obj.draw();
break;
case angled: {
int angle = int(atan2(-obj.ySpeed, obj.xSpeed) * 163.f);
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, angle);
break;
}
case rotating:
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.counter << 5);
break;
}
} else {
obj.draw();
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if (bullet is null && obj.state == STATE::FLY)
killLocalPlayerWithTrap(player, obj.creatorType == CREATOR::PLAYER ? jjPlayers[obj.creatorID] : null);
return true;
}
private ProjectileDrawingMethod drawingMethod;
}
class CannotBeShotDown : jjBEHAVIORINTERFACE {
CannotBeShotDown(const jjBEHAVIOR &in behavior) {
originalBehavior = behavior;
}
void onBehave(jjOBJ@ obj) {
obj.behave(originalBehavior);
if (obj.state == STATE::FLOATFALL)
obj.state = STATE::FLOAT;
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if (bullet is null) {
obj.behavior = originalBehavior;
if (player.objectHit(obj, force, obj.playerHandling))
return true;
obj.behavior = this;
}
return false;
}
private jjBEHAVIOR originalBehavior;
}
void LaserGun(jjOBJ@ obj) {
jjPLAYER@ creator = jjPlayers[obj.creatorID];
if (obj.state == STATE::START) {
obj.state = STATE::FLY;
obj.direction = creator.direction;
}
if (jjMaskedPixel(int(obj.xPos + obj.xSpeed + obj.var[7] / 65536.f), int(obj.yPos))) {
obj.xSpeed = -obj.xSpeed;
obj.var[7] = -obj.var[7];
obj.xAcc = -obj.xAcc;
obj.ySpeed -= 1.5;
obj.counter -= 5;
if (obj.state == STATE::FLY) randomSample(obj);
}
else if (jjMaskedPixel(int(obj.xPos), int(obj.yPos + obj.ySpeed))) {
obj.ySpeed = -obj.ySpeed;
obj.yAcc = -obj.yAcc;
obj.xSpeed -= obj.direction == 1? -1.5:1.5;
obj.counter -= 5;
if (obj.state == STATE::FLY) randomSample(obj);
}
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state == STATE::FLY) jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[0], 1, 0, obj.var[0], 0.9, 0.9, SPRITE::NORMAL);
obj.behave(BEHAVIOR::BULLET, obj.state == STATE::FLY? false:true);
}
void LaserGunPU(jjOBJ@ obj) {
jjPLAYER@ creator = jjPlayers[obj.creatorID];
if (obj.state == STATE::START) {
obj.state = STATE::FLY;
obj.direction = creator.direction;
}
if (jjMaskedPixel(int(obj.xPos + obj.xSpeed + obj.var[7] / 65536.f), int(obj.yPos))) {
obj.xSpeed = -obj.xSpeed;
obj.var[7] = -obj.var[7];
obj.xAcc = -obj.xAcc;
obj.ySpeed -= 3;
obj.counter -= 5;
if (obj.state == STATE::FLY) randomSample(obj);
}
else if (jjMaskedPixel(int(obj.xPos), int(obj.yPos + obj.ySpeed))) {
obj.ySpeed = -obj.ySpeed;
obj.yAcc = -obj.yAcc;
obj.xSpeed -= obj.direction == 1? -3:3;
obj.counter -= 5;
if (obj.state == STATE::FLY) randomSample(obj);
}
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state == STATE::FLY) jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[0], 0, 0, obj.var[0], 1, 1, SPRITE::NORMAL);
obj.behave(BEHAVIOR::BULLET, obj.state == STATE::FLY? false:true);
}
void randomSample(jjOBJ@ obj) {
switch (jjRandom() % 4) {
case 0: jjSample(obj.xPos, obj.yPos, SOUND::AMMO_BUL1, 0, 0); break;
case 1: jjSample(obj.xPos, obj.yPos, SOUND::AMMO_BULFL1, 0, 0); break;
case 2: jjSample(obj.xPos, obj.yPos, SOUND::AMMO_BULFL2, 0, 0); break;
case 3: jjSample(obj.xPos, obj.yPos, SOUND::AMMO_BULFL3, 0, 0); break;
}
}
void coinBooth(jjOBJ@ obj) {
switch (obj.state) {
case STATE::DEACTIVATE:
obj.deactivate();
break;
case STATE::START: {
int x = int(obj.xOrg) >>> 5;
int y = int(obj.yOrg) >>> 5;
if (jjParameterGet(x, y, 17, 1) == 0) {
obj.delete();
return;
}
obj.var[0] = jjParameterGet(x, y, 8, 8);
obj.var[1] = jjParameterGet(x, y, 0, 8);
obj.var[2] = jjParameterGet(x, y, 16, 1);
obj.var[3] = jjParameterGet(x, y, 18, 1);
const array<int> colors = {248, 48, 0, 24, 8, 32, 40};
obj.var[4] = colors[obj.var[0] % 7];
obj.frameID = 0;
obj.determineCurFrame();
obj.xPos -= 16.f;
obj.yPos -= 16.f;
obj.putOnGround(true);
obj.state = STATE::STILL;
}
break;
default: {
const auto@ boothAnim = jjAnimations[obj.special];
obj.counter++;
if (obj.counter & 7 == 0) {
obj.frameID++;
if (obj.frameID >= int(jjAnimations[obj.curAnim].frameCount))
obj.frameID = 0;
obj.determineCurFrame();
}
jjDrawSpriteFromCurFrame(obj.xPos - 1.f, obj.yPos + 3.f, boothAnim + (obj.counter >> 3) % boothAnim.frameCount, obj.direction);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame + jjAnimations[obj.curAnim].frameCount, obj.direction);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, obj.var[4]);
if (obj.var[0] != 0) {
jjTEXTAPPEARANCE style;
style.align = STRING::CENTER;
style.yAmp = 1;
jjDrawString(obj.xPos - 4.f, obj.yPos - 12.f, formatInt(obj.var[0]), STRING::SMALL, style, 0, SPRITE::PALSHIFT, 208);
}
for (int i = 0; i < jjLocalPlayerCount; i++) {
auto@ player = jjLocalPlayers[i];
auto@ data = playerData[i];
if (player.isInGame && data.trapSelection == -1) {
float xDist = player.xPos - obj.xPos;
float yDist = player.yPos - obj.yPos;
if (xDist * xDist + yDist * yDist < 1024.f) {
data.trapPrice = obj.var[0];
if (player.coins < data.trapPrice)
player.testForCoins(data.trapPrice);
else
data.trapSelection = 0;
}
}
}
}
}
}
void createMinimap(jjANIMSET@ animSet) {
animSet.allocate(array<uint> = {1});
auto@ frame = jjAnimFrames[jjAnimations[animSet]];
const int shift = 1;
const int width = jjLayerWidth[4] << 1;
const int height = jjLayerHeight[4] << 1;
const int cornerRadius = 32;
jjPIXELMAP image(width, height);
const auto@ order = jjLayerOrderGet();
uint firstLayer = 0;
while (firstLayer != order.length() && !hasLayer4Speed(order[firstLayer])) {
firstLayer++;
}
uint lastLayer = firstLayer;
while (lastLayer != order.length() && hasLayer4Speed(order[lastLayer])) {
lastLayer++;
}
const jjPIXELMAP background(0, 0, 256, 256, 8);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (j < cornerRadius) {
int xDist = cornerRadius - j;
int yDist = 0;
if (i < cornerRadius)
yDist = cornerRadius - i;
else if (i >= height - cornerRadius)
yDist = i - (height - cornerRadius);
if (xDist * xDist + yDist * yDist > cornerRadius * cornerRadius)
continue;
}
uint layer = firstLayer;
int color = 0;
while (color == 0 && layer != lastLayer) {
int tile = jjGetStaticTile(jjTileGet(layer, j >> shift, i >> shift));
jjPIXELMAP src(tile);
color = src[(j & 1) << 4 | 8, (i & 1) << 4 | 8];
layer++;
}
if (color == 0)
color = background[(j >> 3) % background.width, (i >> 3) % background.height];
image[j, i] = color;
}
}
image.save(frame);
}
void setUpTraps() {
Trap trap;
trap.name = "Crystal Spike Pit";
trap.description = """A floor opens, exposing players to sharp crystal spikes.
Players will die upon touching the Crystal Spikes.""";
trap.x = 37 << 5;
trap.y = 80 << 5;
@trap.behavior = SpikeTrap(34, 81, 6, 271 ^ 376);
traps.insertLast(trap);
/*trap.name = "Spinning Blade";
trap.description = """A spinning blade rises up from the floor, quickly moves
to the left before stopping, then returns to its original position.
Players will die by touching the blade.""";
trap.x = 33 << 5;
trap.y = 47 << 5;
@trap.behavior = BladeTrap();
traps.insertLast(trap);*/
trap.name = "Poison Darts";
trap.description = """Once activated, poisoned darts quickly shoot out of the wall.
Players hit by poisoned darts will die.""";
trap.x = 69 << 5;
trap.y = 31 << 5;
@trap.behavior = DartTrap(69, 31);
traps.insertLast(trap);
trap.name = "Volcano";
trap.description = """Fireballs quickly shoot up from the temple roof, then rain down.
Players will die by touching the Fireballs.""";
trap.x = 88 << 5;
trap.y = 9 << 5;
@trap.behavior = VolcanoTrap(88, 11);
traps.insertLast(trap);
trap.name = "Fire Wall";
trap.description = """Flames shoot out of the wall, then dissipate after 3 seconds.
Players will die by touching the flames.""";
trap.x = 125 << 5;
trap.y = 38 << 5;
@trap.behavior = FireTrap(118, 37, 4);
traps.insertLast(trap);
trap.name = "Falling Rocks";
trap.description = """Rocks fall haphazardly. Players will die by being crushed by the rocks.""";
trap.x = 97 << 5;
trap.y = 72 << 5;
@trap.behavior = RockTrap(81, 71, 32);
traps.insertLast(trap);
}
bool hasLayer4Speed(const jjLAYER@ layer) {
return layer.xSpeed == 1.f && layer.ySpeed == 1.f && layer.xAutoSpeed == 0.f && layer.yAutoSpeed == 0.f;
}
void killLocalPlayerWithTrap(jjPLAYER@ player, jjPLAYER@ activator) {
if (player.health > 0)
player.hurt(player.health, true, activator);
}
void shuffle(array<int>& input, jjRNG& rng) {
for (uint i = input.length(); i != 0;) {
int index = rng() % i;
i--;
auto temp = input[index];
input[index] = input[i];
input[i] = temp;
}
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
const auto@ data = playerData[player.localPlayerID];
if (data.trapSelection >= 0) {
const auto@ minimap = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[3]]]];
const int xMap = jjSubscreenWidth - minimap.width;
const int yMap = jjSubscreenHeight - 96 - minimap.height;
const float levelWidth = jjLayerWidth[4] << 5;
const float levelHeight = jjLayerHeight[4] << 5;
canvas.drawSprite(xMap, yMap, ANIM::CUSTOM[3], 0, 0);
for (int i = traps.length(); i-- != 0;) {
const auto@ target = traps[i];
int xTrap = xMap + int(target.x / levelWidth * minimap.width);
int yTrap = yMap + int(target.y / levelHeight * minimap.height);
canvas.drawResizedSprite(xTrap, yTrap, ANIM::FLAG, i == data.trapSelection ? 3 : 7, 0, 0.5f, 0.5f);
}
for (int i = 0; i < 32; i++) {
const auto@ target = jjPlayers[i];
if (target.isInGame) {
int xPlayer = xMap + int(target.xPos / levelWidth * minimap.width);
int yPlayer = yMap + int(target.yPos / levelHeight * minimap.height);
int face = 3;
switch (target.charCurr) {
case CHAR::BIRD:
face = 0;
break;
case CHAR::BIRD2:
face = 1;
break;
case CHAR::FROG:
face = 2;
break;
case CHAR::JAZZ:
face = 3;
break;
case CHAR::LORI:
face = 4;
break;
case CHAR::SPAZ:
face = jjIsTSF ? 5 : 4;
break;
}
canvas.drawResizedSprite(xPlayer, yPlayer, ANIM::FACES, face, 0, 0.5f, 0.5f, SPRITE::PLAYER, i);
}
}
const auto@ trap = traps[data.trapSelection];
jjTEXTAPPEARANCE style;
style.align = STRING::CENTER;
int middle = jjSubscreenWidth / 2;
canvas.drawString(middle, 64, "Activate a Trap?", STRING::LARGE, style);
canvas.drawString(middle, 128, trap.name, STRING::MEDIUM, style);
canvas.drawString(middle, 160, trap.description, STRING::SMALL, style);
canvas.drawString(middle, jjSubscreenHeight - 64, "Press fire to activate a trap (costs 25 coins)", STRING::SMALL, style);
canvas.drawString(middle, jjSubscreenHeight - 48, "Use the arrow keys to switch between traps", STRING::SMALL, style);
canvas.drawString(middle, jjSubscreenHeight - 32, "Press backspace to quit", STRING::SMALL, style);
if (trap.behavior.isActive())
canvas.drawString(middle, jjSubscreenHeight / 2, "Trap already active", STRING::MEDIUM, style, 0, SPRITE::PALSHIFT, 216);
}
return weaponHook.drawAmmo(player, canvas);
}
void onLevelBegin() {
for (int i = 1; i < 255; i++) {
jjOBJ@ preset = jjObjectPresets[i];
if (preset.playerHandling == HANDLING::PICKUP) {
preset.behavior = CannotBeShotDown(preset.behavior);
}
}
jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]] + 4];
for (uint i = 0; i < anim.frameCount; ++i) {
jjANIMFRAME@ frame = jjAnimFrames[anim + i];
jjPIXELMAP sprite(frame);
for (uint x = 0; x < sprite.width; ++x)
for (uint y = 0; y < sprite.height; ++y)
if (sprite[x,y] < 8 && x <= 16 && y >= 2) sprite[x,y] = 71;
sprite.save(frame);
}
jjSampleLoad(SOUND::P2_PTOEI, "bow_fire_arrow.wav");
jjSampleLoad(SOUND::ORANGE_BOEMR, "expmine.wav");
jjSampleLoad(SOUND::COMMON_COLLAPS, "floorslide.wav");
jjSampleLoad(SOUND::CATERPIL_RIDOE, "floorslide.wav");
}
void onLevelLoad() {
createMinimap(jjAnimSets[ANIM::CUSTOM[3]]);
setUpTraps();
jjUseLayer8Speeds = true;
se::roller.loadAnims(jjAnimSets[ANIM::CUSTOM[2]]);
se::roller.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BRAKE});
se::roller.setAsWeapon(2, weaponHook);
jjAnimSets[ANIM::CUSTOM[2]].load(0, "arrowgun.j2a");
jjAnimSets[ANIM::CUSTOM[1]].load(0, "meteor.j2a");
jjAnimSets[ANIM::CUSTOM[0]].load(0, "LaserBlaster.j2a");
jjAnimations[jjAnimSets[ANIM::AMMO] + 29] = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]] + 2];
jjAnimations[jjAnimSets[ANIM::AMMO] + 28] = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]] + 3];
jjAnimations[jjAnimSets[ANIM::PICKUPS] + 62] = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]] + 4];
jjObjectPresets[OBJECT::ICEBULLET].behavior = LaserGun;
jjObjectPresets[OBJECT::ICEBULLET].special = jjObjectPresets[OBJECT::ICEBULLET].determineCurAnim(ANIM::CUSTOM[0], 0);
jjObjectPresets[OBJECT::ICEBULLET].xSpeed = 1.5;
jjObjectPresets[OBJECT::ICEBULLET].counterEnd = 125;
jjObjectPresets[OBJECT::ICEBULLET].freeze = 0;
jjObjectPresets[OBJECT::ICEBULLET].eventID = OBJECT::FIREBALLBULLET;
jjObjectPresets[OBJECT::ICEBULLET].lightType = jjObjectPresets[OBJECT::FIREBALLBULLET].lightType;
jjObjectPresets[OBJECT::ICEBULLETPU].behavior = LaserGunPU;
jjObjectPresets[OBJECT::ICEBULLETPU].special = jjObjectPresets[OBJECT::ICEBULLET].determineCurAnim(ANIM::CUSTOM[0], 1);
jjObjectPresets[OBJECT::ICEBULLETPU].xSpeed = 2;
jjObjectPresets[OBJECT::ICEBULLETPU].counterEnd = 95;
jjObjectPresets[OBJECT::ICEBULLETPU].var[6] = 8;
jjObjectPresets[OBJECT::ICEBULLETPU].freeze = 0;
jjObjectPresets[OBJECT::ICEBULLETPU].eventID = OBJECT::FIREBALLBULLETPU;
jjObjectPresets[OBJECT::ICEBULLET].lightType = jjObjectPresets[OBJECT::FIREBALLBULLET].lightType;
jjObjectPresets[OBJECT::ICEPOWERUP].determineCurAnim(ANIM::CUSTOM[0], 4, true);
jjObjectPresets[OBJECT::ICEPOWERUP].determineCurFrame();
jjObjectPresets[OBJECT::WARP].behavior = coinBooth;
jjWeapons[WEAPON::ICE].spread = SPREAD::NORMAL;
jjSampleLoad(SOUND::AMMO_ICEGUN, "f_laser1.wav");
jjSampleLoad(SOUND::AMMO_ICEGUN2, "f_laser2.wav");
jjSampleLoad(SOUND::AMMO_ICEGUNPU, "f_laser2.wav");
jjSampleLoad(SOUND::AMMO_ICEPU1, "f_laser3.wav");
jjSampleLoad(SOUND::AMMO_ICEPU2, "f_laser3.wav");
jjSampleLoad(SOUND::AMMO_ICEPU3, "f_laser4.wav");
jjSampleLoad(SOUND::AMMO_ICEPU4, "f_laser4.wav");
jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::AMMO] + 82];
for (uint i = 0; i < anim.frameCount; ++i) {
jjANIMFRAME@ frame = jjAnimFrames[anim + i];
jjPIXELMAP sprite(frame);
for (uint x = 0; x < sprite.width; ++x) {
for (uint y = 0; y < sprite.height; ++y) {
if (sprite[x, y] != 0 && sprite[x, y] != 15)
sprite[x, y] += 33;
}
}
sprite.save(frame);
}
}
void onMain() {
for (int i = traps.length(); i-- != 0;) {
traps[i].behavior.process();
}
weaponHook.processMain();
array<jjLAYER@> layers = jjLayerOrderGet();
layers[8].xAutoSpeed = layers[9].xAutoSpeed = 0;
layers[8].xOffset += 0.2f;
layers[9].xOffset += 0.08f;
}
void onPlayer(jjPLAYER@ player) {
auto@ data = playerData[player.localPlayerID];
if (data.trapSelection >= 0) {
if (!player.isInGame || player.health == 0 || jjKey[quitTrapSelectionKey]) {
data.trapSelection = -210;
player.cameraUnfreeze();
} else {
const auto@ trap = traps[data.trapSelection];
player.cameraFreeze(trap.x, trap.y, true, true);
player.showText("");
}
} else if (data.trapSelection < -1) {
data.trapSelection++;
}
weaponHook.processPlayer(player);
if (jjGameMode == GAME::SP && jjGameTicks == 1) {
player.warpToTile(73,57,true);
}
}
void onPlayerInput(jjPLAYER@ player) {
auto@ data = playerData[player.localPlayerID];
if (data.trapSelection >= 0) {
if (player.keyLeft && !data.prevKeyLeft) {
data.trapSelection--;
if (data.trapSelection < 0)
data.trapSelection = traps.length() - 1;
}
if (player.keyRight && !data.prevKeyRight) {
data.trapSelection++;
if (data.trapSelection >= int(traps.length()))
data.trapSelection = 0;
}
if (player.keyFire && !data.prevKeyFire) {
auto@ trap = traps[data.trapSelection];
if (!trap.behavior.isActive() && player.testForCoins(data.trapPrice)) {
trap.behavior.activate(player);
jjSTREAM packet;
packet.push(uint8(trapPacket));
packet.push(uint8(data.trapSelection));
packet.push(uint8(player.playerID));
jjSendPacket(packet);
}
}
}
data.prevKeyFire = player.keyFire;
data.prevKeyLeft = player.keyLeft;
data.prevKeyRight = player.keyRight;
if (data.trapSelection >= 0) {
player.keyDown = false;
player.keyFire = false;
player.keyLeft = false;
player.keyJump = false;
player.keyRight = false;
player.keyRun = false;
player.keyUp = false;
}
weaponHook.processPlayerInput(player);
}
void onReceive(jjSTREAM &in packet, int clientID) {
if (!weaponHook.processPacket(packet, clientID)) {
jjSTREAM copy = packet;
uint8 type;
uint8 trapID;
uint8 playerID;
if (packet.pop(type) && packet.pop(trapID) && packet.pop(playerID)) {
if (type == trapPacket && trapID < traps.length() && playerID < 32) {
auto@ player = jjPlayers[playerID];
if (!jjIsServer || player.clientID == clientID) {
traps[trapID].behavior.activate(player);
if (jjIsServer)
jjSendPacket(copy, -clientID);
}
}
}
}
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.