Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Anniversary Bash 16 Levels | Jazz2Online | Multiple | N/A | |||||
Towerfall | Violet CLM | Battle | 9 |
const int ARROWCOUNT = 3;
const int TRIGNOLIMITS = 10;
const int TRIGARROWTRAILS = 11;
const int TRIGFROZENARROWS = 12;
uint8 CurrentArena = 255;
array<bool> LastTriggerStates(32, false);
array<string> SettingNames = {"Unlimited Arrows", "Glowing Trails", "Ice Arrows"};
void onLevelLoad() {
jjPalette.gradient(157,93,165, 47,0,60);
jjPalette.apply();
jjSetFadeColors();
jjTexturedBGUsed = true;
jjTexturedBGStyle = TEXTURE::TUNNEL;
jjTexturedBGTexture = TEXTURE::XARGON;
jjTileSet(4, 7, 9, 61 | TILE::VFLIPPED);
jjTileSet(4, 6, 10, 61 | TILE::VFLIPPED);
jjTileSet(4, 1, 32, 525 | TILE::VFLIPPED);
jjTileSet(4, 1, 34, 525 | TILE::VFLIPPED);
jjTileSet(4, 1, 38, 525 | TILE::VFLIPPED);
jjTileSet(4, 1, 40, 525 | TILE::VFLIPPED);
jjTileSet(4, 20, 32, 525 | TILE::VFLIPPED);
jjTileSet(4, 0, 30, 525 | TILE::VFLIPPED);
jjTileSet(4, 1, 30, 525 | TILE::VFLIPPED);
jjTileSet(4, 2, 30, 525 | TILE::VFLIPPED);
jjTileSet(4, 3, 30, 525 | TILE::VFLIPPED);
jjWeapons[WEAPON::BLASTER].replenishes = false;
jjWeapons[WEAPON::BLASTER].infinite = false;
jjObjectPresets[OBJECT::SHARD].determineCurAnim(ANIM::PICKUPS, 86);
jjObjectPresets[OBJECT::FLICKERLIGHT].behavior = smokinghot;
jjObjectPresets[OBJECT::BLASTERBULLET].behavior = arrow;
jjObjectPresets[OBJECT::BLASTERBULLET].counterEnd = 45;
jjObjectPresets[OBJECT::BLASTERBULLET].special = 0; //upAnim
jjObjectPresets[OBJECT::BLASTERBULLET].determineCurAnim(ANIM::FLAG, 0);
jjObjectPresets[OBJECT::BLASTERBULLET].killAnim = jjObjectPresets[OBJECT::BOUNCERAMMO3].killAnim;
jjObjectPresets[OBJECT::BLASTERBULLET].eventID = OBJECT::SMALLTREE; //non-solid
jjObjectPresets[OBJECT::BLASTERBULLET].var[6] = 16; //fireball-like; doesn't explode upon contact with players
jjObjectPresets[OBJECT::ICEBULLET].behavior = arrow;
jjObjectPresets[OBJECT::ICEBULLET].counterEnd = 70; //a little longer
jjObjectPresets[OBJECT::ICEBULLET].special = 0; //upAnim
jjObjectPresets[OBJECT::ICEBULLET].determineCurAnim(ANIM::FLAG, 0);
jjObjectPresets[OBJECT::ICEBULLET].killAnim = jjObjectPresets[OBJECT::BOUNCERAMMO3].killAnim;
jjObjectPresets[OBJECT::ICEBULLET].eventID = OBJECT::SMALLTREE;
jjObjectPresets[OBJECT::ICEBULLET].var[6] = 16;
jjObjectPresets[OBJECT::REDSPRING].isFreezable = false;
jjObjectPresets[OBJECT::GREENSPRING].isFreezable = false;
jjObjectPresets[OBJECT::BLUESPRING].isFreezable = false;
jjMusicLoad("castle.j2b"); //in case you're a client and didn't download the proper music.
jjMusicLoad("TR2-Train.xm"); //in case you did!
}
void onLevelBegin() {
if (jjGameConnection == GAME::LOCAL || jjIsServer) {
jjChat("/allowmouseaim on");
jjTriggers[jjRandom() & 7] = true;
}
if (jjIsServer || jjIsAdmin)
jjLocalPlayers[0].showText("@@@@@@@Trigger " + TRIGNOLIMITS + ": Players may collect infinite arrows.@Trigger " + TRIGARROWTRAILS + ": Arrows leave trails.@Trigger " + TRIGFROZENARROWS + ": Players may shoot ice arrows.");
for (int i = 0; i < 32; ++i) {
jjPlayers[i].score = ARROWCOUNT;
}
}
void onMain() {
jjTexturedBGFadePositionX = jjSin(jjGameTicks << 1) / 2 + .5;
jjTexturedBGFadePositionY = jjCos(jjGameTicks << 1) / 2 + .5;
if (CurrentArena == 255) {
for (int i = 0; i < 8; ++i)
if (jjTriggers[i]) {
CurrentArena = i;
if (i == 7) jjLayerYOffset[3] = -16; //adjust the spikes a little
break;
}
} else for (int i = 1; i < jjObjectCount; ++i) {
jjOBJ@ obj = jjObjects[i];
if (obj.eventID == OBJECT::SMALLTREE && obj.behavior == BEHAVIOR::EXPLOSION2) { //arrow collected by non-local player
obj.eventID = 0; //already been looked at
int playerID = obj.findNearestPlayer(75*75);
if (playerID >= 0 && !jjPlayers[playerID].isLocal)
++jjPlayers[playerID].score; //try to keep a running tally of everyone's ammo counts
}
}
for (int i = 0; i < 32; ++i) {
jjPLAYER@ play = jjPlayers[i];
if (play.isActive && play.health > 0) {
int ammo = play.score;
play.ammo[WEAPON::BLASTER] = ammo;
play.ammo[WEAPON::ICE] = (jjTriggers[TRIGFROZENARROWS]) ? ammo : 0;
float yPos = play.yPos - 25;
uint8 shift = 0;
if (jjGameMode == GAME::CTF) {
if (play.teamRed) shift = 248;
} else if (!play.isLocal) shift = 248;
if (jjTriggers[TRIGNOLIMITS]) { //limitless potential storage
float xPos = play.xPos - (ammo-1)*14/2;
while (ammo-- > 0) {
jjDrawSprite(xPos, yPos, ANIM::BRIDGE, 5, 0, 0, SPRITE::PALSHIFT, shift, 1);
xPos += 14;
}
} else {
float xPos = play.xPos - (ARROWCOUNT-1)*14/2;
for (int i = 0; i < ARROWCOUNT; ++i) {
if (ammo-- > 0)
jjDrawSprite(xPos, yPos, ANIM::BRIDGE, 5, 0, 0, SPRITE::PALSHIFT, shift, 1);
else
jjDrawSprite(xPos, yPos, ANIM::BRIDGE, 5, 0, 0, SPRITE::SINGLECOLOR, 0, 1);
xPos += 14;
}
}
//jjDrawString(play.xPos, play.yPos + 10, "" + play.ammo[WEAPON::BLASTER]);
//jjDrawString(play.xPos, play.yPos + 20, "" + play.ammo[WEAPON::ICE]);
}
}
if (jjIsServer) {
for (int i = TRIGNOLIMITS; i <= TRIGFROZENARROWS; ++i) {
if (jjTriggers[i] != LastTriggerStates[i]) {
LastTriggerStates[i] = jjTriggers[i];
jjChat("\xA71||||" + SettingNames[i - TRIGNOLIMITS] + " have been |||||" + ((jjTriggers[i]) ? "ENABLED" : "|DISABLED"));
}
}
}
}
array<SOUND::Sample> RicochetNoises = {SOUND::AMMO_BULFL1, SOUND::AMMO_BULFL2, SOUND::AMMO_BULFL3};
void arrow(jjOBJ@ obj) {
if (obj.state == STATE::START) {
jjPLAYER@ play = jjPlayers[obj.creatorID];
bool local = play.isLocal;
//do a wee bit of hackery to determine what the firing player's ammo count is
if (local) --play.score;
else if (jjTriggers[TRIGFROZENARROWS] && play.ammo[WEAPON::ICE] < play.ammo[WEAPON::BLASTER]) play.score = play.ammo[WEAPON::ICE];
else if (play.ammo[WEAPON::ICE] == 1 && play.ammo[WEAPON::BLASTER] == 1) play.score = 0; //JJ2+ bug
else play.score = play.ammo[WEAPON::BLASTER];
if (jjGameMode == GAME::CTF) {
if (play.teamRed) obj.frameID = 1;
} else if (!local) obj.frameID = 1;
obj.determineCurFrame();
obj.state = STATE::SLEEP;
if (obj.xSpeed < 0 == obj.var[7] < 0)
obj.xSpeed = obj.xSpeed + obj.var[7] / 65536.;
if (!jjIsServer && !local)
obj.playerHandling = HANDLING::PICKUP; //increase chances of accepting packets telling you that other players picked up this arrow
} else if (obj.state == STATE::SLEEP) {
float angle = atan2(obj.xSpeed, obj.ySpeed);
if (!obj.scriptedCollisions) {
if (obj.lightType == LIGHT::BRIGHT) { //on fire
jjPARTICLE@ fire = jjAddParticle(PARTICLE::FIRE);
if (fire !is null) {
fire.xPos = obj.xPos;
fire.yPos = obj.yPos;
fire.fire.size = jjGameTicks & 3;
}
if ((jjGameTicks & 1) == 0)
jjObjects[jjAddObject(OBJECT::SHARD, obj.xPos, obj.yPos, obj.objectID)].lightType = LIGHT::POINT2;
} else if (jjTriggers[TRIGARROWTRAILS] && (jjGameTicks & 1) == 0)
jjAddObject(OBJECT::EXPLOSION, obj.xPos, obj.yPos, obj.objectID, CREATOR::OBJECT, invisibru);
obj.xOrg = obj.xOrg + obj.xSpeed;
obj.yOrg = obj.yOrg + obj.ySpeed;
if (obj.xOrg < 32) {
obj.xOrg = obj.xOrg + 640;
if (CurrentArena == 6) {
if (obj.yOrg < 3200)
obj.yOrg = obj.yOrg + 9*32;
else
obj.yOrg = obj.yOrg - 9*32;
}
} else if (obj.xOrg >= 672) {
obj.xOrg = obj.xOrg - 640;
if (CurrentArena == 6) {
if (obj.yOrg < 3200)
obj.yOrg = obj.yOrg + 9*32;
else
obj.yOrg = obj.yOrg - 9*32;
}
}
else if (obj.yOrg >= jjLayerHeight[4] * 32) obj.yOrg = obj.yOrg - 32*15;
obj.xPos = obj.xOrg - sin(angle) * 26;
obj.yPos = obj.yOrg - cos(angle) * 26;
if (jjMaskedPixel(obj.xOrg, obj.yOrg)) {
if (jjEventGet(obj.xOrg / 32, obj.yOrg / 32) == AREA::RICOCHET && obj.var[9] < 5) {
//don't want to use the normal .ricochet() method because it's too random and not y-oriented enough
jjSample(obj.xPos, obj.yPos, RicochetNoises[jjGameTicks % 3]);
jjPARTICLE@ spark = jjAddParticle(PARTICLE::SPARK);
if (spark !is null) {
spark.xPos = obj.xOrg;
spark.yPos = obj.yOrg;
spark.xSpeed = obj.xSpeed / 4;
spark.ySpeed = obj.ySpeed / 4;
}
obj.xSpeed = -obj.xSpeed;
obj.ySpeed = -obj.ySpeed;
obj.var[9] = obj.var[9] + 1; //can't ricochet foreverrrr
} else {
jjSample(obj.xPos, obj.yPos, SOUND::AMMO_BUL1);
for (int i = 0; i < 7; ++i) {
jjPARTICLE@ debris = jjAddParticle(PARTICLE::PIXEL);
if (debris !is null) {
debris.xPos = obj.xPos;
debris.yPos = obj.yPos;
uint rand = jjRandom();
debris.xSpeed = (rand & 1023) / 256. - 2;
debris.ySpeed = ((rand >> 10) & 1023) / 256. - 2;
debris.pixel.size = 2; //3x3
for (int j = 0; j < 9; ++j)
debris.pixel.color[j] = (jjRandom() & 15) + 96;
}
}
obj.var[3] = obj.var[2];
obj.playerHandling = HANDLING::PICKUP;
obj.scriptedCollisions = true;
}
}
else {
if (obj.light != 12 && jjEventGet(obj.xOrg / 32, obj.yOrg / 32) == OBJECT::FLICKERLIGHT) { //torch
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN);
obj.freeze = 0; //duh
obj.light = 12;
if (jjMaxHealth > 1) { //not instagib
obj.var[6] = obj.var[6] | 8; //powerup
obj.lightType = LIGHT::BRIGHT;
}
}
obj.ySpeed = obj.ySpeed + .15;
if (obj.ySpeed > 20) obj.ySpeed = 20;
obj.var[2] = (angle - 2) * 1024 * 40; //#codethatjustworks
}
} else {
if (obj.counterEnd > 0) {
if (--obj.counterEnd == 0 && obj.freeze == 0) { obj.lightType = LIGHT::NONE; obj.light = 0; }
else {
obj.var[2] = obj.var[3] + jjSin((jjGameTicks + obj.objectID) << 6) * obj.counterEnd * 512;
float angle = (obj.var[2] + 81920) / (40. * 1024.); //#codethatjustworksinreverse
obj.xPos = obj.xOrg - sin(angle) * 26;
obj.yPos = obj.yOrg - cos(angle) * 26;
}
} else
obj.yPos = obj.yOrg - cos(angle) * 26 + jjSin(((obj.objectID * 8 + jjGameTicks) + int(obj.xOrg) + int(obj.yOrg) * 256)*16) * 4;
}
obj.behave(BEHAVIOR::POLE); //Draw curFrame rotated at an angle based on var[2]. Because state is STILL and eventID is SMALLTREE, this behavior does absolutely nothing besides draw the sprite.
if (obj.lightType == LIGHT::BRIGHT)
jjDrawSprite(obj.xPos, obj.yPos, ANIM::AMMO, /*obj.frameID * */ 13, jjGameTicks % 7);
//jjDrawSprite(obj.xPos, obj.yPos, ANIM::AMMO, 2, 0);
//jjDrawSprite(obj.xOrg, obj.yOrg, ANIM::AMMO, 2, 0, 0, SPRITE::PALSHIFT, 8);
}
}
void invisibru(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.counterEnd = 0;
obj.lightType = LIGHT::POINT;
obj.light = 1;
obj.state = STATE::EXPLODE;
} else if (obj.counterEnd++ >= 20) obj.delete();
}
void smokinghot(jjOBJ@ obj) {
uint rand = jjRandom();
if ((rand & 3) == 0) {
rand >>= 2;
jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
if (smoke !is null) {
smoke.xPos = obj.xOrg + (rand & 31) - 16;
rand >>= 5;
smoke.yPos = obj.yOrg + (rand & 31) - 16;
}
}
}
void onObjectHit(jjOBJ@ object, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if (bullet is null && object.eventID == OBJECT::SMALLTREE) {
int ammo = player.score;
if (!player.isLocal || (object.counterEnd == 0 && (ammo < ARROWCOUNT || jjTriggers[TRIGNOLIMITS]) && player.health > 0)) {
object.state = STATE::EXPLODE; //this one may not actually be needed
object.scriptedCollisions = false;
object.behavior = BEHAVIOR::EXPLOSION2;
object.eventID = 0;
++player.score;
if (object.freeze > 0) {
player.frozen = object.freeze;
object.unfreeze(0);
} else
jjSample(object.xPos, object.yPos, SOUND::COMMON_PICKUPW1);
}
}
}
bool onDrawScore(jjPLAYER@ play, jjCANVAS@ screen) { return true; }
bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ screen) { return !jjTriggers[TRIGFROZENARROWS]; }
void onPlayer(jjPLAYER@ play) {
if (play.yPos < 16 && CurrentArena != 255) {
//play.warpToID(CurrentArena, true);
jjEventSet(0,0, AREA::WARP); //by waiting until the player can process a warp event, we avoid bizarre level-initial deaths
jjParameterSet(0,0, 0,8, CurrentArena);
//if (jjGameConnection != GAME::LOCAL) //local camera freezing results in shaking for some reason, but fixed by making level bigger
play.cameraFreeze(play.subscreenX+32, play.subscreenY + CurrentArena*480, false, true);
}
else if (play.xPos < 32) {
play.xPos = play.xPos + 640;
if (CurrentArena == 6) {
if (play.yPos < 3200)
play.yPos = play.yPos + 9*32;
else
play.yPos = play.yPos - 9*32;
}
} else if (play.xPos >= 672) {
play.xPos = play.xPos - 640;
if (CurrentArena == 6) {
if (play.yPos < 3200)
play.yPos = play.yPos + 9*32;
else
play.yPos = play.yPos - 9*32;
}
}
if (!(int(play.yPos / 32) == 84 && play.ySpeed == 0)) //not on vine
play.keyDown = false;
if (play.score == 0 || play.yPos < 16 || play.frozen > 0) { play.keyFire = false; play.currWeapon = WEAPON::BLASTER; }
}
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.