Downloads containing CursedCrossbow.asc

Downloads
Name Author Game Mode Rating
Custom MLLE Naps WeaponPack Naps Other N/A Download file

File preview

#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();
		}
	}
}