Downloads containing Buzzsawer.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Lockjaw DoubleGJ Battle N/A Download file

File preview

#pragma require "SEweapon.asc"
#pragma require "Buzzsawer.j2a"
#pragma offer "sawgrind.wav"
#include "SEweapon.asc"
class BuzzsawWeapon : se::WeaponInterface {
	private ::jjANIMSET@ m_animSet;
	private SOUND::Sample m_sample = SOUND::BUMBEE_BEELOOP;
	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 void addSparkParticle(float x, float y, float xSpeed, float ySpeed) {
		::jjPARTICLE@ part = jjAddParticle(PARTICLE::SPARK);
		part.xPos = x + xSpeed * 10.f;
		part.yPos = y + ySpeed * 10.f;
		part.xSpeed = xSpeed;
		part.ySpeed = ySpeed;
	}
	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;
		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 {
				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;
			float xContact = obj.xPos + xAvg * xRadius, yContact = obj.yPos + yAvg * yRadius;
			float xDelta = yAvg * obj.xAcc, yDelta = -xAvg * obj.xAcc;
			float sign = obj.xAcc < 0.f ? -1.f : 1.f;
			addSparkParticle(xContact, yContact, -sign * yAvg * 2.f - xAvg, sign * xAvg * 2.f - yAvg);
			obj.var[0] = jjSampleLooped(xContact, yContact, m_sample, obj.var[0]);
			if (::abs(xAvg) <= verticalTolerance) {
				xSpeed += yAvg * obj.xAcc;
				ySpeed -= xAvg * obj.xAcc;
			}
			float projection = xSpeed * xAvg + ySpeed * yAvg;
			if (projection > 0.f) {
				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 (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, SOUND::ROBOT_SHOOT);
				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.counter = obj.frameID = obj.freeze = 0;
						obj.isTarget = obj.triggersTNT = false;
						obj.light = 18;
						obj.lightType = LIGHT::BRIGHT;
						obj.playerHandling = HANDLING::EXPLOSION;
						jjSample(obj.xPos, obj.yPos, SOUND::AMMO_BOEM1);
					}
					obj.counter++;
					if (obj.counter & 7 == 0)
						obj.frameID++;
					obj.light--;
					if (obj.light < 2)
						obj.lightType = LIGHT::NONE;
					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 ? 13.f : 7.5f);
	}
	protected void behavePowered(::jjOBJ@ obj) const {
		behaveCommon(obj, 9, 0.6f, obj.yPos < ::jjWaterLevel ? 15.f : 8.5f);
	}
	protected void behaveSplit(::jjOBJ@ obj) const {
		int id = ::jjAddObject(obj.eventID, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType, BEHAVIOR::INACTIVE);
		::jjOBJ@ other = ::jjObjects[id];
		if (id > 0) {
			other.behavior = @::jjVOIDFUNCOBJ(behaveBasic);
			other.curAnim = obj.curAnim;
			other.direction = obj.direction;
			other.xSpeed = obj.xSpeed * 0.5f;
			other.ySpeed = obj.ySpeed * 0.5f;
			other.xAcc = obj.xAcc;
			other.yAcc = obj.yAcc;
			other.var[7] = obj.var[7];
			if (id < obj.objectID)
				other.behave();
		}
		obj.behavior = @::jjVOIDFUNCOBJ(behavePowered);
		obj.behave();
	}
	protected void behaveTNT(::jjOBJ@ obj) const {
		if (obj.creatorType == CREATOR::PLAYER && ::jjPlayers[obj.creatorID].powerup[WEAPON::TNT]) {
			obj.behavior = @::jjVOIDFUNCOBJ(behaveSplit);
			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(behaveSplit);
		}
		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 = powerup.killAnim = ::jjAnimSets[ANIM::AMMO] + 3;
		basic.lightType = powerup.lightType = LIGHT::POINT;
		basic.playerHandling = powerup.playerHandling = HANDLING::PLAYERBULLET;
		basic.var[0] = powerup.var[0] = 0;
		basic.var[3] = powerup.var[3] = number;
		basic.var[6] = 0;
		powerup.var[6] = 8;
		basic.xAcc = powerup.xAcc = 0.2f;
		basic.yAcc = powerup.yAcc = 0.25f;
		basic.xSpeed = powerup.xSpeed = 3.f;
		basic.ySpeed = powerup.ySpeed = 0.f;
	}
	protected void preparePickupPresets(::jjOBJ@ ammo3, ::jjOBJ@ ammo15, ::jjOBJ@ powerup) const {
		if (ammo3 !is null) {
			ammo3.behavior = @se::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, "Buzzsawer.j2a", 0);
		return @animSet;
	}
	::array<bool>@ loadSamples(const ::array<SOUND::Sample>& samples) override {
		return @::array<bool>(1, samples.length() == 1 && loadSample(samples[0], "sawgrind.wav"));
	}
	uint getSampleCount() const override {
		return 1;
	}
	uint getTraits(bool powerup) const override {
		return se::weapon_default_traits;
	}
	uint getMaxDamage(bool powerup) const override {
		return powerup ? 2 : 1;
	}
	bool setAsWeapon(uint number, se::WeaponHook@ weaponHook = null) override {
		if (m_animSet !is null && se::isValidWeapon(number)) {
			loadSample(SOUND::BUMBEE_BEELOOP, "sawgrind.wav");
			uint basic = se::getBasicBulletOfWeapon(number);
			uint powered = se::getPoweredBulletOfWeapon(number);
			uint ammo3 = se::getAmmoPickupOfWeapon(number);
			uint ammo15 = se::getAmmoCrateOfWeapon(number);
			uint powerup = se::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;
	}
}
BuzzsawWeapon buzzsaw;