Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Penelope | cooba | Capture the flag | 9 | |||||
Intergalactic Destination | Dragusela | Battle | N/A | |||||
Anniversary Bash 26 CTF | Jazz2Online | Capture the flag | N/A | |||||
Anniversary Bash 26 Battle | Jazz2Online | Battle | N/A | |||||
Cybercity | koralyx | Tileset | 9.2 | |||||
Anniversary Bash 25 Battle | Jazz2Online | Battle | N/A | |||||
Anniversary Bash 25 CTF | Jazz2Online | Capture the flag | N/A | |||||
Anniversary Bash 24 Battle | Jazz2Online | Battle | N/A | |||||
Acid Reign | cooba | Battle | 9.2 | |||||
Anniversary Bash 23 levels | Jazz2Online | Multiple | N/A | |||||
Goliath Woods | PurpleJazz | Capture the flag | 8.9 | |||||
Hollow of the Haunted | cooba | Capture the flag | 9.2 | |||||
Giant's Steps | PurpleJazz | Capture the flag | 9.2 | |||||
Anniversary Bash 22 levels | Jazz2Online | Multiple | N/A | |||||
Party Crash Landing | cooba | Battle | 9.5 | |||||
Anniversary Bash 21 Levels | Jazz2Online | Multiple | N/A | |||||
The Fingers of Icarus | cooba | Battle | 8.8 | |||||
Cleanse | Seren | Capture the flag | 8.7 | |||||
Anniversary Bash 20 Levels | Jazz2Online | Multiple | N/A | |||||
Press Garden | SmokeNC | Battle | 9.2 | |||||
Standard Weapon Interface | Seren | Other | 10 |
#pragma require "SEweapon.asc"
#pragma require "SEenergyblast.j2a"
#pragma offer "SEenergyblast.wav"
#include "SEweapon.asc"
namespace se {
shared class EnergyBlastWeapon : WeaponInterface {
private ::jjANIMSET@ m_animSet;
private SOUND::Sample m_sample = SOUND::COMMON_BURNIN;
private ::array<int> m_lastUsed(32, -15), m_lastObserved(32, -1), m_sampleHandle(32, 0);
private int m_soundFrequency = 25000;
protected ::jjANIMSET@ getAnimSet() const {
return @m_animSet;
}
protected SOUND::Sample getSample() const {
return m_sample;
}
protected bool loadAnimSet(::jjANIMSET@ animSet, const ::string &in filename, uint setID) {
if (animSet !is null && !::jjSTREAM(filename).isEmpty()) {
@m_animSet = @animSet.load(setID, filename);
return true;
}
return false;
}
protected bool loadSample(SOUND::Sample sample, const ::string &in filename) {
if (::jjSampleLoad(sample, filename)) {
m_sample = sample;
m_soundFrequency = 150000;
return true;
}
return false;
}
protected bool lowestFreePlayerSpace(float x, float y, float height = 0.f, float &out result = void) {
int left = int(x) - 12;
int top = int(y) - 12;
int row = int(y + height) - 12;
int bottom = row + 24;
while (row >= top) {
int start = row;
while (!::jjMaskedHLine(left, 24, row)) {
row++;
if (row == bottom) {
result = start + 12;
return true;
}
}
bottom = start;
row -= 24;
}
return false;
}
protected void behave(::jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
if (obj.creatorType != CREATOR::PLAYER || m_lastObserved[obj.creatorID] < ::jjGameTicks) {
if (obj.creatorType == CREATOR::PLAYER)
m_lastObserved[obj.creatorID] = ::jjGameTicks;
int angle = int(atan2(-obj.ySpeed, obj.xSpeed) * 162.974662f + 768.5f);
obj.state = STATE::FLY;
if (obj.ySpeed > 10.f)
obj.ySpeed = 10.f;
else if (obj.ySpeed < -10.f)
obj.ySpeed = -10.f;
{
float xNew = obj.xPos + obj.xSpeed;
float yNew = obj.yPos + obj.ySpeed;
if (lowestFreePlayerSpace(xNew, yNew)) {
obj.xPos = xNew;
obj.yPos = yNew;
if (!lowestFreePlayerSpace(xNew + obj.xSpeed, yNew + obj.ySpeed))
obj.xSpeed = obj.ySpeed = 0.f;
} else {
bool ok = obj.ySpeed >= 0.f;
float yFree;
if (ok) {
float y = obj.yPos - ::abs(obj.xSpeed);
ok = lowestFreePlayerSpace(xNew, y, yNew - y, yFree);
}
if (ok) {
obj.xPos = xNew;
obj.yPos = yFree;
obj.ySpeed = yFree - obj.yPos;
} else if (lowestFreePlayerSpace(obj.xPos, yNew)) {
obj.yPos = yNew;
obj.xSpeed = 0.f;
} else {
obj.xSpeed = obj.ySpeed = 0.f;
}
}
}
obj.yPos -= 8.f;
array<int> colors = {obj.var[6] & 8 != 0 ? 84 : 60, obj.var[6] & 8 != 0 ? 80 : 40};
for (int i = 0; i < 2; i++) {
const ::jjANIMATION@ anim = ::jjAnimations[obj.curAnim + 3];
int frame = anim + ::jjGameTicks % anim.frameCount;
::jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, frame, angle, i * 2 - 1.f, 1.f, SPRITE::ALPHAMAP, colors[i], 4);
}
for (int i = 0; i < 2; i++) {
const ::jjANIMATION@ anim = ::jjAnimations[obj.curAnim + i + 1];
int frame = anim + ::jjGameTicks % anim.frameCount;
::jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, frame, angle, 1.f, 1.f, SPRITE::ALPHAMAP, colors[1], i + 3);
}
}
break;
case STATE::FLY:
obj.state = STATE::EXPLODE;
break;
case STATE::EXPLODE:
case STATE::KILL:
case STATE::DEACTIVATE:
obj.delete();
break;
}
}
protected void behaveTNT(::jjOBJ@ obj) {
if (obj.creatorType == CREATOR::PLAYER && ::jjPlayers[obj.creatorID].powerup[WEAPON::TNT]) {
obj.animSpeed = 2;
obj.var[6] = 24;
obj.xSpeed = 16.f;
} else {
obj.animSpeed = 1;
obj.var[6] = 16;
obj.xSpeed = 14.f;
}
obj.behavior = @::jjVOIDFUNCOBJ(behave);
obj.behave();
}
protected void disableControl(::jjPLAYER@ player) const {
float xPos = player.xPos;
float yPos = player.yPos;
::jjOBJ@ obj = ::jjObjects[0];
int state = obj.state;
int var = obj.var[0];
int counter = obj.counter;
obj.state = STATE::ACTION;
obj.var[0] = player.playerID;
obj.behave(BEHAVIOR::EVA, false);
obj.state = state;
obj.var[0] = var;
obj.counter = counter;
player.idle = 0;
player.xPos = xPos;
player.yPos = yPos;
}
protected void reactToPlayerInput(::jjPLAYER@ player, int number) {
const array<int> forbiddenChars = {CHAR::FROG, CHAR::BIRD};
const array<int> forbiddenEvents = {AREA::HPOLE, AREA::VPOLE, AREA::WARP, AREA::SUCKERTUBE};
if (forbiddenChars.find(player.charCurr) >= 0)
return;
bool forbidden = player.health <= 0 || player.noFire || player.fly > 1 || player.warpID != 0 && player.xSpeed == 0.f && player.ySpeed == 0.f || player.charCurr == CHAR::BIRD2 || forbiddenEvents.find(::jjEventGet(int(player.xPos) >> 5, int(player.yPos) >> 5)) >= 0;
if (forbidden) {
m_lastUsed[player.playerID] = -15;
if (int(player.currWeapon) == number)
player.keyFire = false;
return;
}
bool using = int(player.currWeapon) == number && player.keyFire && player.frozen == 0;
if (using)
m_lastUsed[player.playerID] = ::jjGameTicks;
if (using || ::jjGameTicks - m_lastUsed[player.playerID] < 15) {
const float tau = 6.28318531f, pi = 3.14159265f, pi4 = 0.785398163f;
const float dirUp = 0.f, dirRight = 1.57079633f, dirDown = pi, dirLeft = 4.71238898f;
const float angularVelocity = 0.2f, gravity = 0.125f;
bool ignoreCurrent = ::closeTo(player.xSpeed, 0.f) && player.ySpeed <= gravity && player.ySpeed >= 0.f;
float current, direction;
if (ignoreCurrent) {
if (player.buttstomp < 81) {
current = dirDown;
ignoreCurrent = false;
}
} else {
current = ::atan2(player.xSpeed, -(player.ySpeed - gravity));
}
if (::jjAllowsMouseAim && ::jjMouseAim) {
float x, y;
x = ::jjMouseX + player.cameraX - player.xPos;
y = ::jjMouseY + player.cameraY - player.yPos;
direction = ::atan2(x, -y);
} else {
int x = 0, y = 0;
if (player.keyLeft)
x--;
if (player.keyRight)
x++;
if (player.keyUp)
y--;
if (player.keyDown)
y++;
if (x == 0 && y == 0) {
if (ignoreCurrent) {
direction = player.direction < 0 ? dirLeft : dirRight;
} else {
direction = current / pi4;
float frac = ::fraction(direction);
if (frac >= 0.5f || frac < 0.f && frac >= -0.5f)
direction = ::ceil(direction);
else
direction = ::floor(direction);
direction *= pi4;
}
} else {
direction = ::atan2(x, -y);
}
}
if (!ignoreCurrent) {
float difference = direction - current;
difference = (difference + tau) % tau;
if (::closeTo(difference, pi)) {
direction = player.direction < 0 ? dirLeft : dirRight;
difference = direction - current;
difference = (difference + tau) % tau;
if (::closeTo(difference, 0.f) || ::closeTo(difference, pi)) {
direction = dirUp;
difference = direction - current;
difference = (difference + tau) % tau;
}
}
if (difference < pi) {
if (difference > angularVelocity)
difference = angularVelocity;
} else {
difference -= tau;
if (difference < -angularVelocity)
difference = -angularVelocity;
}
direction = current + difference;
}
float xSpeed = player.xSpeed;
float ySpeed = player.ySpeed;
player.xSpeed = 0.f;
player.ySpeed = 0.f;
int id = player.fireBullet(number, true, true, direction + tau);
if (id > 0) {
const ::jjOBJ@ obj = @::jjObjects[id];
disableControl(@player);
player.ballTime = 10;
player.currWeapon = number;
player.xAcc = 0.f;
player.yAcc = 0.f;
player.xSpeed = obj.xSpeed;
player.ySpeed = player.antiGrav ? -obj.ySpeed : obj.ySpeed;
player.keyLeft = false;
player.keyRight = false;
player.keyUp = false;
player.keyDown = player.yPos < ::jjWaterLevel;
player.keyJump = false;
player.keyRun = false;
player.buttstomp = player.keyDown ? 81 : 121;
player.fly = FLIGHT::NONE;
player.helicopter = 0;
player.specialMove = 0;
if (player.invincibility > -2 && player.invincibility < 2)
player.invincibility = -2;
int volume = player.ammo[number] << 3 | 4;
int vol2 = 63 - ((::jjGameTicks - m_lastUsed[player.playerID]) << 2);
if (volume > vol2)
volume = vol2;
m_sampleHandle[player.playerID] = ::jjSampleLooped(obj.xPos, obj.yPos, m_sample, m_sampleHandle[player.playerID], volume, m_soundFrequency);
} else {
m_lastUsed[player.playerID] = -15;
player.xSpeed = xSpeed;
player.ySpeed = ySpeed;
do {
if (player.currWeapon == WEAPON::BLASTER)
player.currWeapon = WEAPON::GUN9;
else
player.currWeapon = player.currWeapon - 1;
} while (player.ammo[player.currWeapon] <= 0 && int(player.currWeapon) != number);
if (int(player.currWeapon) == number)
player.currWeapon = WEAPON::BLASTER;
}
}
}
protected void prepareWeaponProfile(::jjWEAPON@ weapon) const {
weapon.comesFromBirds = false;
weapon.comesFromBirdsPowerup = false;
weapon.defaultSample = false;
weapon.gradualAim = false;
weapon.multiplier = 3;
weapon.replacedByBubbles = false;
weapon.spread = SPREAD::NORMAL;
weapon.style = WEAPON::POPCORN;
}
protected void prepareBulletPresets(::jjOBJ@ basic, ::jjOBJ@ powerup, uint number) const {
if (basic is powerup)
basic.behavior = @::jjVOIDFUNCOBJ(behaveTNT);
else
basic.behavior = powerup.behavior = @::jjVOIDFUNCOBJ(behave);
basic.animSpeed = 1;
powerup.animSpeed = 2;
basic.counterEnd = powerup.counterEnd = 1;
basic.curAnim = powerup.curAnim = basic.special = powerup.special = m_animSet + 4;
basic.curFrame = powerup.curFrame = ::jjAnimations[basic.curAnim];
basic.direction = powerup.direction = 0;
basic.energy = powerup.energy = basic.freeze = powerup.freeze = 0;
basic.frameID = powerup.frameID = 0;
basic.killAnim = powerup.killAnim = 0;
basic.lightType = powerup.lightType = LIGHT::NONE;
basic.playerHandling = powerup.playerHandling = HANDLING::PLAYERBULLET;
basic.var[3] = powerup.var[3] = number;
basic.var[6] = 16;
powerup.var[6] = 24;
basic.xAcc = powerup.xAcc = 0.f;
basic.yAcc = powerup.yAcc = 0.f;
basic.xSpeed = 14.f;
powerup.xSpeed = 16.f;
basic.ySpeed = powerup.ySpeed = 0.f;
}
protected void preparePickupPresets(::jjOBJ@ ammo3, ::jjOBJ@ ammo15, ::jjOBJ@ powerup) const {
if (ammo3 !is null) {
ammo3.behavior = @AmmoPickup(::jjAnimations[m_animSet], ::jjAnimations[m_animSet + 1], 5);
ammo3.curAnim = m_animSet;
ammo3.frameID = 0;
ammo3.determineCurFrame();
}
if (ammo15 !is null) {
ammo15.curAnim = m_animSet + 2;
ammo15.frameID = 0;
ammo15.determineCurFrame();
}
if (powerup !is null) {
powerup.curAnim = m_animSet + 3;
powerup.frameID = 0;
powerup.determineCurFrame();
}
}
::jjANIMSET@ loadAnims(::jjANIMSET@ animSet) override {
loadAnimSet(animSet, "SEenergyblast.j2a", 0);
return @animSet;
}
::array<bool>@ loadSamples(const ::array<SOUND::Sample>& samples) override {
return @::array<bool>(1, samples.length() == 1 && loadSample(samples[0], "SEenergyblast.wav"));
}
uint getSampleCount() const override {
return 1;
}
uint getTraits(bool) const override {
return weapon_default_traits | weapon_increases_mobility;
}
uint getMaxDamage(bool powerup) const override {
return powerup ? 2 : 1;
}
bool setAsWeapon(uint number, WeaponHook@ weaponHook) override {
if (m_animSet !is null && isValidWeapon(number) && weaponHook !is null) {
uint basic = getBasicBulletOfWeapon(number);
uint powered = getPoweredBulletOfWeapon(number);
uint ammo3 = getAmmoPickupOfWeapon(number);
uint ammo15 = getAmmoCrateOfWeapon(number);
uint powerup = getPowerupMonitorOfWeapon(number);
weaponHook.resetCallbacks(number);
weaponHook.setWeaponSprite(number, false, ::jjAnimations[m_animSet]);
weaponHook.setWeaponSprite(number, true, ::jjAnimations[m_animSet + 1]);
weaponHook.setPlayerInputCallback(number, @PlayerCallback(reactToPlayerInput));
prepareWeaponProfile(@::jjWeapons[number]);
prepareBulletPresets(@::jjObjectPresets[basic], @::jjObjectPresets[powered], number);
preparePickupPresets(ammo3 != 0 ? @::jjObjectPresets[ammo3] : null, ammo15 != 0 ? @::jjObjectPresets[ammo15] : null, @::jjObjectPresets[powerup]);
return true;
}
return false;
}
}
EnergyBlastWeapon energyBlast;
}
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.