#pragma require "SEweapon.asc"
#pragma require "SEroller.j2a"
#pragma offer "SEroller.wav"
#include "SEweapon.asc"
namespace se {
shared class RollerWeapon : WeaponInterface {
private ::jjANIMSET@ m_animSet;
private SOUND::Sample m_sample = SOUND::COMMON_FLAP;
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;
return true;
}
return false;
}
protected bool move(::jjOBJ@ obj, int mask, float verticalTolerance, float maxSpeed) const {
::jjANIMFRAME@ maskFrame = @::jjAnimFrames[::jjAnimations[m_animSet + mask]];
float xRadius = maskFrame.width / 2.f, yRadius = maskFrame.height / 2.f;
float xCenter = obj.xPos + maskFrame.hotSpotX + xRadius, yCenter = obj.yPos + maskFrame.hotSpotY + yRadius;
float xAvg = 0.f, yAvg = 0.f;
bool noRoom = true;
bool overWater = obj.yPos < ::jjWaterLevel;
bool canSkipOverWater = overWater && obj.ySpeed > 1.5f && ::abs(obj.xSpeed) > obj.ySpeed;
bool skippingOverWater = false;
for (int i = 0; i < 1024; i += 16) {
float cosine = ::jjCos(i);
float sine = ::jjSin(i);
float x = xCenter + cosine * xRadius;
float y = yCenter + sine * yRadius;
if (::jjMaskedPixel(int(x + 0.5f), int(y + 0.5f))) {
xAvg += cosine;
yAvg += sine;
} else if (canSkipOverWater && y >= ::jjWaterLevel) {
skippingOverWater = true;
xAvg += cosine;
yAvg += sine;
} else {
noRoom = false;
}
}
float avg = sqrt(xAvg * xAvg + yAvg * yAvg);
float xSpeed = obj.xSpeed, ySpeed = obj.ySpeed + obj.yAcc;
if (avg != 0.f) {
xAvg /= avg;
yAvg /= avg;
if (::abs(xAvg) <= verticalTolerance) {
xSpeed += yAvg * obj.xAcc;
ySpeed -= xAvg * obj.xAcc;
}
float projection = xSpeed * xAvg + ySpeed * yAvg;
if (projection > 0.f) {
if (skippingOverWater)
projection *= 1.8f;
xSpeed -= projection * xAvg;
ySpeed -= projection * yAvg;
}
}
float speed = sqrt(xSpeed * xSpeed + ySpeed * ySpeed);
if (speed > maxSpeed) {
float factor = maxSpeed / speed;
xSpeed *= factor;
ySpeed *= factor;
}
obj.xSpeed = xSpeed;
obj.ySpeed = ySpeed;
obj.xPos += xSpeed;
obj.yPos += ySpeed;
if (skippingOverWater || overWater && obj.yPos >= ::jjWaterLevel) {
int id = ::jjAddObject(OBJECT::EXPLOSION, obj.xPos, ::jjWaterLevel, obj.objectID);
if (id != 0) {
::jjOBJ@ splash = @::jjObjects[id];
splash.determineCurAnim(ANIM::COMMON, 3);
::jjSample(obj.xPos, ::jjWaterLevel, SOUND::COMMON_WATER, 32);
}
}
return noRoom;
}
protected void behaveCommon(::jjOBJ@ obj, int mask, float verticalTolerance, float maxSpeed) const {
switch (obj.state) {
case STATE::START:
if (obj.creatorType == CREATOR::PLAYER && ::jjPlayers[obj.creatorID].isLocal)
::jjSample(obj.xPos, obj.yPos, m_sample);
if (obj.xSpeed == 0.f) {
if (obj.var[7] != 0)
obj.direction = obj.var[7] < 0 ? -1 : 1;
else if (::jjGameConnection != GAME::LOCAL)
obj.direction = 1;
else if (obj.creatorType == CREATOR::PLAYER)
obj.direction = ::jjPlayers[obj.creatorID].direction;
else if (obj.creatorType == CREATOR::OBJECT)
obj.direction = ::jjObjects[obj.creatorID].direction;
}
obj.xAcc = ::jjObjectPresets[obj.eventID].xAcc;
if (obj.direction < 0)
obj.xAcc = -obj.xAcc;
obj.yAcc = ::jjObjectPresets[obj.eventID].yAcc;
obj.xSpeed += obj.var[7] / 1e5f;
obj.state = STATE::ROTATE;
case STATE::ROTATE:
if (move(obj, mask, verticalTolerance, maxSpeed) || obj.counter++ > int(obj.counterEnd))
obj.state = STATE::EXPLODE;
if (::jjGameTicks % 3 == 0) {
obj.frameID++;
if (obj.frameID >= int(::jjAnimations[obj.curAnim].frameCount))
obj.frameID = 0;
}
obj.determineCurFrame();
obj.draw();
break;
case STATE::EXPLODE:
obj.curAnim = obj.killAnim;
if (obj.curAnim == 0) {
obj.delete();
} else {
if (obj.playerHandling != HANDLING::EXPLOSION) {
obj.frameID = obj.freeze = 0;
obj.isTarget = obj.triggersTNT = false;
obj.playerHandling = HANDLING::EXPLOSION;
}
if (::jjGameTicks & 3 == 0)
obj.frameID++;
if (obj.frameID < int(::jjAnimations[obj.curAnim].frameCount)) {
obj.determineCurFrame();
obj.draw();
} else {
obj.delete();
}
}
break;
case STATE::KILL:
case STATE::DEACTIVATE:
obj.delete();
break;
}
}
protected void behaveBasic(::jjOBJ@ obj) const {
behaveCommon(obj, 8, 0.9f, obj.yPos < ::jjWaterLevel ? 14.f : 8.f);
}
protected void behavePowered(::jjOBJ@ obj) const {
if (obj.yPos >= ::jjWaterLevel) {
obj.behavior = @::jjVOIDFUNCOBJ(behaveBasic);
obj.counterEnd = 90;
obj.curFrame = ::jjAnimations[obj.curAnim = obj.special = m_animSet + 4];
obj.killAnim = m_animSet + 6;
obj.var[6] = 0;
obj.behave();
::jjANIMFRAME@ maskFrame = @::jjAnimFrames[::jjAnimations[m_animSet + 9]];
float xRadius = maskFrame.width / 2.f, yRadius = maskFrame.height / 2.f;
for (int i = 0; i < 1024; i += 64) {
::jjAddObject(OBJECT::BUBBLE, obj.xPos + ::jjSin(i) * xRadius, obj.yPos + ::jjCos(i) * yRadius, obj.objectID);
}
} else {
behaveCommon(obj, 9, 2.f, 14.f);
}
}
protected void behaveTNT(::jjOBJ@ obj) const {
if (obj.creatorType == CREATOR::PLAYER && ::jjPlayers[obj.creatorID].powerup[WEAPON::TNT]) {
obj.behavior = @::jjVOIDFUNCOBJ(behavePowered);
obj.counterEnd = 120;
obj.curFrame = ::jjAnimations[obj.curAnim = obj.special = m_animSet + 5];
obj.killAnim = m_animSet + 7;
obj.var[6] = 26;
} else {
obj.behavior = @::jjVOIDFUNCOBJ(behaveBasic);
obj.counterEnd = 90;
obj.curFrame = ::jjAnimations[obj.curAnim = obj.special = m_animSet + 4];
obj.killAnim = m_animSet + 6;
obj.var[6] = 0;
}
obj.behave();
}
protected void prepareWeaponProfile(::jjWEAPON@ weapon) const {
weapon.defaultSample = false;
weapon.gradualAim = false;
weapon.multiplier = 1;
weapon.replacedByBubbles = false;
weapon.spread = SPREAD::NORMAL;
weapon.style = WEAPON::NORMAL;
}
protected void prepareBulletPresets(::jjOBJ@ basic, ::jjOBJ@ powerup, uint number) const {
if (basic is powerup) {
basic.behavior = @::jjVOIDFUNCOBJ(behaveTNT);
} else {
basic.behavior = @::jjVOIDFUNCOBJ(behaveBasic);
powerup.behavior = @::jjVOIDFUNCOBJ(behavePowered);
}
basic.animSpeed = powerup.animSpeed = 2;
basic.counterEnd = 90;
powerup.counterEnd = 120;
basic.curFrame = ::jjAnimations[basic.curAnim = basic.special = m_animSet + 4];
powerup.curFrame = ::jjAnimations[powerup.curAnim = powerup.special = m_animSet + 5];
basic.direction = powerup.direction = 1;
basic.energy = powerup.energy = basic.freeze = powerup.freeze = 0;
basic.frameID = powerup.frameID = 0;
basic.killAnim = m_animSet + 6;
powerup.killAnim = m_animSet + 7;
basic.lightType = powerup.lightType = LIGHT::POINT;
basic.playerHandling = powerup.playerHandling = HANDLING::PLAYERBULLET;
basic.var[3] = powerup.var[3] = number;
basic.var[6] = 0;
powerup.var[6] = 26;
basic.xAcc = powerup.xAcc = 0.5f;
basic.yAcc = powerup.yAcc = 0.25f;
basic.xSpeed = powerup.xSpeed = 5.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]);
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, "SEroller.j2a", 0);
return @animSet;
}
::array<bool>@ loadSamples(const ::array<SOUND::Sample>& samples) override {
return @::array<bool>(1, samples.length() == 1 && loadSample(samples[0], "SEroller.wav"));
}
uint getSampleCount() const override {
return 1;
}
uint getTraits(bool powerup) const override {
uint result = weapon_default_traits;
if (powerup)
result |= weapon_melts_ice;
return result;
}
uint getMaxDamage(bool powerup) const override {
return powerup ? 2 : 1;
}
bool setAsWeapon(uint number, WeaponHook@ weaponHook = null) override {
if (m_animSet !is null && isValidWeapon(number)) {
uint basic = getBasicBulletOfWeapon(number);
uint powered = getPoweredBulletOfWeapon(number);
uint ammo3 = getAmmoPickupOfWeapon(number);
uint ammo15 = getAmmoCrateOfWeapon(number);
uint powerup = getPowerupMonitorOfWeapon(number);
if (weaponHook !is null) {
weaponHook.resetCallbacks(number);
weaponHook.setWeaponSprite(number, false, ::jjAnimations[m_animSet]);
weaponHook.setWeaponSprite(number, true, ::jjAnimations[m_animSet + 1]);
}
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;
}
}
RollerWeapon roller;
}
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.