Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Anniversary Bash 22 levels | Jazz2Online | Multiple | N/A | |||||
Astolfo | Seren | Battle | 10 |
#pragma require "SEroller.asc"
#include "SEroller.asc"
funcdef float EasingFunction(float);
class Point {
int x, y;
Point() {}
Point(int X, int Y) {
x = X;
y = Y;
}
}
class Timer {
private EasingFunction@ easing;
private const jjANIMATION@ anim;
private int animFrameDelay;
private int frameCounter;
private int curFrame;
private bool visible;
private int visibility;
private int maxVisibility;
private float posAlpha;
private float posBeta;
private int time;
private string oldText;
private string newText;
private STRING::Size size;
private int transition;
private int maxTransition;
private int textAlpha;
private int textBeta;
private float offsetAlpha;
private float offsetBeta;
private float maxOffset;
jjTEXTAPPEARANCE style;
Timer() {
@easing = function(t) {
const float c = 1.70158f;
const float a3 = c + 1.f;
const float a2 = -2.f * c - 3.f;
const float a1 = c + 3.f;
return t * (t * (t * a3 + a2) + a1);
};
@anim = jjAnimations[jjAnimSets[ANIM::PICKUPS] + 40];
animFrameDelay = 4;
maxVisibility = 35;
size = STRING::MEDIUM;
maxTransition = 15;
maxOffset = 16.f;
}
void setVisible(bool value) {
visible = value;
}
void setTime(int value, bool playSample) {
if (time != value) {
time = value;
oldText = newText;
newText = formatInt(value);
transition = visibility == 0 ? maxTransition : 0;
if (playSample)
jjSamplePriority(value == 0 ? SOUND::COMMON_BELL_FIRE : SOUND::COMMON_BELL_FIRE2);
}
}
void process() {
frameCounter++;
curFrame = anim + frameCounter / animFrameDelay % anim.frameCount;
if (visible) {
if (visibility < maxVisibility)
visibility++;
} else {
if (visibility > 0)
visibility--;
}
float t = float(visibility) / maxVisibility;
posBeta = easing(t);
posAlpha = 1.f - posBeta;
if (transition < maxTransition) {
transition++;
float a = float(transition) / maxTransition;
textBeta = int(a * 255.f);
textAlpha = 255 - textBeta;
offsetAlpha = -a * maxOffset;
offsetBeta = maxOffset + offsetAlpha;
}
}
void draw(jjCANVAS@ canvas, float x0, float y0, float x1, float y1) const {
int x = int(x0 * posAlpha + x1 * posBeta);
float y = y0 * posAlpha + y1 * posBeta;
if (curFrame != 0)
canvas.drawSpriteFromCurFrame(x, int(y), curFrame);
x += jjAnimFrames[anim].width + jjAnimFrames[anim].hotSpotX;
canvas.drawString(x, int(y + offsetAlpha), oldText, size, style, 0, SPRITE::BLEND_NORMAL, textAlpha);
canvas.drawString(x, int(y + offsetBeta), newText, size, style, 0, SPRITE::BLEND_NORMAL, textBeta);
}
}
const array<int> powerupEventIDs = {
OBJECT::BLASTERPOWERUP,
OBJECT::BOUNCERPOWERUP,
OBJECT::ICEPOWERUP,
OBJECT::SEEKERPOWERUP,
OBJECT::RFPOWERUP,
OBJECT::TOASTERPOWERUP,
OBJECT::TNTPOWERUP,
OBJECT::GUN8POWERUP,
OBJECT::GUN9POWERUP,
};
bool powerupsEnabled = false;
int powerupSpawnTimesAtPrevTick = -3;
se::DefaultWeaponHook weaponHook;
array<Point> oneWays;
array<bool> specialMove(jjLocalPlayerCount);
array<int> fastSpringSpeeds(jjLocalPlayerCount);
array<int> flyCarrotTime(jjLocalPlayerCount);
array<Timer> flyCarrotTimers(jjLocalPlayerCount);
void prepareOneWays() {
for (int i = 0; i < jjLayerHeight[4]; i++) {
for (int j = 0; j < jjLayerWidth[4]; j++) {
if (jjEventGet(j, i) == AREA::ONEWAY)
oneWays.insertLast(Point(j, i));
}
}
}
void enforceOneWays(jjPLAYER@ player) {
bool previousSpecialMove = specialMove[player.localPlayerID];
bool currentSpecialMove = player.specialMove != 0 && jjCharacters[player.charCurr].groundJump != GROUND::JAZZ;
if (currentSpecialMove ^^ previousSpecialMove) {
for (uint i = 0; i < oneWays.length(); i++) {
const Point@ tile = oneWays[i];
jjEventSet(tile.x, tile.y, currentSpecialMove ? 0 : AREA::ONEWAY);
}
specialMove[player.localPlayerID] = currentSpecialMove;
}
}
void handleFastSpringSpeeds(jjPLAYER@ player) {
if (player.ySpeed < -32.f) {
fastSpringSpeeds[player.localPlayerID] = int(ceil((player.ySpeed + 32.f) / -0.125f));
} else if (fastSpringSpeeds[player.localPlayerID] != 0) {
if (player.ySpeed < -31.f) {
fastSpringSpeeds[player.localPlayerID]--;
player.ySpeed = -32.f;
} else {
fastSpringSpeeds[player.localPlayerID] = 0;
}
}
}
void handleFlight(jjPLAYER@ player) {
Timer@ timer = flyCarrotTimers[player.localPlayerID];
if (flyCarrotTime[player.localPlayerID] > 0) {
if (player.fly == FLIGHT::FLYCARROT) {
flyCarrotTime[player.localPlayerID]--;
if (flyCarrotTime[player.localPlayerID] == 0)
player.fly = FLIGHT::NONE;
timer.setTime((flyCarrotTime[player.localPlayerID] + 69) / 70, flyCarrotTime[player.localPlayerID] < 250);
} else {
flyCarrotTime[player.localPlayerID] = 0;
}
}
timer.setVisible(flyCarrotTime[player.localPlayerID] > 0);
timer.process();
}
void moveGenerators() {
array<Point> positions;
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ obj = jjObjects[i];
if (obj.isActive) {
Point position(int(obj.xPos) >>> 5, int(obj.yPos) >>> 5);
int tile = jjTileGet(2, position.x, position.y);
if (tile != 0) {
obj.xPos += ((tile + 2) % 9 - 1 << 5) / 3.f;
obj.yPos += ((tile + 2) / 9 - 3 << 5) / 3.f;
positions.insertLast(position);
}
}
}
for (int i = positions.length(); i-- != 0;) {
const Point@ position = positions[i];
jjTileSet(2, position.x, position.y, 0);
}
jjLayerHasTiles[2] = false;
}
void detectPowerupsEnabled() {
if (jjIsServer) {
int powerupSpawnTimes = -1;
for (int i = 1; i < jjObjectCount; i++) {
const jjOBJ@ obj = jjObjects[i];
if (obj.eventID == OBJECT::GENERATOR && powerupEventIDs.find(obj.var[3]) >= 0) {
if (obj.var[0] > 0 && jjObjects[obj.var[0]].isActive && jjObjects[obj.var[0]].creatorID == uint(i)) {
powerupSpawnTimes = -2;
break;
} else if (powerupSpawnTimes == -1) {
powerupSpawnTimes = obj.var[1];
} else if (obj.var[1] != powerupSpawnTimes) {
powerupSpawnTimes = -2;
break;
}
}
}
bool newPowerupsEnabled = powerupSpawnTimesAtPrevTick == -3 ? powerupsEnabled : powerupSpawnTimes == -2 || powerupSpawnTimes != powerupSpawnTimesAtPrevTick;
powerupSpawnTimesAtPrevTick = powerupSpawnTimes;
if (newPowerupsEnabled != powerupsEnabled) {
powerupsEnabled = newPowerupsEnabled;
jjSTREAM packet;
packet.push(powerupsEnabled);
jjSendPacket(packet);
}
}
}
void grantPoints(jjPLAYER@ player, jjOBJ@ obj) {
if (obj.points > 0 && (jjGameMode == GAME::SP || jjGameMode == GAME::COOP)) {
player.score += obj.points;
jjPARTICLE@ part = jjAddParticle(PARTICLE::STRING);
if (part !is null) {
part.xPos = obj.xPos;
part.yPos = obj.yPos;
part.xSpeed = -(0x8000 + (jjRandom() & 0x3FFF)) / float(0x10000);
part.ySpeed = -(0x10000 + (jjRandom() & 0x7FFF)) / float(0x10000);
part.string.text = formatInt(obj.points);
}
obj.points = 0;
}
}
float getPickupY(const jjOBJ@ obj) {
bool floating = obj.state == STATE::FLOAT || obj.behavior != BEHAVIOR::PICKUP;
int arg = (((obj.objectID << 3) + jjGameTicks) << (floating && obj.yPos > jjWaterLevel ? 1 : 4)) + (floating ? int(obj.xPos) << 4 : 0);
return obj.yPos + jjSin(arg) * 4.f;
}
void turnPickupIntoFlyCarrot(jjOBJ@ obj, int time) {
const jjOBJ@ flyCarrot = jjObjectPresets[OBJECT::FLYCARROT];
obj.eventID = OBJECT::FLYCARROT;
obj.counter = time;
obj.curAnim = flyCarrot.curAnim;
obj.curFrame = flyCarrot.curFrame;
obj.points = flyCarrot.points;
obj.scriptedCollisions = true;
}
void drawFlyCarrotPickupTimer(const jjOBJ@ obj, int alpha = 255, int layer = 4) {
jjTEXTAPPEARANCE style;
style.align = STRING::CENTER;
jjDrawString(obj.xPos - 3.f, obj.yPos + 22.f, formatInt(obj.counter / 70), STRING::SMALL, style, 0, SPRITE::BLEND_LUMINANCE, alpha, layer);
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
flyCarrotTimers[player.localPlayerID].draw(canvas, jjSubscreenWidth + 32, jjSubscreenHeight / 2, jjSubscreenWidth - 64, jjSubscreenHeight / 2);
return weaponHook.drawAmmo(player, canvas);
}
void onLevelBegin() {
jjWeapons[WEAPON::GUN8].allowedPowerup = true;
moveGenerators();
}
void onLevelLoad() {
if (!jjIsServer)
jjSendPacket(jjSTREAM());
jjUseLayer8Speeds = true;
prepareOneWays();
jjObjectPresets[OBJECT::BLUESPRING].ySpeed = -35.f;
turnPickupIntoFlyCarrot(jjObjectPresets[OBJECT::EXTRATIME], 490);
turnPickupIntoFlyCarrot(jjObjectPresets[OBJECT::EXTRALIFE], 700);
se::roller.loadAnims(jjAnimSets[ANIM::CUSTOM[0]]);
se::roller.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
se::roller.setAsWeapon(4, weaponHook);
}
void onMain() {
for (int i = 6; i <= 7; i++) {
jjLayerXOffset[i] = (jjLayerXOffset[i] + (i == 6 ? -1.f : 1.f)) % (jjLayerWidth[i] * 32);
}
for (int i = 1; i < jjObjectCount; i++) {
const jjOBJ@ obj = jjObjects[i];
if (obj.playerHandling == HANDLING::PICKUP) {
int x = int(obj.xPos);
int y = int(obj.yPos);
int tile = jjTileGet(3, x >>> 5, y >>> 5);
bool isFlyCarrot = obj.eventID == OBJECT::FLYCARROT;
if (isFlyCarrot)
drawFlyCarrotPickupTimer(obj);
if (tile != 0) {
jjPIXELMAP image(tile);
if (image[x & 31, y & 31] != 0) {
int alpha = jjAnimFrames[obj.curFrame].transparent ? 32 : 64;
jjDrawSpriteFromCurFrame(obj.xPos, getPickupY(obj), obj.curFrame, obj.direction, SPRITE::BLEND_NORMAL, alpha, 3);
if (isFlyCarrot)
drawFlyCarrotPickupTimer(obj, alpha, 3);
}
}
}
}
detectPowerupsEnabled();
weaponHook.processMain();
}
void onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int) {
if (bullet is null && obj.eventID == OBJECT::FLYCARROT) {
player.fly = FLIGHT::FLYCARROT;
player.doubleJumpCount = 0;
if (player.isLocal && flyCarrotTime[player.localPlayerID] < obj.counter)
flyCarrotTime[player.localPlayerID] = obj.counter;
grantPoints(player, obj);
obj.frameID = 0;
obj.behavior = BEHAVIOR::EXPLOSION2;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1);
}
}
void onPlayer(jjPLAYER@ player) {
if (jjColorDepth == 8) {
jjEnforceLighting = LIGHT::COMPLETE;
player.lighting = 110;
} else {
jjEnforceLighting = LIGHT::OPTIONAL;
player.lighting = 100;
}
if (player.ammo[WEAPON::GUN8] == 0 || !player.powerup[WEAPON::GUN8])
player.powerup[WEAPON::GUN8] = powerupsEnabled;
enforceOneWays(player);
handleFastSpringSpeeds(player);
handleFlight(player);
weaponHook.processPlayer(player);
}
void onPlayerInput(jjPLAYER@ player) {
weaponHook.processPlayerInput(player);
}
void onReceive(jjSTREAM &in packet, int clientID) {
if (jjIsServer) {
jjSTREAM response;
response.push(powerupsEnabled);
jjSendPacket(response, clientID);
} else {
packet.pop(powerupsEnabled);
}
}
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.