Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Custom MLLE Naps WeaponPack | Naps | Other | N/A |
#pragma require "CursedCrossbow.asc"
#include "MLLE-Weapons.asc"
#pragma require "CursedCrossbow.j2a"
#pragma offer "CursedCrossbow.wav" //https://elements.envato.com/object-door-slamming-door-01-HZR6YZB
#pragma offer "GhostBounce1.wav" //https://elements.envato.com/magic-whoosh-ghost-CRM46ZG
#pragma offer "GhostBounce2.wav"//https://elements.envato.com/ghost-pass-by-13258-CTFQVRE
namespace NapsWeapons {
class CursedCrossbow : MLLEWeapons::WeaponInterface {
int bounces = 1; //Number of non-pu max bounces
int bouncesPU = 2; //Number of pu max bounces
bool rapierInteraction = true; //Rapiers can take control of this ammo
CursedCrossbow() {
super(
regularObjectTemplate: MLLEWeapons::ObjectTemplate(
xSpeed: 11,
xAcc: 0.125,
animSpeed: 2,
curAnim: 0,
killAnim: 1,
lightType: LIGHT::POINT2,
counterEnd: 70
),
powerupObjectTemplate: MLLEWeapons::ObjectTemplate(
xSpeed: 11,
xAcc: 0.25,
animSpeed: 3,
curAnim: 2,
killAnim: 3,
lightType: LIGHT::POINT2,
counterEnd: 70
),
style: WEAPON::CAPPED,
animSetFilename: "CursedCrossbow.j2a",
sampleFilenames: array<string> = {"CursedCrossbow.wav","ghostBounce1.wav","ghostBounce2.wav"},
pickupAnimation: 4,
poweredUpPickupAnimation: 5,
ammoCrateAnimation: 7,
powerupAnimation: 6,
traits: se::weapon_default_traits | se::weapon_goes_through_thin_walls,
behavior: MLLEWeapons::behaviorFunction(DetermineBehavior),
apply: MLLEWeapons::applyFunction(DetermineBehavior)
);
}
void DetermineBehavior(jjOBJ@ obj, bool powerup) const {
if (obj.creatorType == CREATOR::PLAYER && jjPlayers[obj.creatorID].isLocal)
jjSample(obj.xPos, obj.yPos, Samples[0],64);
obj.var[8] = powerup? 1 : 0;
obj.behavior = jjVOIDFUNCOBJ(Behavior);
}
void Behavior(jjOBJ@ obj) const {
const bool isPowerup = MLLEWeapons::HelpfulBulletFunctions::IsPowerup(obj);
checkObjectCollision(obj);
if (obj.state == STATE::START) {
if (obj.creatorType != CREATOR::PLAYER) {
obj.playerHandling = HANDLING::ENEMYBULLET;
}
obj.var[2] = isPowerup? bouncesPU : bounces;
obj.var[4] = isPowerup? 89 : 80;
obj.state = STATE::FLY;
} else if (obj.state == STATE::FLY){
if (jjMaskedPixel(int(obj.xPos + obj.xSpeed + obj.xAcc),int(obj.yPos + obj.ySpeed))) {
if (obj.var[1] < obj.var[2]) {
obj.isBlastable = false;
obj.state = STATE::WAIT;
} else {
obj.state = STATE::EXPLODE;
obj.counter = 0;
obj.lightType = 0;
jjSample(obj.xPos, obj.yPos, Samples[2],48, (isPowerup? 40000 : 50000));
}
} else {
obj.xPos += obj.xSpeed;
obj.yPos += obj.ySpeed;
if (abs(obj.xSpeed) < 15) obj.xSpeed += obj.xAcc;
if (abs(obj.ySpeed) < 15) obj.ySpeed += obj.yAcc;
}
jjDrawRectangle(int(obj.xPos + obj.xSpeed + obj.xAcc),int(obj.yPos + obj.ySpeed),4,4,32,SPRITE::NORMAL);
} else if (obj.state == STATE::WAIT) {
obj.var[0] = lookForEnemyID(obj,220);
if (obj.var[0] > -1) {
turnTowardsTarget(obj,true);
}
} else {
obj.frameID = 0;
obj.behavior = BEHAVIOR::EXPLOSION2;
}
if ((obj.counter > int(obj.counterEnd) || obj.var[1] > obj.var[2] || obj.var[9] > 0) && obj.state != STATE::START) {
jjSample(obj.xPos, obj.yPos, Samples[2],48, (isPowerup? 40000 : 50000));
obj.state = STATE::EXPLODE;
obj.counter = 0;
obj.lightType = 0;
}
obj.counter++;
if (obj.state == STATE::FLY || obj.state == STATE::WAIT) {
if (obj.var[1] < obj.var[2])
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, MLLEWeapons::HelpfulBulletFunctions::GetAngle(obj), MLLEWeapons::HelpfulBulletFunctions::GetDirection(obj) * 1.4, 1.4, SPRITE::TRANSLUCENTCOLOR, obj.var[4]);
MLLEWeapons::HelpfulBulletFunctions::DrawAngled(obj);
} else {
obj.draw();
}
}
int lookForEnemyID(jjOBJ@ obj,uint maxDistance) {
int target = -1;
uint minDistance = maxDistance * maxDistance;
if (jjGameMode > GAME::COOP || obj.creatorType != CREATOR::PLAYER) {
for (int i = 0; i < 32; ++i) {
const jjPLAYER@ playerTarget = jjPlayers[i];
if (!playerTarget.isActive)
continue;
if (playerTarget.blink > 0)
continue;
if (!jjPlayers[obj.creatorID].isEnemy(playerTarget) && obj.creatorType == CREATOR::PLAYER)
continue;
const float dx = playerTarget.xPos - obj.xPos, dy = playerTarget.yPos - obj.yPos;
const uint distance = uint(dx * dx + dy * dy);
if (distance < minDistance && !checkCollisionBetween2Pos(int(obj.xPos),int(playerTarget.xPos),int(obj.yPos),int(playerTarget.yPos)) && !(obj.direction >= 0 && playerTarget.xPos > obj.xPos && obj.xSpeed > 0) && !(obj.direction < 1 && playerTarget.xPos < obj.xPos && obj.xSpeed < 0)) {
minDistance = distance;
target = i;
}
}
}
if (jjGameMode <= GAME::COOP && obj.creatorType == CREATOR::PLAYER) {
for (int i = 0; i < jjObjectCount; ++i) {
const jjOBJ@ monster = jjObjects[i];
if (!monster.isActive)
continue;
if (!monster.isTarget)
continue;
const float dx = monster.xPos - obj.xPos, dy = monster.yPos - obj.yPos;
const uint distance = uint(dx * dx + dy * dy);
if (distance < minDistance && !checkCollisionBetween2Pos(int(obj.xPos),int(monster.xPos),int(obj.yPos),int(monster.yPos)) && !(obj.direction >= 0 && monster.xPos > obj.xPos && obj.xSpeed > 0) && !(obj.direction < 1 && monster.xPos < obj.xPos && obj.xSpeed < 0)) {
minDistance = distance;
target = i;
}
}
}
return target;
}
void turnTowardsTarget(jjOBJ@ obj,bool loseBounce) {
int destination = 0;
if (jjGameMode > GAME::COOP || obj.creatorType != CREATOR::PLAYER) {
jjPLAYER@ play = jjPlayers[obj.var[0]];
destination = int(atan2(play.yPos - obj.yPos ,play.xPos - obj.xPos) * (512 / 3.1415927f));
if (play.xPos > obj.xPos)
obj.direction = 1;
else
obj.direction = -1;
}
if (jjGameMode <= GAME::COOP && obj.creatorType == CREATOR::PLAYER) {
jjOBJ@ monster = jjObjects[obj.var[0]];
destination = int(atan2(monster.yPos - obj.yPos ,monster.xPos - obj.xPos) * (512 / 3.1415927f));
if (monster.xPos > obj.xPos)
obj.direction = 1;
else
obj.direction = -1;
}
if (loseBounce) {
jjOBJ@ Particle = jjObjects[jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType, GhostParticle)];
Particle.playerHandling = HANDLING::PARTICLE;
Particle.bulletHandling = HANDLING::IGNOREBULLET;
Particle.light = 0;
Particle.counter = 0;
Particle.determineCurAnim(SetID, 8);
Particle.determineCurFrame();
Particle.xSpeed = obj.xSpeed;
Particle.xAcc = obj.xAcc;
Particle.ySpeed = obj.ySpeed;
Particle.yAcc = obj.yAcc;
Particle.direction = obj.direction;
Particle.var[4] = obj.var[4];
}
jjSample(obj.xPos, obj.yPos, Samples[1],64);
obj.xAcc = 0.25 * jjCos(destination);
obj.xSpeed = 11 * jjCos(destination);
obj.yAcc = 0.25 * jjSin(destination);
obj.ySpeed = 11 * jjSin(destination);
if (loseBounce) {
obj.var[1] = obj.var[1] + 1;
}
obj.counterEnd += 30;
obj.isBlastable = true;
obj.state = STATE::FLY;
}
void checkObjectCollision(jjOBJ@ obj) {
if ((jjGameMode <= GAME::COOP) && rapierInteraction) {
obj.var[6] = 16;
for (int i = 0; i < jjObjectCount;i++) {
jjOBJ@ obj2 = jjObjects[i];
if (!obj2.isActive || obj2 is obj)
continue;
if (!obj.doesCollide(obj2,true))
continue;
if (obj2.eventID == OBJECT::RAPIER) {
obj.creatorType = CREATOR::OBJECT;
obj.creatorID = obj2.objectID;
obj.var[2] = obj.var[2] + 1;
obj.var[4] = 64;
obj.var[0] = lookForEnemyID(obj,220);
obj.playerHandling = HANDLING::ENEMYBULLET;
obj2.delete();
obj.counterEnd += 30;
if (obj.var[0] > -1) {
turnTowardsTarget(obj,false);
}
}
if (obj.var[6] == 16 && obj.state != STATE::START && (obj2.behavior == BEHAVIOR::MONITOR || (obj2.eventID >= OBJECT::BOMBCRATE && obj2.eventID <= OBJECT::TOASTERAMMO15) || obj2.eventID == OBJECT::GUNCRATE || obj2.eventID == OBJECT::GEMCRATE || obj2.eventID == OBJECT::CARROTCRATE || (obj2.isTarget && obj2.eventID != OBJECT::RAPIER) || obj2.eventID == OBJECT::DESTRUCTSCENERY || (((obj2.bulletHandling == HANDLING::HURTBYBULLET && obj2.energy > 0) || obj2.bulletHandling == HANDLING::DETECTBULLET) && obj2.eventID != OBJECT::RAPIER && !obj.causesRicochet))) {
obj.state = STATE::EXPLODE;
}
}
}
}
bool checkCollisionBetween2Pos(int x0,int x1,int y0,int y1) { //Taken from snippets category from j2O, code by stijn
bool steep = (abs(y1 - y0) > abs(x1 - x0));
int x2;
int y2;
if (steep) {
x2 = x0; x0 = y0; y0 = x2; //swap
y2 = x1; x1 = y1; y1 = y2; //swap
}
if (x0 > x1) {
x2 = x1; x1 = x0; x0 = x2; //swap
y2 = y1; y1 = y0; y0 = y2; //swap
}
float dx = x1 - x0;
float dy = abs(y1 - y0);
float error = dx / 2.0f;
int ystep = (y0 < y1) ? 1 : -1;
int y = int(y0);
int max_x = int(x1);
for(int x = int(x0); x < max_x; x += 1) {
if (steep) {
if(jjLayers[4].maskedPixel(y, x)) {
return true;
}
} else {
if(jjLayers[4].maskedPixel(x, y)) {
return true;
}
}
error -= dy;
if (error < 0) {
y += ystep;
error += dx;
}
}
return false;
}
bool DetermineBehavior(uint, se::WeaponHook@, jjSTREAM@ parameter) {
if (parameter !is null && parameter.getSize() >= 3) {
parameter.pop(bounces);
parameter.pop(bouncesPU);
parameter.pop(rapierInteraction);
}
return true;
}
}
void GhostParticle(jjOBJ@ obj) {
obj.determineCurFrame();
if (jjGameTicks % 5 == 0)
obj.counter++;
obj.frameID = obj.counter;
obj.counterEnd = 7;
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, MLLEWeapons::HelpfulBulletFunctions::GetAngle(obj), MLLEWeapons::HelpfulBulletFunctions::GetDirection(obj), 1, SPRITE::TRANSLUCENTSINGLEHUE, obj.var[4]);
if (obj.counter >= int(obj.counterEnd)) {
obj.delete();
}
}
}
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.