Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Anniversary Bash 25 Battle | Jazz2Online | Battle | N/A | |||||
Anniversary Bash 20 Levels | Jazz2Online | Multiple | N/A | |||||
Anniversary Bash 18 Levels | Jazz2Online | Multiple | N/A | |||||
Decimation | Seren | Battle | 8.5 |
namespace palshift {
const array<uint8> ammoCount = {208, 232, 240, 216};
const uint8 asmdParticle = 221;
const uint8 barrel = 64;
const uint8 barrelDurability = 232;
const uint8 enemyHealth = 216;
const uint8 flak = 32;
const array<uint8> machineBadge = {249, 1, 241, 1, 249, 249, 9, 9, 17, 33};
const uint8 machineShard = 248;
const array<uint8> machineSpring = {0, 8, 248, 8, 0, 0, 16, 16, 0, 248};
const array<uint8> rocketShard = {200, 248};
const array<uint8> turret = {0, 248, 232, 248, 240, 240, 0, 0, 8, 24};
const uint8 turretDurability = 16;
}
namespace rabbit {
const int blinkingTime = 40;
}
namespace tileset {
const uint blackLine = 131;
const uint blackSquare = 114;
const uint empty = 0;
const uint healthBar = 230;
const uint ventShaft = 19;
const uint wall = 10;
const uint weaponLarge = 140;
const uint weaponSmall = 200;
const uint weaponSmallInactive = 205;
}
namespace trigger {
enum option {disableSD, friendlyFire, damageAmplifier}
}
namespace weapon {
const uint8 count = client::isCoopOrSP() ? 4 : 6;
const int dispersionPistolRegenerationTime = 80;
const int displayTime = 40;
const array<int> fireInterval = {0, 25, 5, 32, 70, 40, 1, 0, 0, 0};
const uint8 first = 1;
enum flags {maxDamage = 7, allowSD = 8}
const array<string> name = {"0", "Dispersion Pistol", "Machine Gun", "ASMD", "Rocket Launcher", "Flak Cannon", "Flamethrower", "7", "8", "9"};
const array<int> pickupMultiplier = {0, 1, 20, 4, 1, 1, 50, 0, 0, 0};
}
interface Itile {
void step();
}
class TlocalPlayer {
int dispersionPistolRegenerationTimer, fireIntervalTimer, weaponChangeTimer;
bool keyFirePrevious;
uint8 weaponLastShot, weaponPrevious;
TlocalPlayer() {
dispersionPistolRegenerationTimer = fireIntervalTimer = weaponChangeTimer = 0;
weaponPrevious = weaponLastShot = WEAPON::BLASTER;
keyFirePrevious = false;
}
}
class Tsprite {
int x, y, direction;
uint frame;
SPRITE::Mode mode;
uint8 param;
void draw(jjCANVAS@ canvas) const {
canvas.drawSpriteFromCurFrame(x, y, frame, direction, mode, param);
}
}
class TventShaft : Itile {
private int x, y;
private float xHigh, xLow, yHigh, yLow;
TventShaft(int X, int Y) {
x = X * 32 + 12;
y = Y * 32 + 12;
xHigh = x + 328;
yHigh = y + 248;
xLow = x - 320;
yLow = y - 240;
}
void step() {
if (client::isIdleServer())
return;
if (jjGameTicks & 1 == 0) {
const uint random = jjRandom();
if (random & 1 == 0) {
for (int i = 0; i < jjLocalPlayerCount; i++) {
const jjPLAYER@ player = jjLocalPlayers[i];
if (player.cameraX < xHigh && player.cameraY <= yHigh && player.cameraX + jjSubscreenWidth > xLow && player.cameraY + jjSubscreenHeight > yLow) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::SMOKE);
if (part !is null) {
part.xPos = x + (random >> 1 & 7);
part.yPos = y + (random >> 4 & 7);
part.ySpeed = (random >> 7 & 3) / 4.f - 1.5f;
}
return;
}
}
}
}
}
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
if (client::isIdleServer())
return true;
if (jjSubscreenWidth >= 640 && jjSubscreenHeight >= 384) {
draw::weaponIconBarVertical(canvas, jjSubscreenWidth - 88, jjSubscreenHeight / 2, player);
} else if (jjSubscreenWidth >= 640) {
draw::weaponIconBarHorizontal(canvas, jjSubscreenWidth / 2, jjSubscreenHeight - 40, player);
} else if (jjSubscreenWidth >= 512 || jjSubscreenHeight >= 400) {
uint8 weapon = player.currWeapon;
draw::largeWeaponIcon(canvas, jjSubscreenWidth - 176, jjSubscreenHeight - 80, weapon - 1);
draw::ammoCounter(canvas, jjSubscreenWidth - 176, jjSubscreenHeight - 24, player.ammo[weapon], jjWeapons[weapon].maximum, true);
if (client::localPlayer[player.localPlayerID].weaponChangeTimer > 0)
draw::weaponName(canvas, jjSubscreenWidth - 16, jjSubscreenHeight - 72, weapon);
} else {
uint8 weapon = player.currWeapon;
draw::smallWeaponIcon(canvas, jjSubscreenWidth - 88, jjSubscreenHeight - 40, weapon - 1, true);
draw::ammoCounter(canvas, jjSubscreenWidth - 88, jjSubscreenHeight - 8, player.ammo[weapon], jjWeapons[weapon].maximum, true);
}
return true;
}
bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
if (client::isIdleServer())
return true;
if (jjSubscreenWidth >= 512 || jjSubscreenHeight >= 400) {
draw::healthBar(canvas, 16, text::getScoreHUDHeight(jjGameMode), player.health, jjMaxHealth, player.blink > 0 && jjGameTicks >> 2 & 1 == 0);
return true;
}
return false;
}
void onDrawLayer3(jjPLAYER@, jjCANVAS@ canvas) {
if (client::isIdleServer())
return;
sprite::drawQueue(canvas, 2);
jjTileType[tileset::blackLine] = jjTileType[tileset::blackSquare] = 1;
}
void onDrawLayer4(jjPLAYER@, jjCANVAS@ canvas) {
if (client::isIdleServer())
return;
if (!client::isCoopOrSP()) {
for (int i = 0; i < jjObjectCount; i++) {
jjOBJ@ obj = jjObjects[i];
if (!obj.isActive || obj.eventID != OBJECT::GENERATOR)
continue;
if (obj.direction == 0)
obj.direction = obj.var[3] != OBJECT::TNT && (obj.xPos / 32 % 2 > 1 ^^ obj.yPos / 32 % 2 > 1) ? -1 : 1;
bool draw = obj.var[0] <= 0;
if (!draw) {
jjOBJ@ item = jjObjects[obj.var[0]];
draw = !item.isActive || item.creatorType != CREATOR::LEVEL || item.creatorID != uint(obj.objectID);
}
if (draw)
canvas.drawSpriteFromCurFrame(int(obj.xPos), int(obj.yPos), jjObjectPresets[obj.var[3]].curFrame, obj.direction, SPRITE::SINGLECOLOR, 79);
}
}
sprite::drawQueue(canvas, 3);
}
void onDrawLayer7(jjPLAYER@, jjCANVAS@) {
jjTileType[tileset::blackLine] = jjTileType[tileset::blackSquare] = 0;
}
bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) {
if (client::isIdleServer())
return true;
if ((jjGameMode == GAME::COOP || jjGameMode == GAME::SP) && (jjSubscreenWidth >= 512 || jjSubscreenHeight >= 400)) {
string text = formatInt(player.lives, "");
canvas.drawString(43 - text::getSmallFontIntWidth(text) / 2, text::getScoreHUDHeight(jjGameMode) + 33, text);
return true;
}
return false;
}
bool onDrawScore(jjPLAYER@, jjCANVAS@) {
return true;
}
void onLevelLoad() {
initialize::objectPresets();
initialize::weaponProfiles();
initialize::specialTiles();
initialize::palette();
jjTexturedBGTexture = TEXTURE::WTF;
if (client::isCoopOrSP()) {
for (int i = 0; i < jjLayerHeight[4]; i++) {
for (int j = 0; j < jjLayerWidth[4]; j++) {
if (jjParameterGet(j, i, -4, 2) == 3)
jjEventSet(j, i, 0);
}
}
if (jjGameConnection == GAME::LOCAL) {
jjChat("/flipmousewheel on");
jjChat("/allowmouseaim on");
if (jjLocalPlayerCount == 1)
jjChat("/mouseaim on");
else
jjChat("/mouseaim off");
int health = 6 - jjDifficulty;
if (jjStartHealth != health || jjMaxHealth != health)
jjChat("/smhealth " + formatInt(health, ""));
}
}
}
void onLevelReload() {
initialize::palette();
}
void onMain() {
for (int i = 0; i < 32; i++) {
jjPLAYER@ player = jjPlayers[i];
if (player.blink < -rabbit::blinkingTime)
player.blink = -rabbit::blinkingTime;
}
for (uint i = 0; i < level::specialTile.length(); i++) {
level::specialTile[i].step();
}
if ((jjIsServer || jjIsAdmin) && !client::admin) {
jjAlert("/trigger " + formatInt(trigger::disableSD, "") + " " + (jjTriggers[trigger::disableSD] ? "off - enable" : "on - disable") + " Self-Destruction");
jjAlert("/trigger " + formatInt(trigger::friendlyFire, "") + " " + (jjTriggers[trigger::friendlyFire] ? "off - disable" : "on - enable") + " Friendly Fire");
jjAlert("/trigger " + formatInt(trigger::damageAmplifier, "") + " " + (jjTriggers[trigger::damageAmplifier] ? "off - disable" : "on - enable") + " Damage Amplifier");
client::admin = true;
}
if (client::isCoopOrSP()) {
for (int i = 0; i < 1024; i++) {
jjPARTICLE@ part = jjParticles[i];
if (part.type == PARTICLE::STRING) {
if (part.string.text == "1") {
part.xSpeed = 0;
part.ySpeed = -5;
part.string.text = "|+ HP";
}
if ((part.ySpeed = part.ySpeed * 16 / 17 + 0.125f) > 0) {
part.string.text = "";
}
}
}
}
if (client::isCoopOrSP() != client::startedAsCoopOrSP) {
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjPLAYER@ player = jjLocalPlayers[i];
for (int j = 1; j < 10; j++) {
player.ammo[j] = 0;
player.powerup[j] = false;
}
}
client::startedAsCoopOrSP = !client::startedAsCoopOrSP;
if (jjIsServer || jjGameConnection == GAME::LOCAL)
jjChat("/r");
}
}
void onObjectHit(jjOBJ@ obj, jjOBJ@ other, jjPLAYER@ player, int) {
if (obj is null)
return;
if (other !is null) {
if (obj.eventID == OBJECT::TNT)
collision::barrelExplode(obj, other);
return;
}
if (player !is null) {
switch (obj.eventID) {
case OBJECT::BOUNCERAMMO3:
collision::ammoPickup(player, obj, WEAPON::BOUNCER);
break;
case OBJECT::ICEAMMO3:
collision::ammoPickup(player, obj, WEAPON::ICE);
break;
case OBJECT::SEEKERAMMO3:
collision::ammoPickup(player, obj, WEAPON::SEEKER);
break;
case OBJECT::RFAMMO3:
collision::ammoPickup(player, obj, WEAPON::RF);
break;
case OBJECT::TOASTERAMMO3:
collision::ammoPickup(player, obj, WEAPON::TOASTER);
break;
case OBJECT::BLASTERBULLET:
case OBJECT::BOUNCERBULLET:
case OBJECT::ICEBULLET:
case OBJECT::SEEKERBULLET:
case OBJECT::RFBULLET:
case OBJECT::TOASTERBULLET:
collision::projectile(player, obj);
break;
}
}
}
void onPlayer(jjPLAYER@ player) {
sprite::clearQueues();
player.frozen = player.score = 0;
player.fastfire = weapon::fireInterval[player.currWeapon];
TlocalPlayer@ thisPlayer = client::localPlayer[player.localPlayerID];
if (--thisPlayer.dispersionPistolRegenerationTimer < 0) {
if (player.ammo[WEAPON::BLASTER] < jjWeapons[WEAPON::BLASTER].maximum) {
player.ammo[WEAPON::BLASTER] = player.ammo[WEAPON::BLASTER] + weapon::pickupMultiplier[WEAPON::BLASTER];
thisPlayer.dispersionPistolRegenerationTimer = weapon::dispersionPistolRegenerationTime;
} else {
thisPlayer.dispersionPistolRegenerationTimer = 0;
}
}
thisPlayer.weaponChangeTimer--;
if (player.currWeapon != thisPlayer.weaponPrevious) {
thisPlayer.weaponChangeTimer = weapon::displayTime;
thisPlayer.weaponPrevious = player.currWeapon;
}
thisPlayer.fireIntervalTimer++;
if (client::isCoopOrSP() && jjLocalPlayerCount == 1) {
if (jjMouseX >= 0 && jjMouseX < jjResolutionWidth && jjMouseY >= 0 && jjMouseY < jjResolutionHeight)
player.cameraFreeze(player.xPos + jjMouseX - jjSubscreenWidth, player.yPos + jjMouseY - jjSubscreenHeight, false, true);
else
player.cameraUnfreeze();
}
}
void onPlayerInput(jjPLAYER@ player) {
TlocalPlayer@ thisPlayer = client::localPlayer[player.localPlayerID];
if (!thisPlayer.keyFirePrevious && player.keyFire) {
if (thisPlayer.fireIntervalTimer < player.fastfire)
player.keyFire = false;
else
thisPlayer.fireIntervalTimer = 0;
}
thisPlayer.keyFirePrevious = player.keyFire;
}
namespace behavior {
void asmdBeam(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
obj.var[5] = jjGameTicks;
break;
case STATE::ACTION:
obj.state = STATE::EXPLODE;
break;
}
obj.behave(BEHAVIOR::BULLET, false);
if (obj.state != STATE::EXPLODE) {
obj.xPos = obj.xPos + obj.xSpeed / 2;
obj.yPos = obj.yPos + obj.ySpeed / 2;
if (obj.counter % 2 == 0) {
explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::AMMO, 71);
if (obj.counter % 10 == 0)
explosion::asmdRing(obj.xPos, obj.yPos, obj.xSpeed, obj.ySpeed, 30.f / obj.counter, 10.f / obj.counter);
}
} else if (obj.age++ == 0 && jjMaskedPixel(int(obj.xPos), int(obj.yPos))){
explosion::asmdRing(obj.xPos, obj.yPos, obj.xSpeed, obj.ySpeed, 6, 2);
explosion::harmfulExplosion(obj.xPos, obj.yPos, 32, 2, 50, obj.creatorType == CREATOR::PLAYER ? jjPlayers[obj.creatorID] : null);
}
}
void barrel(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
if (jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, -4, 2) != 3 ^^ client::isCoopOrSP()) {
obj.delete();
return;
}
obj.putOnGround();
obj.state = STATE::IDLE;
case STATE::IDLE:
sprite::add(obj.xPos, obj.yPos, obj.curFrame, 0, SPRITE::PALSHIFT, palshift::barrel);
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ bull = jjObjects[i];
if (bull.isActive
&& bull.playerHandling == HANDLING::SPECIAL
&& bull.animSpeed > 0
&& bull.state != STATE::START
&& bull.state != STATE::EXPLODE
&& bull.xPos > obj.xPos - 11
&& bull.xPos < obj.xPos + 15
&& bull.yPos > obj.yPos - 19
&& bull.yPos < obj.yPos + 15)
collision::barrel(obj, bull);
}
if (obj.energy < jjObjectPresets[obj.eventID].energy) {
string text = formatInt(obj.energy, "");
jjDrawString(obj.xPos - text::getSmallFontIntWidth(text) / 2, obj.yPos + 16, text, STRING::SMALL, STRING::PALSHIFT, palshift::barrelDurability);
}
break;
case STATE::EXTRA:
{
uint16 creatorID = obj.special >= 0 ? obj.special : 0;
CREATOR::Type creatorType = obj.special >= 0 ? CREATOR::PLAYER : CREATOR::OBJECT;
int ID = jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, creatorID, creatorType, behavior::delete);
if (ID != 0) {
jjOBJ@ bull = jjObjects[ID];
bull.curFrame = obj.curFrame;
bull.freeze = 1;
bull.playerHandling = HANDLING::PLAYERBULLET;
bull.state = STATE::IDLE;
}
}
break;
case STATE::ACTION:
if (obj.special >= 0 || client::isCoopOrSP() || uint(++obj.counter) > obj.counterEnd) {
explosion::barrelExplosion(obj.xPos, obj.yPos, obj.special >= 0 ? jjPlayers[obj.special] : null);
obj.delete();
}
break;
}
}
void bullet(jjOBJ@ obj) {
if (obj.state == STATE::ACTION)
obj.state = STATE::EXPLODE;
obj.behave(BEHAVIOR::BULLET, false);
sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed));
}
void delete(jjOBJ@ obj) {
if (++obj.age > 3)
obj.delete();
}
void destructScenery(jjOBJ@ obj) {
if (obj.special == 0) {
if (client::isCoopOrSP()) {
obj.behavior = BEHAVIOR::DESTRUCTSCENERY;
obj.behave();
if (obj.eventID == OBJECT::DESTRUCTSCENERYBOMB)
obj.delete();
return;
}
jjTileSet(4, uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, obj.eventID == OBJECT::DESTRUCTSCENERY ? tileset::wall : tileset::empty);
obj.delete();
}
}
void enemy(jjOBJ@ obj) {
if (jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 8, 1) == 0) {
obj.behavior = turret;
obj.doesHurt = 1;
obj.energy = 50;
obj.determineCurAnim(ANIM::SONCSHIP, 6);
} else {
obj.behavior = machine;
obj.doesHurt = 0;
obj.var[0] = obj.var[1] = 30;
obj.determineCurAnim(ANIM::SONCSHIP, 2);
}
obj.determineCurFrame();
obj.behave();
}
void explosion(jjOBJ@ obj) {
obj.behave(BEHAVIOR::EXPLOSION, false);
sprite::add(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::RESIZED, obj.age, 3);
}
void flak(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
obj.var[5] = 0;
obj.determineCurAnim(ANIM::PICKUPS, 44 + (jjRandom() & 3));
obj.determineCurFrame();
obj.state = STATE::DELAYEDSTART;
break;
case STATE::DELAYEDSTART:
if (obj.special > 0) {
if (obj.var[7] * obj.xSpeed > 0)
obj.xSpeed = obj.xSpeed + float(obj.var[7]) / 0x10000;
const float angle = atan2(obj.ySpeed, obj.xSpeed);
const float speed = sqrt(obj.xSpeed * obj.xSpeed + obj.ySpeed * obj.ySpeed);
for (int i = -obj.special; i <= obj.special; i++) {
int ID = jjAddObject(OBJECT::RFBULLET, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType);
if (ID != 0) {
float newAngle = angle + i * 0.05f;
float newSpeed = speed + (i * i & 18);
jjOBJ@ bull = jjObjects[ID];
bull.counterEnd = obj.counterEnd + (i * i & 5);
bull.direction = obj.direction;
bull.special = 0;
bull.xAcc = -obj.xAcc * cos(newAngle);
bull.xSpeed = newSpeed * cos(newAngle);
bull.yAcc = obj.yAcc;
bull.ySpeed = newSpeed * sin(newAngle);
}
}
obj.delete();
return;
}
obj.state = STATE::FLY;
break;
case STATE::ACTION:
obj.state = STATE::EXPLODE;
case STATE::EXPLODE:
explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::PICKUPS, 4);
obj.delete();
return;
}
uint8 damage = jjObjectPresets[obj.eventID].doesHurt * (obj.counterEnd - obj.counter) / (obj.counterEnd * (obj.var[9] + 1)) + 1;
if (damage > weapon::maxDamage)
damage = weapon::maxDamage;
obj.doesHurt = damage | obj.var[5];
if (uint(++obj.counter) > obj.counterEnd)
obj.state = STATE::EXPLODE;
obj.xSpeed = obj.xSpeed + obj.xAcc;
obj.ySpeed = obj.ySpeed + obj.yAcc;
float x = obj.xPos;
obj.xPos = obj.xPos + obj.xSpeed;
if (obj.counter > 5)
obj.var[5] = weapon::allowSD;
if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
if (jjRandom() & 3 == 0)
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_CUP);
obj.counter += 4;
obj.var[9] = obj.var[9] + 1;
obj.xPos = x;
obj.xSpeed = -obj.xSpeed;
obj.xAcc = -obj.xAcc;
}
float y = obj.yPos;
obj.yPos = obj.yPos + obj.ySpeed;
if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
obj.counter += 4;
obj.var[9] = obj.var[9] + 1;
obj.yPos = y;
obj.ySpeed = -obj.ySpeed;
}
if (jjGameTicks % 7 == 0) {
obj.frameID++;
obj.determineCurFrame();
}
sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed), SPRITE::PALSHIFT, palshift::flak);
}
void flame(jjOBJ@ obj) {
obj.xSpeed = obj.xSpeed + obj.xAcc;
obj.ySpeed = obj.ySpeed + obj.yAcc;
float xPrev = obj.xPos;
float yPrev = obj.yPos;
obj.xPos = obj.xPos + obj.xSpeed;
obj.yPos = obj.yPos + obj.ySpeed;
if (jjRandom() & 15 == 0) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::SMOKE);
if (part !is null) {
part.xPos = obj.xPos;
part.yPos = obj.yPos;
}
}
switch (obj.state) {
case STATE::START:
if (jjGameTicks & 6 == 0)
jjSample(obj.xPos, obj.yPos, SOUND::BILSBOSS_FIRE);
obj.xSpeed = obj.xSpeed * 4 + float(obj.var[7]) / 0x20000;
obj.ySpeed = obj.ySpeed * 4;
obj.age = abs(obj.xSpeed) > abs(obj.ySpeed) ? 1 : 0;
obj.state = STATE::FIRE;
case STATE::FIRE:
{
bool masked = jjMaskedPixel(int(obj.xPos), int(obj.yPos));
if (masked || (obj.age == 1 ? abs(obj.xSpeed) < 1 : abs(obj.ySpeed) < 1)) {
obj.xAcc = obj.yAcc = 0;
obj.doesHurt = (obj.doesHurt & weapon::maxDamage) / 2 | weapon::allowSD;
if (masked) {
obj.xPos = xPrev;
obj.yPos = yPrev;
obj.xSpeed = obj.ySpeed = 0;
}
obj.state = STATE::FALL;
}
}
break;
case STATE::FALL:
if (obj.yAcc < 0.125f)
obj.yAcc = obj.yAcc + 0.005f;
if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
obj.xAcc = obj.xSpeed = obj.yAcc = obj.ySpeed = 0;
if (uint(++obj.counter) > obj.counterEnd)
obj.state = STATE::EXPLODE;
}
break;
case STATE::ACTION:
obj.state = STATE::EXPLODE;
case STATE::EXPLODE:
explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::AMMO, 55);
obj.delete();
return;
}
if (jjGameTicks % 7 == 0) {
obj.frameID++;
obj.determineCurFrame();
}
sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed));
}
void machine(jjOBJ@ obj) {
const jjPLAYER@ nearestPlayer;
float shortestDistanceSqr = 640 * 640;
for (int i = 0; i < 32; i++) {
const jjPLAYER@ player = jjPlayers[i];
if (!player.isActive || player.health <= 0)
continue;
float dx = player.xPos - obj.xPos;
float dy = player.yPos - obj.yPos;
float distanceSqr = dx * dx + 4 * dy * dy;
if (distanceSqr < shortestDistanceSqr && level::isLineMaskFree(int(obj.xPos), int(obj.yPos), int(player.xPos), int(player.yPos))) {
@nearestPlayer = player;
shortestDistanceSqr = distanceSqr;
}
}
int8 springFrame = 0;
int yMod = 0;
switch (obj.state) {
case STATE::START:
obj.age = obj.var[0];
obj.counterEnd = 50 - jjDifficulty * 15;
obj.counter = obj.counterEnd / 2;
obj.direction = 1;
obj.special = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 8) % 10;
obj.var[4] = weapon::fireInterval[obj.special] * (4 - jjDifficulty);
obj.yAcc = 0.125f;
obj.yPos = obj.yPos - 25;
obj.state = STATE::IDLE;
case STATE::IDLE:
if ((yMod = ((jjGameTicks >> 3) + obj.objectID) & 3) == 3)
yMod = 1;
if (obj.var[3] == 0 && nearestPlayer !is null) {
if (--obj.counter < 4)
springFrame = 1;
if (obj.counter < 0) {
obj.counter = 0;
float xDistance = nearestPlayer.xPos - obj.xPos;
if (xDistance * obj.direction >= 0) {
obj.doesHurt = 0;
obj.xSpeed = xDistance / 64;
if (obj.xSpeed > 3)
obj.xSpeed = 3;
else if (obj.xSpeed < -3)
obj.xSpeed = -3;
obj.ySpeed = -5;
jjSample(obj.xPos, obj.yPos + 40, SOUND::SPRING_SPRING1);
} else {
obj.doesHurt = 1;
obj.xSpeed = 0;
obj.ySpeed = -3;
jjSample(obj.xPos, obj.yPos + 40, SOUND::SPRING_BOING_DOWN);
}
obj.state = STATE::JUMP;
}
}
break;
case STATE::JUMP:
obj.xPos = obj.xPos + obj.xSpeed;
obj.yPos = obj.yPos + obj.ySpeed;
obj.ySpeed = obj.ySpeed + obj.yAcc;
if (obj.doesHurt > 0 && obj.ySpeed > 0 && nearestPlayer !is null && (nearestPlayer.xPos - obj.xPos) * obj.direction < 0) {
obj.direction = -obj.direction;
obj.doesHurt--;
}
if (++obj.counter < 12)
springFrame = (obj.counter >> 2) + 2;
if (jjMaskedVLine(int(obj.xPos) + obj.direction * 20, int(obj.yPos) - 12, 48)) {
obj.xSpeed = -obj.xSpeed;
obj.doesHurt++;
}
if (obj.ySpeed < 0 && jjMaskedHLine(int(obj.xPos) - 16, 32, int(obj.yPos) - 12))
obj.ySpeed = -obj.ySpeed / 2;
if (jjMaskedHLine(int(obj.xPos) - 16, 32, int(obj.yPos) + 42)) {
while (jjMaskedHLine(int(obj.xPos) - 16, 32, int(obj.yPos) + 41) && obj.yPos > 0) {
obj.yPos = obj.yPos - 1;
}
explosion::machineStomp(obj.xPos, obj.yPos + 42);
obj.counter = obj.counterEnd;
obj.state = STATE::IDLE;
}
break;
case STATE::EXPLODE:
for (int i = 0; i < 3; i++) {
if (obj.var[2] == 0)
jjAddParticlePixelExplosion(obj.xPos - obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 1);
if (obj.var[3] == 0)
jjAddParticlePixelExplosion(obj.xPos + obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 1);
}
explosion::machineExplosion(obj.xPos, obj.yPos);
obj.delete();
return;
}
if (obj.var[2] == 0
&& nearestPlayer !is null
&& (nearestPlayer.xPos - obj.xPos) * obj.direction >= 0
&& abs(nearestPlayer.yPos - obj.yPos) < 128
&& jjGameTicks % obj.var[4] == 0) {
int ID = jjAddObject(obj.special, obj.xPos + obj.direction * 35, obj.yPos + 13, obj.objectID);
if (obj.special > 3 && ID != 0) {
jjOBJ@ bull = jjObjects[ID];
bull.xPos = bull.xOrg;
bull.yPos = bull.yOrg;
bull.xSpeed = bull.xSpeed * obj.direction;
bull.xAcc = bull.xAcc * obj.direction;
bull.direction = obj.direction;
}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ bull = jjObjects[i];
if (bull.isActive
&& bull.playerHandling == HANDLING::SPECIAL
&& bull.animSpeed > 0
&& bull.state != STATE::START
&& bull.state != STATE::EXPLODE
&& bull.xPos > obj.xPos - 30
&& bull.xPos < obj.xPos + 30
&& bull.yPos > obj.yPos - 30
&& bull.yPos < obj.yPos + 30) {
float dx = bull.xPos - obj.xPos;
float dy = bull.yPos - obj.yPos;
if (dx * dx + dy * dy < 30 * 30)
collision::machine(obj, bull);
}
}
obj.determineCurAnim(ANIM::SPRING, 4);
obj.frameID = springFrame;
sprite::add(obj.xPos, obj.yPos + 39, obj.determineCurFrame(false), 0, SPRITE::PALSHIFT, palshift::machineSpring[obj.special]);
obj.determineCurAnim(ANIM::LIZARD, 2);
obj.frameID = jjGameTicks >> 3 & 3;
if (obj.var[2] == 0) {
sprite::add(obj.xPos - obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction);
if (obj.var[0] < obj.age) {
string text = formatInt(obj.var[0], "");
jjDrawString(obj.xPos - obj.direction * 20 - text::getSmallFontIntWidth(text) / 2, obj.yPos, text, STRING::SMALL, STRING::PALSHIFT, palshift::enemyHealth);
}
} else if (obj.var[2] == 1) {
jjAddParticlePixelExplosion(obj.xPos - obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 0);
obj.var[2] = 2;
}
obj.frameID = obj.frameID + 2 & 3;
if (obj.var[3] == 0) {
sprite::add(obj.xPos + obj.direction * 9, obj.yPos + yMod - 9, obj.determineCurFrame(false), obj.direction);
if (obj.var[1] < obj.age) {
string text = formatInt(obj.var[1], "");
jjDrawString(obj.xPos + obj.direction * 20 - text::getSmallFontIntWidth(text) / 2, obj.yPos, text, STRING::SMALL, STRING::PALSHIFT, palshift::enemyHealth);
}
} else if (obj.var[3] == 1) {
jjAddParticlePixelExplosion(obj.xPos + obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 0);
obj.var[3] = 2;
}
sprite::add(obj.xPos, obj.yPos + yMod, obj.curFrame, obj.direction);
obj.determineCurAnim(ANIM::AMMO, 8);
obj.frameID = 4;
sprite::add(obj.xPos - obj.direction * 9, obj.yPos + yMod + 11, obj.determineCurFrame(false), 0, SPRITE::PALSHIFT, palshift::machineBadge[obj.special]);
}
void pickup(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
if (jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, -4, 2) != 3 ^^ client::isCoopOrSP()) {
obj.delete();
return;
}
break;
case STATE::ACTION:
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUPW1);
explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::PICKUPS, 86);
obj.delete();
return;
case STATE::FLOATFALL:
obj.state = STATE::FLOAT;
break;
}
obj.behave(BEHAVIOR::PICKUP, false);
sprite::add(obj.xPos, obj.yPos + 4 * jjSin(((obj.objectID << 3) + jjGameTicks) << 4), obj.curFrame);
}
void rocket(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
obj.state = STATE::ROCKETFLY;
break;
case STATE::ACTION:
obj.state = STATE::EXPLODE;
case STATE::EXPLODE:
explosion::rocketExplosion(obj.xPos, obj.yPos, obj.creatorType == CREATOR::PLAYER ? jjPlayers[obj.creatorID] : null);
obj.delete();
return;
}
obj.xSpeed = obj.xSpeed + obj.xAcc;
obj.ySpeed = obj.ySpeed + obj.yAcc;
obj.xPos = obj.xPos + obj.xSpeed;
obj.yPos = obj.yPos + obj.ySpeed;
if (jjMaskedPixel(int(obj.xPos), int(obj.yPos)))
obj.state = STATE::EXPLODE;
if (jjGameTicks % 7 == 0) {
obj.frameID++;
obj.determineCurFrame();
}
sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed));
}
void savePoint(jjOBJ@ obj) {
if (!client::isCoopOrSP()) {
obj.delete();
return;
}
obj.behave(BEHAVIOR::CHECKPOINT, false);
sprite::add(obj.xPos, obj.yPos, obj.curFrame);
}
void shard(jjOBJ@ obj) {
if (obj.age == 0)
obj.age = (4 << (jjRandom() & 3)) - 1;
obj.behave(BEHAVIOR::SHARD, false);
obj.determineCurFrame();
sprite::add(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, obj.special);
uint random = jjRandom();
if (random & obj.age == 0) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::FIRE);
if (part !is null) {
part.xPos = obj.xPos;
part.yPos = obj.yPos;
}
}
}
void shortLivedParticle(jjOBJ@ obj) {
if (--obj.counter < 0) {
obj.delete();
return;
}
obj.xSpeed = obj.xSpeed + obj.xAcc;
obj.ySpeed = obj.ySpeed + obj.yAcc;
obj.xPos = obj.xPos + obj.xSpeed;
obj.yPos = obj.yPos + obj.ySpeed;
if (jjGameTicks % 7 == 0 || obj.state == STATE::START) {
obj.frameID++;
obj.determineCurFrame();
}
sprite::add(obj.xPos, obj.yPos, obj.curFrame, 0, SPRITE::Mode(obj.special), obj.var[0]);
}
void spring(jjOBJ@ obj) {
if (obj.state == STATE::START && jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, -4, 2) == 3 && client::isCoopOrSP()) {
obj.delete();
return;
}
obj.behave(BEHAVIOR::SPRING, false);
sprite::add(obj.xPos, obj.yPos, obj.curFrame);
}
void turret(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
obj.age = obj.energy;
obj.direction = 64;
obj.special = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 8) % 10;
obj.yPos = obj.yPos - 8;
obj.state = STATE::DELAYEDSTART;
break;
case STATE::EXPLODE:
obj.counter = 35;
obj.state = STATE::EXTRA;
case STATE::EXTRA:
if (--obj.counter & 15 == 0)
explosion::turretExplosion(obj.xPos, obj.yPos);
if (obj.counter < 0)
obj.delete();
return;
}
obj.counter--;
const jjPLAYER@ nearestPlayer;
float xDistance = 0;
float yDistance = 0;
for (int i = 0; i < 32; i++) {
const jjPLAYER@ player = jjPlayers[i];
if (!player.isActive || player.health <= 0 || player.yPos <= obj.yPos)
continue;
float dx = player.xPos - obj.xPos;
float dy = player.yPos - obj.yPos;
if ((nearestPlayer is null || dx * dx + dy * dy < xDistance * xDistance + yDistance * yDistance)
&& level::isLineMaskFree(int(obj.xPos), int(obj.yPos), int(player.xPos), int(player.yPos))) {
@nearestPlayer = player;
xDistance = dx;
yDistance = dy;
}
}
if (nearestPlayer !is null) {
float angle = atan2(yDistance, xDistance);
int convertedAngle = int(angle * 125 / 3.1415927f);
if (obj.direction != convertedAngle) {
if (obj.state == STATE::DELAYEDSTART) {
obj.direction = convertedAngle;
} else {
if (obj.direction < convertedAngle)
obj.direction++;
else
obj.direction--;
}
if (obj.direction < 8)
obj.direction = 8;
else if (obj.direction >= 120)
obj.direction = 120;
obj.frameID = (125 - obj.direction) / 14 - 1;
if (obj.frameID < 0)
obj.frameID = 0;
else if (obj.frameID > 6)
obj.frameID = 6;
obj.determineCurFrame();
}
if (obj.counter <= 0) {
int convertedDirection = obj.direction * 512 / 125;
int8 direction = obj.direction;
obj.direction = 1;
int ID = jjAddObject(obj.special, obj.xPos + 20 * jjCos(convertedDirection), obj.yPos + 20 * jjSin(convertedDirection), obj.objectID);
obj.direction = direction;
if (ID != 0) {
jjOBJ@ bull = jjObjects[ID];
float speed = bull.xSpeed;
float acc = bull.xAcc;
bull.xPos = bull.xOrg;
bull.yPos = bull.yOrg;
bull.xSpeed = speed * jjCos(convertedDirection);
bull.ySpeed = speed * jjSin(convertedDirection);
bull.xAcc = acc * jjCos(convertedDirection);
bull.yAcc = acc * jjSin(convertedDirection);
bull.direction = bull.xSpeed >= 0 ? 1 : -1;
}
obj.counter = weapon::fireInterval[obj.special] << 3 >> jjDifficulty;
}
}
if (obj.state == STATE::DELAYEDSTART)
obj.state = STATE::ROTATE;
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ bull = jjObjects[i];
if (bull.isActive
&& bull.playerHandling == HANDLING::SPECIAL
&& bull.animSpeed > 0
&& bull.state != STATE::START
&& bull.state != STATE::EXPLODE
&& bull.xPos > obj.xPos - 10
&& bull.xPos < obj.xPos + 10
&& bull.yPos > obj.yPos - 10
&& bull.yPos < obj.yPos + 10)
collision::turret(obj, bull);
}
sprite::add(obj.xPos, obj.yPos, obj.curFrame, 0, SPRITE::PALSHIFT, palshift::turret[obj.special]);
if (obj.energy < obj.age) {
string text = formatInt(obj.energy, "");
jjDrawString(obj.xPos - text::getSmallFontIntWidth(text) / 2, obj.yPos + 32, text, STRING::SMALL, STRING::PALSHIFT, palshift::turretDurability);
}
}
}
namespace client {
bool admin = false;
int lastIdleServer = 0;
array<TlocalPlayer> localPlayer(jjLocalPlayerCount);
bool startedAsCoopOrSP = isCoopOrSP();
bool isCoopOrSP() {
return jjGameMode == GAME::SP || jjGameMode == GAME::COOP;
}
bool isIdleServer() {
return lastIdleServer == jjGameTicks || (jjIsServer && jjLocalPlayers[0].xPos == 0 && jjLocalPlayers[0].yPos == 0 && (lastIdleServer = jjGameTicks) != 0);
}
}
namespace collision {
void ammoPickup(jjPLAYER@ player, jjOBJ@ obj, WEAPON::Weapon type) {
if (player.ammo[type] >= jjWeapons[type].maximum)
return;
if (player.ammo[type] == 0 && !player.keyFire && (uint8(type) > player.currWeapon || type == WEAPON::SEEKER))
player.currWeapon = type;
player.ammo[type] = player.ammo[type] + weapon::pickupMultiplier[type];
if (player.ammo[type] > jjWeapons[type].maximum)
player.ammo[type] = jjWeapons[type].maximum;
if (client::isCoopOrSP()) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::STRING);
if (part !is null) {
part.xPos = obj.xPos;
part.yPos = obj.yPos;
part.xSpeed = 0;
part.ySpeed = -5;
part.string.text = "||+ AMMO";
}
}
obj.state = STATE::ACTION;
}
void barrel(jjOBJ@ obj, jjOBJ@ bull) {
if (bull.creatorType == CREATOR::PLAYER)
obj.special = bull.creatorID;
if (obj.state == STATE::ACTION || obj.state == STATE::EXTRA)
return;
switch (bull.eventID) {
case OBJECT::BLASTERBULLET:
jjSample(obj.xPos, obj.yPos, SOUND::AMMO_GUNJAZZ);
bull.state = STATE::EXPLODE;
break;
case OBJECT::BOUNCERBULLET:
bull.direction = bull.xSpeed > 0 ? -1 : 1;
bull.ricochet();
bull.state = STATE::EXPLODE;
break;
case OBJECT::ICEBULLET:
if (obj.var[5] == bull.var[5])
return;
obj.var[5] = bull.var[5];
break;
case OBJECT::RFBULLET:
if (jjRandom() & 2 == 0)
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_CUP);
bull.counter += 8;
bull.var[9] = bull.var[9] + 1;
if (!jjMaskedPixel(int(bull.xPos - bull.xSpeed), int(bull.yPos))) {
bull.xSpeed = -bull.xSpeed;
} else {
if (jjMaskedPixel(int(bull.xPos), int(bull.yPos - bull.ySpeed)))
bull.xSpeed = -bull.xSpeed;
bull.ySpeed = -bull.ySpeed;
}
break;
default:
bull.state = STATE::EXPLODE;
}
if (obj.energy > bull.animSpeed)
obj.energy -= bull.animSpeed;
else
obj.state = STATE::EXTRA;
}
void barrelExplode(jjOBJ@ obj, jjOBJ@ bull) {
obj.state = STATE::ACTION;
bull.delete();
}
bool hurtPlayer(jjPLAYER@ player, jjPLAYER@ attacker, uint8 damage) {
if (player.blink != 0 || player.health <= 0)
return false;
if (attacker !is null) {
if (attacker.blink != 0)
return false;
if (player is attacker) {
if (damage & weapon::allowSD == 0 || jjTriggers[trigger::disableSD])
return false;
} else if (jjGameMode == GAME::CTF && player.teamRed == attacker.teamRed && !jjTriggers[trigger::friendlyFire]) {
return false;
}
}
if (jjTriggers[trigger::damageAmplifier] && damage & weapon::maxDamage < weapon::maxDamage)
damage++;
if (player.hurt(damage & weapon::maxDamage, true, attacker)) {
player.blink = 60;
return true;
}
return false;
}
void machine(jjOBJ@ obj, jjOBJ@ bull) {
if (bull.yPos > obj.yPos - 12) {
if (bull.eventID == OBJECT::BOUNCERBULLET) {
bull.direction = bull.xSpeed > 0 ? -1 : 1;
bull.ricochet();
}
} else {
int index = (bull.xPos - obj.xPos) * obj.direction >= 0 ? 1 : 0;
if (obj.var[index + 2] != 0)
return;
if ((obj.var[index] = obj.var[index] - bull.animSpeed) <= 0)
obj.var[index + 2] = 1;
}
bull.state = STATE::EXPLODE;
}
void projectile(jjPLAYER@ player, jjOBJ@ bull) {
jjPLAYER@ creator;
if (bull.creatorType == CREATOR::PLAYER)
@creator = jjPlayers[bull.creatorID];
if (hurtPlayer(player, creator, bull.doesHurt))
bull.state = STATE::ACTION;
}
void turret(jjOBJ@ obj, jjOBJ@ bull) {
bull.state = STATE::EXPLODE;
if (obj.energy > bull.animSpeed)
obj.energy -= bull.animSpeed;
else
obj.state = STATE::EXPLODE;
}
}
namespace draw {
void ammoCounter(jjCANVAS@ canvas, int x, int y, int value, int max, bool active) {
int color = 0;
if (active) {
if (2 * value <= max) {
if (4 * value <= max) {
if (value <= 0)
color = 3;
else
color = 2;
} else {
color = 1;
}
}
}
STRING::Mode mode = active ? STRING::PALSHIFT : STRING::DARK;
string text = formatInt(value, "") + "/" + formatInt(max, "");
canvas.drawString(x, y, text, STRING::SMALL, mode, palshift::ammoCount[color]);
}
void healthBar(jjCANVAS@ canvas, int x, int y, int value, int max, bool red) {
const uint backgroundTile = tileset::healthBar + 12;
const int backgroundX = x + 32;
const uint insideTile = tileset::healthBar + 5;
const int insideX = x + 46;
const int insideY = y + 8;
const int length = 105 * value / max;
const bool low = value <= max / 2;
const TILE::Quadrant quadrantLeft = low ? TILE::BOTTOMLEFT : TILE::TOPLEFT;
const TILE::Quadrant quadrantRight = low ? TILE::BOTTOMRIGHT : TILE::TOPRIGHT;
if (value < max) {
for (int i = 0; i < 4; i++) {
canvas.drawTile(backgroundX + i * 32, y, backgroundTile + i);
}
}
for (int i = 0; i < length; i++) {
uint random = jjRandom();
canvas.drawTile(insideX + i, insideY, insideTile + (random & 1), random & 2 != 0 ? quadrantLeft : quadrantRight);
}
if (value < max)
canvas.drawTile(insideX + length, insideY, insideTile + 11, jjRandom() & 1 != 0 ? quadrantLeft : quadrantRight);
if (length >= 9) {
canvas.drawTile(x + 48, y, insideTile + 4, quadrantLeft);
if (length >= 50) {
canvas.drawTile(x + 80, y, insideTile + 4, quadrantRight);
if (length >= 82)
canvas.drawTile(x + 112, y, insideTile + 4, quadrantRight);
}
}
for (int i = 0; i < 5; i++) {
canvas.drawTile(x + i * 32, y, tileset::healthBar + i);
}
for (int i = 0; i < 2; i++) {
canvas.drawTile(x + i * 32, y + 32, tileset::healthBar + 10 + i);
}
if (!red) {
const uint heartTile = tileset::healthBar + (low ? 17 : 7);
for (int i = 0; i < 2; i++) {
canvas.drawTile(x + i * 32, y + 16, heartTile + i);
}
}
}
void largeWeaponIcon(jjCANVAS@ canvas, int x, int y, uint8 type) {
uint modifier = tileset::weaponLarge + (type + (type & ~1)) * 5;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++) {
canvas.drawTile(x + j * 32, y + i * 32, modifier + i * 10 + j);
}
}
}
void smallWeaponIcon(jjCANVAS@ canvas, int x, int y, uint8 type, bool active) {
uint modifier = (active ? tileset::weaponSmall : tileset::weaponSmallInactive) + type * 5;
if (type & 1 == 0) {
canvas.drawTile(x, y, modifier);
canvas.drawTile(x + 32, y, modifier + 1);
canvas.drawTile(x + 64, y, modifier + 2, TILE::TOPLEFT);
canvas.drawTile(x + 64, y + 16, modifier + 2, TILE::BOTTOMLEFT);
} else {
canvas.drawTile(x, y, modifier - 3, TILE::TOPRIGHT);
canvas.drawTile(x, y + 16, modifier - 3, TILE::BOTTOMRIGHT);
canvas.drawTile(x + 16, y, modifier - 2);
canvas.drawTile(x + 48, y, modifier - 1);
}
}
void weaponIconBarHorizontal(jjCANVAS@ canvas, int x, int y, const jjPLAYER@ player) {
const bool largeDisplay = client::localPlayer[player.localPlayerID].weaponChangeTimer > 0;
x -= weapon::count * 40 + (largeDisplay ? 40 : 0);
int x2 = x + (largeDisplay ? 80 : 0);
const uint8 currentWeaponID = player.currWeapon - weapon::first;
for (uint i = 0; i < weapon::count; i++) {
uint8 weapon = i + 1;
bool hasAmmoOrIsCurrent = player.ammo[weapon] > 0 || i == currentWeaponID;
if (i == currentWeaponID && largeDisplay) {
largeWeaponIcon(canvas, x + i * 80, y - 32, i);
ammoCounter(canvas, x + i * 80, y + 24, player.ammo[weapon], jjWeapons[weapon].maximum, true);
weaponName(canvas, x + i * 80 + 160, y - 24, weapon);
} else {
int xUsed = i < currentWeaponID ? x : x2;
smallWeaponIcon(canvas, xUsed + i * 80, y - 16, i, hasAmmoOrIsCurrent);
if (hasAmmoOrIsCurrent)
ammoCounter(canvas, xUsed + i * 80, y + 16, player.ammo[weapon], jjWeapons[weapon].maximum, i == currentWeaponID);
}
}
}
void weaponIconBarVertical(jjCANVAS@ canvas, int x, int y, const jjPLAYER@ player) {
const bool largeDisplay = client::localPlayer[player.localPlayerID].weaponChangeTimer > 0;
y -= weapon::count * 24 + (largeDisplay ? 16 : 0);
const int x2 = x - 32;
const int y2 = y + (largeDisplay ? 32 : 0);
const uint8 currentWeaponID = player.currWeapon - weapon::first;
for (uint i = 0; i < weapon::count; i++) {
uint8 weapon = i + 1;
bool hasAmmoOrIsCurrent = player.ammo[weapon] > 0 || i == currentWeaponID;
if (i == currentWeaponID && largeDisplay) {
largeWeaponIcon(canvas, x - 80, y + i * 48 + 8, i);
ammoCounter(canvas, x - 80, y + i * 48 + 72, player.ammo[weapon], jjWeapons[weapon].maximum, true);
weaponName(canvas, x + 80, y + i * 48 + 8, weapon);
} else {
int yUsed = i < currentWeaponID ? y : y2;
int xUsed = i != currentWeaponID ? x : x2;
smallWeaponIcon(canvas, xUsed, yUsed + i * 48, i, hasAmmoOrIsCurrent);
if (hasAmmoOrIsCurrent)
ammoCounter(canvas, xUsed, yUsed + i * 48 + 32, player.ammo[weapon], jjWeapons[weapon].maximum, i == currentWeaponID);
}
}
}
void weaponName(jjCANVAS@ canvas, int x, int y, uint8 type) {
canvas.drawString(x - text::getSmallFontIntWidth(weapon::name[type]), y, weapon::name[type]);
}
}
namespace explosion {
void asmdRing(float x, float y, float xSpeed, float ySpeed, float semiMajor, float semiMinor) {
if (client::isIdleServer())
return;
const int shift = semiMajor > 2 ? 5 : 6;
const int count = 1 << (10 - shift);
const float multiplier = 6.2831853 / count;
const float hypot = sqrt(xSpeed * xSpeed + ySpeed * ySpeed);
const float axisSin = ySpeed / hypot;
const float axisCos = xSpeed / hypot;
const float majorSin = semiMajor * axisSin;
const float minorSin = semiMinor * axisSin;
const float majorCos = semiMajor * axisCos;
const float minorCos = semiMinor * axisCos;
for (int i = 0; i < count; i++) {
const int angle = i << shift;
const float angleSin = jjSin(angle);
const float angleCos = jjCos(angle);
const float xSpeedUlt = minorCos * angleCos - majorSin * angleSin;
const float ySpeedUlt = minorSin * angleCos + majorCos * angleSin;
particle(x, y, xSpeedUlt, ySpeedUlt, 0, 0, 35, ANIM::AMMO, 9, SPRITE::PALSHIFT, palshift::asmdParticle);
}
}
void barrelExplosion(float x, float y, jjPLAYER@ creator) {
harmfulExplosion(x, y, 128, 4, 80, creator);
if (client::isIdleServer())
return;
jjSample(x, y, SOUND::COMMON_GLASS2);
for (int i = 0; i < 20; i++) {
int ID = jjAddObject(OBJECT::SHARD, x, y);
if (ID != 0) {
jjOBJ@ obj = jjObjects[ID];
obj.behavior = behavior::shard;
obj.special = palshift::barrel;
uint random = jjRandom();
int speed = 8 + (random >> 2 & 7);
uint angle = random >> 5;
obj.xSpeed = jjSin(angle) * speed;
obj.ySpeed = jjCos(angle) * speed;
obj.determineCurAnim(ANIM::PICKUPS, 6 + (random & 3));
}
}
simpleExplosion(x, y, ANIM::AMMO, 5, 128);
for (int i = 0; i < 3; i++) {
uint angle = jjRandom();
simpleExplosion(x + jjSin(angle) * 64, y + jjCos(angle) * 64, ANIM::AMMO, 3, 64);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 3, 48);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 3, 32);
}
uint16 creatorID = creator !is null ? creator.playerID : 0;
CREATOR::Type creatorType = creator !is null ? CREATOR::PLAYER : CREATOR::OBJECT;
for (int i = 0; i < 5; i++) {
int ID = jjAddObject(OBJECT::TOASTERBULLET, x, y, creatorID, creatorType);
if (ID != 0) {
uint angle = (i - 2) << 6;
jjOBJ@ obj = jjObjects[ID];
obj.doesHurt = (obj.doesHurt & weapon::maxDamage) / 2 | weapon::allowSD;
obj.state = STATE::FALL;
obj.xAcc = obj.yAcc = 0;
obj.xSpeed = jjSin(angle) * 2;
obj.ySpeed = -jjCos(angle) * 2;
}
}
}
void harmfulExplosion(float x, float y, float radius, uint damage, int objectDamage, jjPLAYER@ creator = null) {
damage &= weapon::maxDamage;
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjPLAYER@ player = jjLocalPlayers[i];
if (player.xPos < x - radius || player.xPos > x + radius || player.yPos < y - radius || player.yPos > y + radius)
continue;
float dx = player.xPos - x;
float dy = player.yPos - y;
float distance = sqrt(dx * dx + dy * dy);
if (distance > radius)
continue;
uint value = uint(damage * (radius - distance) / radius) + 1;
if (value > damage)
value = damage;
collision::hurtPlayer(player, creator, value | weapon::allowSD);
}
for (int i = 0; i < jjObjectCount; i++) {
jjOBJ@ obj = jjObjects[i];
if (!obj.isActive || obj.xPos < x - radius || obj.xPos > x + radius || obj.yPos < y - radius || obj.yPos > y + radius)
continue;
float dx = obj.xPos - x;
float dy = obj.yPos - y;
float distance = sqrt(dx * dx + dy * dy);
if (distance > radius)
continue;
int value = int(objectDamage * (radius - distance) / radius) + 1;
switch (obj.eventID) {
case OBJECT::TNT:
if (value > objectDamage)
value = objectDamage;
if (obj.energy > value)
obj.energy -= value;
else
obj.state = STATE::EXTRA;
if (creator !is null)
obj.special = creator.playerID;
break;
case OBJECT::DESTRUCTSCENERY:
if (obj.state != STATE::DONE && value > 50)
obj.state = STATE::KILL;
break;
case OBJECT::FLOATLIZARD:
if (obj.doesHurt == 1) {
if (obj.energy > value)
obj.energy -= value;
else
obj.state = STATE::EXPLODE;
} else if (value > 50) {
obj.state = STATE::EXPLODE;
}
break;
}
}
}
void machineExplosion(float x, float y) {
harmfulExplosion(x, y, 160, 7, 200);
if (client::isIdleServer())
return;
jjSample(x, y, SOUND::COMMON_DAMPED1);
for (int i = 0; i < 40; i++) {
int ID = jjAddObject(OBJECT::SHARD, x, y);
if (ID != 0) {
jjOBJ@ obj = jjObjects[ID];
obj.behavior = behavior::shard;
uint random = jjRandom();
obj.special = palshift::machineShard;
int speed = 7 + (random >> 2 & 7);
uint angle = random >> 5;
obj.xSpeed = jjSin(angle) * speed;
obj.ySpeed = jjCos(angle) * speed;
obj.determineCurAnim(ANIM::PICKUPS, 6 + (random & 3));
}
}
simpleExplosion(x, y, ANIM::AMMO, 5, 160);
for (int i = 0; i < 2; i++) {
uint angle = jjRandom();
simpleExplosion(x + jjSin(angle) * 64, y + jjCos(angle) * 64, ANIM::AMMO, 5, 96);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 5, 96);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 128, y + jjCos(angle) * 128, ANIM::AMMO, 5, 96);
}
}
void machineStomp(float x, float y) {
harmfulExplosion(x, y, 32, 3, 100);
if (client::isIdleServer())
return;
jjSample(x, y, SOUND::COMMON_METALHIT);
uint random = jjRandom();
for (int i = 0; i < 3; i++) {
simpleExplosion(x + (i - 1) * 16, y + (random & 7), ANIM::AMMO, 72, 48);
random >>= 3;
}
}
void particle(float x, float y, float xSpeed, float ySpeed, float xAcc, float yAcc, int counter, ANIM::Set setID, uint8 animation, SPRITE::Mode mode = SPRITE::NORMAL, uint8 param = 0) {
if (client::isIdleServer())
return;
int ID = jjAddObject(OBJECT::EXPLOSION, x, y);
if (ID != 0) {
jjOBJ@ obj = jjObjects[ID];
obj.behavior = behavior::shortLivedParticle;
obj.xSpeed = xSpeed;
obj.ySpeed = ySpeed;
obj.xAcc = xAcc;
obj.yAcc = yAcc;
obj.counter = counter;
obj.determineCurAnim(setID, animation);
obj.special = mode;
obj.var[0] = param;
}
}
void rocketExplosion(float x, float y, jjPLAYER@ creator) {
harmfulExplosion(x, y, 160, 5, 120, creator);
if (client::isIdleServer())
return;
jjSample(x, y, SOUND::COMMON_DAMPED1);
for (int i = 0; i < 20; i++) {
int ID = jjAddObject(OBJECT::SHARD, x, y);
if (ID != 0) {
jjOBJ@ obj = jjObjects[ID];
obj.behavior = behavior::shard;
uint random = jjRandom();
obj.special = palshift::rocketShard[random >> 2 & 1];
int speed = 7 + (random >> 3 & 3);
uint angle = random >> 5;
obj.xSpeed = jjSin(angle) * speed;
obj.ySpeed = jjCos(angle) * speed;
obj.determineCurAnim(ANIM::PICKUPS, 6 + (random & 3));
}
}
simpleExplosion(x, y, ANIM::AMMO, 5, 160);
for (int i = 0; i < 2; i++) {
uint angle = jjRandom();
simpleExplosion(x + jjSin(angle) * 64, y + jjCos(angle) * 64, ANIM::AMMO, 5, 96);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 5, 64);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 128, y + jjCos(angle) * 128, ANIM::AMMO, 5, 48);
}
}
void simpleExplosion(float x, float y, ANIM::Set setID, uint8 animation, uint8 scale = 32) {
if (client::isIdleServer())
return;
int ID = jjAddObject(OBJECT::EXPLOSION, x, y);
if (ID != 0) {
jjOBJ@ obj = jjObjects[ID];
obj.determineCurAnim(setID, animation);
obj.age = scale;
}
}
void turretExplosion(float x, float y) {
if (client::isIdleServer())
return;
jjSample(x, y, SOUND::COMMON_GLASS2);
simpleExplosion(x, y, ANIM::AMMO, 5, 64);
for (int i = 0; i < 3; i++) {
uint angle = jjRandom();
simpleExplosion(x + jjSin(angle) * 32, y + jjCos(angle) * 32, ANIM::AMMO, 3);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 48, y + jjCos(angle) * 48, ANIM::AMMO, 3);
angle >>= 10;
simpleExplosion(x + jjSin(angle) * 48, y + jjCos(angle) * 48, ANIM::AMMO, 3);
}
}
}
namespace initialize {
void objectPresets() {
jjOBJ@ preset;
@preset = jjObjectPresets[OBJECT::BLASTERBULLET];
preset.animSpeed = 10;
preset.behavior = behavior::bullet;
preset.bulletHandling = HANDLING::IGNOREBULLET;
preset.counterEnd = 50;
preset.doesHurt = 2;
preset.freeze = 0;
preset.isFreezable = false;
preset.killAnim = preset.determineCurAnim(ANIM::AMMO, 82, false);
preset.lightType = LIGHT::POINT2;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.special = preset.determineCurAnim(ANIM::AMMO, 32, false);
preset.xAcc = preset.yAcc = preset.ySpeed = 0;
preset.xSpeed = 7;
preset.determineCurAnim(ANIM::AMMO, 30);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::BOUNCERBULLET];
preset.animSpeed = 6;
preset.behavior = behavior::bullet;
preset.bulletHandling = HANDLING::IGNOREBULLET;
preset.counterEnd = 100;
preset.doesHurt = 1;
preset.freeze = 0;
preset.isFreezable = false;
preset.killAnim = preset.determineCurAnim(ANIM::AMMO, 10, false);
preset.lightType = LIGHT::NONE;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.special = preset.determineCurAnim(ANIM::AMMO, 22, false);
preset.xAcc = preset.yAcc = preset.ySpeed = 0;
preset.xSpeed = 10;
preset.determineCurAnim(ANIM::AMMO, 20);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::ICEBULLET];
preset.animSpeed = 25;
preset.behavior = behavior::asmdBeam;
preset.bulletHandling = HANDLING::IGNOREBULLET;
preset.counterEnd = 40;
preset.doesHurt = 3;
preset.freeze = 0;
preset.isFreezable = false;
preset.killAnim = preset.determineCurAnim(ANIM::AMMO, 71, false);
preset.light = 4;
preset.lightType = LIGHT::RING2;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.special = preset.determineCurAnim(ANIM::AMMO, 65, false);
preset.xAcc = preset.yAcc = preset.ySpeed = 0;
preset.xSpeed = 10;
preset.determineCurAnim(ANIM::AMMO, 73);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::SEEKERBULLET];
preset.animSpeed = 1000;
preset.behavior = behavior::rocket;
preset.bulletHandling = HANDLING::IGNOREBULLET;
preset.doesHurt = 7;
preset.freeze = 0;
preset.isFreezable = false;
preset.lightType = LIGHT::NONE;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.xAcc = preset.yAcc = preset.ySpeed = 0;
preset.xSpeed = 10;
@preset = jjObjectPresets[OBJECT::RFBULLET];
preset.animSpeed = 10;
preset.behavior = behavior::flak;
preset.bulletHandling = HANDLING::IGNOREBULLET;
preset.counterEnd = 35;
preset.doesHurt = 6;
preset.freeze = 0;
preset.isFreezable = false;
preset.lightType = LIGHT::NONE;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.special = 3;
preset.xAcc = -0.1f;
preset.yAcc = 0.1f;
preset.xSpeed = 15;
preset.ySpeed = 0;
@preset = jjObjectPresets[OBJECT::TOASTERBULLET];
preset.animSpeed = 5;
preset.behavior = behavior::flame;
preset.bulletHandling = HANDLING::IGNOREBULLET;
preset.counterEnd = 40;
preset.doesHurt = 2;
preset.freeze = 0;
preset.isFreezable = false;
preset.lightType = LIGHT::NONE;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.xAcc = -0.2f;
preset.xSpeed = 3;
preset.yAcc = preset.ySpeed = 0;
preset.determineCurAnim(ANIM::AMMO, 13);
@preset = jjObjectPresets[OBJECT::TNT];
preset.behavior = behavior::barrel;
preset.bulletHandling = HANDLING::DETECTBULLET;
preset.counterEnd = 15;
preset.energy = 100;
preset.freeze = 0;
preset.isFreezable = false;
preset.lightType = LIGHT::NONE;
preset.playerHandling = HANDLING::SPECIAL;
preset.scriptedCollisions = true;
preset.special = -1;
preset.determineCurAnim(ANIM::PICKUPS, 3);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::BOUNCERAMMO3];
preset.behavior = behavior::pickup;
preset.scriptedCollisions = true;
preset.determineCurAnim(ANIM::HATTER, 1);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::ICEAMMO3];
preset.behavior = behavior::pickup;
preset.scriptedCollisions = true;
preset.determineCurAnim(ANIM::AMMO, 69);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::SEEKERAMMO3];
preset.behavior = behavior::pickup;
preset.scriptedCollisions = true;
preset.determineCurAnim(ANIM::SONCSHIP, 0);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::RFAMMO3];
preset.behavior = behavior::pickup;
preset.scriptedCollisions = true;
preset.determineCurAnim(ANIM::LIZARD, 1);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::TOASTERAMMO3];
preset.behavior = behavior::pickup;
preset.scriptedCollisions = true;
preset.determineCurAnim(ANIM::BILSBOSS, 3);
preset.determineCurFrame();
@preset = jjObjectPresets[OBJECT::CARROT];
preset.behavior = behavior::pickup;
preset.points = 1;
@preset = jjObjectPresets[OBJECT::EXPLOSION];
preset.behavior = behavior::explosion;
@preset = jjObjectPresets[OBJECT::COLLAPSESCENERY];
preset.behavior = behavior::destructScenery;
@preset = jjObjectPresets[OBJECT::DESTRUCTSCENERY];
preset.behavior = behavior::destructScenery;
preset.points = 0;
@preset = jjObjectPresets[OBJECT::DESTRUCTSCENERYBOMB];
preset.behavior = behavior::destructScenery;
preset.points = 0;
@preset = jjObjectPresets[OBJECT::STOMPSCENERY];
preset.behavior = behavior::destructScenery;
preset.points = 0;
@preset = jjObjectPresets[OBJECT::REDSPRING];
preset.behavior = behavior::spring;
@preset = jjObjectPresets[OBJECT::GREENSPRING];
preset.behavior = behavior::spring;
@preset = jjObjectPresets[OBJECT::BLUESPRING];
preset.behavior = behavior::spring;
@preset = jjObjectPresets[OBJECT::FLOATLIZARD];
preset.behavior = behavior::enemy;
preset.isFreezable = false;
preset.playerHandling = HANDLING::PARTICLE;
@preset = jjObjectPresets[OBJECT::CHECKPOINT];
preset.behavior = behavior::savePoint;
for (int i = 1; i < 256; i++) {
@preset = jjObjectPresets[i];
preset.deactivates = false;
}
}
void palette() {
jjPalette.fill(255, 255, 0, 104, 1);
jjPalette.fill(192, 192, 0, 117, 1);
jjPalette.gradient(200, 200, 0, 0, 0, 0, 123, 5);
jjPalette.gradient(255, 255, 0, 192, 0, 0, 144, 5);
jjPalette.gradient(192, 0, 0, 0, 0, 0, 148, 4);
jjPalette.gradient(128, 192, 192, 32, 48, 48);
jjPalette.apply();
}
void specialTiles() {
for (int i = 0; i < jjLayerHeight[4]; i++) {
for (int j = 0; j < jjLayerWidth[4]; j++) {
switch (jjTileGet(4, j, i)) {
case tileset::ventShaft:
level::specialTile.insertLast(TventShaft(j, i));
break;
}
}
}
}
void weaponProfiles() {
jjWEAPON@ weapon;
@weapon = jjWeapons[WEAPON::BLASTER];
weapon.infinite = false;
weapon.maximum = 24;
weapon.multiplier = 1;
weapon.replenishes = true;
weapon.style = WEAPON::NORMAL;
@weapon = jjWeapons[WEAPON::BOUNCER];
weapon.infinite = false;
weapon.maximum = 120;
weapon.multiplier = 1;
weapon.replenishes = false;
weapon.style = WEAPON::NORMAL;
@weapon = jjWeapons[WEAPON::ICE];
weapon.infinite = false;
weapon.maximum = 40;
weapon.multiplier = 1;
weapon.replenishes = false;
weapon.style = WEAPON::NORMAL;
@weapon = jjWeapons[WEAPON::SEEKER];
weapon.infinite = false;
weapon.maximum = 4;
weapon.multiplier = 1;
weapon.replenishes = false;
weapon.style = WEAPON::NORMAL;
@weapon = jjWeapons[WEAPON::RF];
weapon.infinite = false;
weapon.maximum = client::isCoopOrSP() ? 0 : 16;
weapon.multiplier = 1;
weapon.replenishes = false;
weapon.style = WEAPON::NORMAL;
@weapon = jjWeapons[WEAPON::TOASTER];
weapon.infinite = false;
weapon.maximum = client::isCoopOrSP() ? 0 : 300;
weapon.multiplier = 1;
weapon.replenishes = false;
weapon.style = WEAPON::NORMAL;
@weapon = jjWeapons[WEAPON::TNT];
weapon.infinite = false;
weapon.maximum = 0;
@weapon = jjWeapons[WEAPON::GUN8];
weapon.infinite = false;
weapon.maximum = 0;
@weapon = jjWeapons[WEAPON::GUN9];
weapon.infinite = false;
weapon.maximum = 0;
}
}
namespace level {
array<Itile@> specialTile;
bool isLineMaskFree(int xPos1, int yPos1, int xPos2, int yPos2) {
int xLength = xPos2 - xPos1;
int yLength = yPos2 - yPos1;
if (xLength == 0 && yLength == 0)
return !jjMaskedPixel(xPos1, yPos1);
int x, y;
if (abs(xLength) >= abs(yLength)) {
if (xPos1 < xPos2) {
x = xPos1;
y = yPos1;
} else {
x = xPos2;
y = yPos2;
xLength = -xLength;
yLength = -yLength;
}
for (int i = 0; i <= xLength; i++) {
if (jjMaskedPixel(x + i, y + i * yLength / xLength))
return false;
}
} else {
if (yPos1 < yPos2) {
x = xPos1;
y = yPos1;
} else {
x = xPos2;
y = yPos2;
xLength = -xLength;
yLength = -yLength;
}
for (int i = 0; i <= yLength; i++) {
if (jjMaskedPixel(x + i * xLength / yLength, y + i))
return false;
}
}
return true;
}
}
namespace sprite {
array<array<Tsprite>> spriteQueue(8);
void add(float x, float y, uint frame, int direction = 0, SPRITE::Mode mode = SPRITE::NORMAL, uint8 param = 0, uint8 layer = 4) {
if (client::isIdleServer())
return;
Tsprite sprite;
sprite.x = int(floor(x));
sprite.y = int(floor(y));
sprite.frame = frame;
sprite.direction = direction;
sprite.mode = mode;
sprite.param = param;
spriteQueue[layer - 1].insertLast(sprite);
}
void clearQueues() {
for (uint i = 0; i < spriteQueue.length(); i++) {
spriteQueue[i].resize(0);
}
}
void drawQueue(jjCANVAS@ canvas, uint8 layer) {
for (uint i = 0; i < spriteQueue[layer].length(); i++) {
spriteQueue[layer][i].draw(canvas);
}
}
}
namespace text {
const array<int> smallFontCharacterWidth = {8, 6, 7, 15, 10, 12, 0, 4, 9, 9, 10, 13, 6, 10, 5, 11, 10, 8 /*actually 6*/, 11, 10, 11, 10, 9, 8, 9, 8, 6, 7, 9, 11, 9, 10, 14, 11, 11, 10, 12, 12, 9, 11, 9, 10, 11, 12, 10, 12, 12, 11, 10, 11, 12, 9, 11, 11, 9, 12, 10, 9, 11, 8, 11, 8, 13, 10, 6, 10, 9, 9, 9, 11, 9, 10, 10, 6, 9, 10, 6, 11, 10, 9, 10, 10, 10, 10, 9, 10, 9, 12, 9, 8, 9, 0, 0, 0, 0, 0};
int getScoreHUDHeight(GAME::Mode mode) {
switch (jjGameMode) {
case GAME::BATTLE:
case GAME::TREASURE:
return 36;
case GAME::CTF:
switch (jjGameCustom) {
case GAME::DOM:
case GAME::JB:
case GAME::TLRS:
return 80;
default:
return 62;
}
case GAME::RACE:
return 62;
case GAME::COOP:
case GAME::SP:
return 16;
}
return 0;
}
int getSmallFontIntWidth(string text) {
int width = 0;
for (uint i = 0; i < text.length(); i++) {
if(text[i] - 32 < smallFontCharacterWidth.length())
width += smallFontCharacterWidth[text[i] - 32] + 1;
else
width++;
}
return width;
}
}
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.