Downloads containing SEminimirv.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 20 Levels Jazz2Online Multiple N/A Download file

File preview

#pragma require "SEweapon.asc"
#pragma require "SEminimirv.j2a"
#pragma offer "SEminimirv1.wav"
#pragma offer "SEminimirv2.wav"
#include "SEweapon.asc"
namespace se {
namespace detail {
	shared class MiniMirvData {
		private int m_objectID, m_warheadCount;
		private ::array<float> m_warheadXSpeed, m_warheadYSpeed;
		MiniMirvData(int id) {
			m_objectID = id;
			m_warheadCount = 0;
		}
		bool opEquals(const MiniMirvData@ other) const {
			return m_objectID == other.m_objectID;
		}
		bool isEmpty() const {
			return m_warheadCount == 0;
		}
		int get_objectID() const {
			return m_objectID;
		}
		int get_warheadCount() const {
			return m_warheadCount;
		}
		float get_xSpeed(int index) const {
			return m_warheadXSpeed[index];
		}
		float get_ySpeed(int index) const {
			return m_warheadYSpeed[index];
		}
		void clear() {
			m_warheadCount = 0;
			m_warheadXSpeed.resize(0);
			m_warheadYSpeed.resize(0);
		}
		void addWarhead(float xSpeed, float ySpeed) {
			m_warheadCount++;
			m_warheadXSpeed.insertLast(xSpeed);
			m_warheadYSpeed.insertLast(ySpeed);
		}
	}
	shared class MiniMirvPolynomial {
		private ::array<double> m_coefficients;
		MiniMirvPolynomial() {}
		MiniMirvPolynomial(const ::array<double> &in coefficients) {
			m_coefficients = coefficients;
		}
		double opCall(double x) const {
			double y = 0.0;
			for (int i = m_coefficients.length(); i-- != 0;) {
				y = y * x + m_coefficients[i];
			}
			return y;
		}
	}
}
shared class MiniMirvWeapon : WeaponInterface {
	private ::jjANIMSET@ m_animSet;
	private ::array<SOUND::Sample> m_samples = {SOUND::AMMO_MISSILE, SOUND::AMMO_BOEM1};
	private PacketConstructor@ m_packetConstructor;
	private ::array<se::detail::MiniMirvData@> m_data;
	protected ::jjANIMSET@ getAnimSet() const {
		return @m_animSet;
	}
	protected const array<SOUND::Sample>& getSamples() const {
		return m_samples;
	}
	protected PacketConstructor@ getPacketConstructor() const {
		return @m_packetConstructor;
	}
	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, int index) {
		if (::jjSampleLoad(sample, filename)) {
			m_samples[index] = sample;
			return true;
		}
		return false;
	}
	protected int getPlayerTeam(const ::jjPLAYER@ player) const {
		if (::jjGameMode == GAME::SP || ::jjGameMode == GAME::COOP)
			return 0;
		if (::jjGameMode == GAME::CTF)
			return player.team;
		if (::jjGameCustom == GAME::PEST)
			return player.isZombie ? 1 : 0;
		if (::jjGameCustom == GAME::RT) {
			if (player is ::jjTokenOwner)
				return 1;
			if (player is ::jjBottomFeeder)
				return 2;
			return 0;
		}
		return player.playerID;
	}
	protected void behaveExplosion(::jjOBJ@ obj) const {
		switch (obj.state) {
			case STATE::START:
				{
					float xAvg = 0.f, yAvg = 0.f;
					for (int i = 0; i < 1024; i += 16) {
						float cosine = ::jjCos(i);
						float sine = ::jjSin(i);
						float x = obj.xPos + cosine * 10.f;
						float y = obj.yPos + sine * 10.f;
						if (::jjMaskedPixel(int(x + 0.5f), int(y + 0.5f))) {
							xAvg += cosine;
							yAvg += sine;
						}
					}
					obj.special = int(::atan2(xAvg, yAvg) * 162.975f);
				}
				::jjSample(obj.xPos, obj.yPos, m_samples[1]);
				obj.state = STATE::EXPLODE;
				break;
			case STATE::EXPLODE:
				obj.counter++;
				if (obj.counter & 3 == 0) {
					obj.frameID++;
					if (obj.counter == 4 && (::jjIsServer || ::jjGameConnection == GAME::LOCAL)) {
						const int maxPlayers = 32;
						for (int i = 0; i < maxPlayers; i++) {
							::jjPLAYER@ player = @::jjPlayers[i];
							if (player.isInGame && !player.isJailed && obj.var[1] != getPlayerTeam(player)) {
								float x = player.xPos - obj.xPos;
								float y = player.yPos - obj.yPos;
								if (::abs(::jjCos(obj.special) * x + ::jjSin(obj.special) * y) < 280.f && x * x + y * y < 589824.f)
									player.hurt(5, true, obj.creatorType == CREATOR::PLAYER ? @::jjPlayers[obj.creatorID] : null);
							}
						}
					}
				}
				if (obj.frameID < int(::jjAnimations[obj.curAnim].frameCount)) {
					obj.determineCurFrame();
					::jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.special, 4.f, 4.f, SPRITE::TRANSLUCENTTILE);
				} else {
					obj.state = STATE::KILL;
				}
				break;
			case STATE::KILL:
			case STATE::DEACTIVATE:
				obj.delete();
				break;
		}
	}
	protected void explode(::jjOBJ@ obj) const {
		obj.state = STATE::KILL;
		int id = ::jjAddObject(obj.eventID, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType, @::jjVOIDFUNCOBJ(behaveExplosion));
		if (id != 0) {
			::jjOBJ@ explosion = @::jjObjects[id];
			explosion.animSpeed = obj.animSpeed;
			explosion.curAnim = obj.killAnim;
			explosion.curFrame = ::jjAnimations[explosion.curAnim];
			explosion.playerHandling = HANDLING::EXPLOSION;
			explosion.var[1] = obj.var[1];
		}
	}
	protected void draw(::jjOBJ@ obj) const {
		if (::jjGameTicks & 7 == 0) {
			obj.frameID++;
			if (obj.frameID >= int(::jjAnimations[obj.curAnim].frameCount))
				obj.frameID = 0;
		}
		obj.determineCurFrame();
		float dir = obj.xSpeed < 0.f ? -1.f : 1.f;
		int angle = int(::atan2(-obj.ySpeed, obj.xSpeed) * 162.975f);
		if (dir < 0.f)
			angle += 512;
		::jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, angle, dir);
	}
	protected void behaveWarhead(::jjOBJ@ obj) const {
		switch (obj.state) {
			case STATE::START:
				obj.state = STATE::FALL;
				break;
			case STATE::FALL:
				obj.xSpeed += obj.xAcc;
				obj.ySpeed += obj.yAcc;
				{
					float width = ::jjLayerWidth[4] << 5, height = ::jjLayerHeight[4] << 5;
					float xSpeed = ::abs(obj.xSpeed), ySpeed = ::abs(obj.ySpeed);
					float maxSpeed = xSpeed > ySpeed ? xSpeed : ySpeed;
					float steps = ::ceil(maxSpeed / 8.f);
					float xStep = obj.xSpeed / steps, yStep = obj.ySpeed / steps;
					for (int i = int(steps + 0.5f); i-- != 0;) {
						obj.xPos += xStep;
						obj.yPos += yStep;
						if (obj.yPos >= height || obj.xPos >= 0.f && obj.yPos >= 0.f && obj.xPos < width && ::jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
							obj.state = STATE::EXPLODE;
							break;
						}
					}
				}
				draw(obj);
				break;
			case STATE::EXPLODE:
				explode(obj);
				break;
			case STATE::KILL:
			case STATE::DEACTIVATE:
				obj.delete();
				break;
		}
	}
	protected float findReasonableArrivalTime(float xDist, float yDist, float xSpeed, float ySpeed, float yAcc) const {
		::array<double> coefficients = {
			xDist * xDist + yDist * yDist,
			-2.f * (xSpeed * xDist + ySpeed * yDist),
			-3.f * (xSpeed * xSpeed + ySpeed * ySpeed) - yDist * yAcc,
			ySpeed * yAcc,
			0.25f * yAcc * yAcc
		};
		se::detail::MiniMirvPolynomial f(coefficients);
		for (int i = 1; i < 5; i++) {
			coefficients[i] *= i;
		}
		coefficients.removeAt(0);
		se::detail::MiniMirvPolynomial df(coefficients);
		double left = 0.0, right = 20.0;
		double fl = f(left), fr = f(right);
		while (fl * fr >= 0.0) {
			left = right;
			fl = fr;
			right += 20.0;
			if (right > 420.0)
				return -1.f;
			fr = f(right);
		}
		double dfl = df(left), dfr = df(right);
		if (dfl * dfr > 0.0) {
			double x = (dfr - dfl) * dfl < 0.0 ? left : right;
			double fx = f(x);
			bool ok = true;
			for (int i = 40; !::closeTo(fx, 0.0, 1e-7); i--) {
				x -= fx / df(x);
				if (i == 0 || x < left || x > right) {
					ok = false;
					break;
				}
				fx = f(x);
			}
			if (ok)
				return float(x);
		}
		double x = (left + right) / 2.0;
		double fx = f(x);
		for (int i = 40; !::closeTo(fx, 0.0, 1e-7); i--) {
			if (fx * fl < 0.0) {
				right = x;
				fr = f(right);
			} else {
				left = x;
				fl = f(left);
			}
			if (i == 0)
				break;
			fx = f(x);
		}
		return float(x);
	}
	protected void predictPlayer(const ::jjPLAYER@ player, int time, float xAcc, float &out x, float &out y) const {
		x = player.xPos;
		y = player.yPos;
		float xSpeed = player.xSpeed, ySpeed = player.ySpeed;
		for (int i = 0; i < time; i++) {
			if (ySpeed < 0.f) {
				ySpeed += 0.25f;
			} else {
				ySpeed += 0.125f;
				if (ySpeed > 12.f)
					ySpeed = 12.f;
			}
			float effectiveYSpeed = ySpeed;
			if (effectiveYSpeed < -8.f)
				effectiveYSpeed = -8.f;
			y += effectiveYSpeed;
			if (ySpeed > 0.f) {
				if (::jjMaskedHLine(int(x) - 12, 24, int(y) + 20)) {
					while (::jjMaskedHLine(int(x) - 12, 24, int(y) + 19)) {
						y--;
					}
					ySpeed = 0.f;
				}
			} else {
				if (::jjMaskedHLine(int(x) - 12, 24, int(y) - 4)) {
					while (::jjMaskedHLine(int(x) - 12, 24, int(y) - 3)) {
						y++;
					}
					ySpeed = 0.f;
				}
			}
			xSpeed += xAcc;
			if (xSpeed > 16.f)
				xSpeed = 16.f;
			else if (xSpeed < -16.f)
				xSpeed = -16.f;
			float effectiveXSpeed = xSpeed;
			if (effectiveXSpeed > 8.f)
				effectiveXSpeed = 8.f;
			else if (effectiveXSpeed < -8.f)
				effectiveXSpeed = -8.f;
			x += effectiveXSpeed;
			if (xSpeed > 0.f) {
				int mask = 25 - ::jjMaskedTopVLine(int(x) + 12, int(y) - 4, 24);
				if (mask != 0) {
					if (mask - 1 < xSpeed) {
						y -= mask;
						ySpeed = 0.f;
					} else {
						xSpeed = 0.f;
					}
				}
			} else {
				int mask = 25 - ::jjMaskedTopVLine(int(x) - 12, int(y) - 4, 24);
				if (mask != 0) {
					if (mask - 1 < -xSpeed) {
						y -= mask;
						ySpeed = 0.f;
					} else {
						xSpeed = 0.f;
					}
				}
			}
		}
	}
	protected void selectTargets(const ::jjOBJ@ obj, se::detail::MiniMirvData@ data) const {
		if (::jjIsServer || ::jjGameConnection == GAME::LOCAL) {
			const int minWarheads = 3, maxWarheads = 5;
			const int maxPlayers = 32;
			float timeLeft = obj.state == STATE::ACTION ? 0.f : obj.counterEnd - obj.counter + 1;
			float xReal = obj.xPos + timeLeft * obj.xSpeed;
			float yReal = obj.yPos + timeLeft * obj.ySpeed - timeLeft * timeLeft * 0.0125f;
			float xSpeedReal = obj.xSpeed;
			float ySpeedReal = obj.ySpeed + timeLeft * obj.yAcc;
			float speed = ::sqrt(xSpeedReal * xSpeedReal + ySpeedReal * ySpeedReal) * 2.f;
			{
				::array<float> interest, times, targetsX, targetsY;
				int targetCount = 0;
				for (int i = 0; i < maxPlayers; i++) {
					const ::jjPLAYER@ target = @::jjPlayers[i];
					if (target.isInGame && !target.isJailed && obj.var[1] != getPlayerTeam(target)) {
						float thisInterest = 1.f;
						if (target.flag != 0 && ::jjObjects[target.flag].var[0] == target.playerID + 0x8000 || ::jjGameCustom == GAME::RT && target is ::jjTokenOwner)
							thisInterest = 5.f;
						if (::jjGameMode == GAME::TREASURE || ::jjGameCustom == GAME::HEAD)
							thisInterest += target.gems[GEM::RED];
						if (target.lrsLives >= 0)
							thisInterest += ::sqrt(float(target.lrsLives));
						else if (target.deaths >= 0)
							thisInterest += 1.f / (target.deaths + 1);
						bool inMovement = !::closeTo(target.xSpeed, 0.f, 0.01f);
						float xAcc = inMovement ? 375.f / 1024.f : 0.f;
						for (int j = inMovement ? 2 : 1; j-- != 0; xAcc = -xAcc) {
							float xPos, yPos;
							float time = timeLeft, prevTime = -128.f;
							for (int k = 20; k != 0 && time >= 0.f && !::closeTo(time, prevTime, 1.f); k--) {
								predictPlayer(@target, int(time), xAcc, xPos, yPos);
								yPos += 20.f;
								prevTime = time;
								time = findReasonableArrivalTime(xPos - xReal, yPos - yReal, xSpeedReal, ySpeedReal, obj.yAcc);
							}
							if (time > 0.f) {
								interest.insertLast(thisInterest / time);
								times.insertLast(time);
								targetsX.insertLast(xPos);
								targetsY.insertLast(yPos);
								targetCount++;
							}
						}
					}
				}
				while (targetCount > 0 && data.warheadCount < maxWarheads) {
					float maxInterest = interest[0];
					int targetID = 0;
					for (int i = 1; i < targetCount; i++) {
						if (interest[i] > maxInterest)
							targetID = i;
					}
					float xPos = targetsX[targetID];
					float yPos = targetsY[targetID];
					float xSpeed = (xPos - xReal) / times[targetID];
					float ySpeed = (yPos - yReal) / times[targetID] - obj.yAcc * times[targetID] / 2.f;
					data.addWarhead(xSpeed, ySpeed);
					interest.removeAt(targetID);
					times.removeAt(targetID);
					targetsX.removeAt(targetID);
					targetsY.removeAt(targetID);
					targetCount--;
				}
			}
			if (data.warheadCount < maxWarheads) {
				::array<float> interest, times;
				::array<const ::jjOBJ@> potentialTargets;
				int targetCount = 0;
				for (int i = 0; i < ::jjObjectCount; i++) {
					const ::jjOBJ@ target = @::jjObjects[i];
					if (target.isActive && target.isTarget) {
						float time = findReasonableArrivalTime(target.xPos - xReal, target.yPos - yReal, xSpeedReal, ySpeedReal, obj.yAcc);
						if (time > 0.f) {
							interest.insertLast((target.points + 100) / time);
							times.insertLast(time);
							potentialTargets.insertLast(@target);
							targetCount++;
						}
					}
				}
				while (targetCount > 0 && data.warheadCount < maxWarheads) {
					float maxInterest = interest[0];
					int targetID = 0;
					for (int i = 1; i < targetCount; i++) {
						if (interest[i] > maxInterest)
							targetID = i;
					}
					const ::jjOBJ@ target = potentialTargets[targetID];
					float xSpeed = (target.xPos - xReal) / times[targetID];
					float ySpeed = (target.yPos - yReal) / times[targetID] - obj.yAcc * times[targetID] / 2.f;
					data.addWarhead(xSpeed, ySpeed);
					interest.removeAt(targetID);
					times.removeAt(targetID);
					potentialTargets.removeAt(targetID);
					targetCount--;
				}
			}
			while (data.warheadCount < minWarheads) {
				float angle = ::jjRandom() * 6.28318531f / 0x100000000;
				data.addWarhead(xSpeedReal + ::sin(angle) * speed, ySpeedReal + ::cos(angle) * speed);
			}
			if (::jjIsServer) {
				::jjSTREAM packet = m_packetConstructor();
				packet.push(uint8(obj.creatorID));
				packet.push(uint8(data.warheadCount));
				for (int i = 0; i < data.warheadCount; i++) {
					packet.push(float(data.xSpeed[i]));
					packet.push(float(data.ySpeed[i]));
				}
				::jjSendPacket(packet);
			}
		}
	}
	protected void detach(::jjOBJ@ obj, const se::detail::MiniMirvData@ data) const {
		obj.state = STATE::KILL;
		int damage = data.warheadCount == 0 ? 0 : obj.animSpeed / data.warheadCount;
		for (int i = 0; i < data.warheadCount; i++) {
			int id = ::jjAddObject(obj.eventID, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType, @::jjVOIDFUNCOBJ(behaveWarhead));
			if (id != 0) {
				::jjOBJ@ warhead = @::jjObjects[id];
				warhead.animSpeed = damage;
				warhead.curAnim = warhead.special = obj.curAnim + 1;
				warhead.curFrame = ::jjAnimations[warhead.curAnim];
				warhead.killAnim = obj.killAnim;
				warhead.var[1] = obj.var[1];
				warhead.xAcc = 0.f;
				warhead.yAcc = obj.yAcc;
				warhead.xSpeed = data.xSpeed[i];
				warhead.ySpeed = data.ySpeed[i];
			}
		}
	}
	protected void behave(::jjOBJ@ obj) {
		se::detail::MiniMirvData tempData(obj.objectID);
		int dataID = m_data.find(@tempData);
		if (dataID == -1) {
			dataID = m_data.length();
			m_data.insertLast(@tempData);
		}
		switch (obj.state) {
			case STATE::START:
				m_data[dataID].clear();
				if (obj.creatorType == CREATOR::PLAYER) {
					obj.var[1] = getPlayerTeam(@::jjPlayers[obj.creatorID]);
					if (::jjGameMode == GAME::CTF)
						obj.curAnim += (obj.var[1] + 1) << 1;
					if (::jjPlayers[obj.creatorID].isLocal)
						::jjSample(obj.xPos, obj.yPos, m_samples[0]);
				} else {
					obj.var[1] = -1;
				}
				obj.xAcc = 0.f;
				obj.yAcc = ::jjObjectPresets[obj.eventID].yAcc;
				obj.state = STATE::ROCKETFLY;
			case STATE::ROCKETFLY:
				obj.xPos += obj.xSpeed;
				obj.yPos += obj.ySpeed -= 0.025f;
				obj.counter++;
				if (::jjMaskedPixel(int(obj.xPos), int(obj.yPos)))
					obj.state = STATE::EXPLODE;
				else if (obj.counter > int(obj.counterEnd))
					obj.state = STATE::ACTION;
				else if (obj.counter > int(obj.counterEnd) - 35 && m_data[dataID].isEmpty())
					selectTargets(obj, @m_data[dataID]);
				draw(obj);
				break;
			case STATE::ACTION:
				if (m_data[dataID].isEmpty())
					selectTargets(obj, @m_data[dataID]);
				else
					detach(obj, @m_data[dataID]);
				obj.counter--;
				if (obj.counter < 0)
					obj.state = STATE::KILL;
				draw(obj);
				break;
			case STATE::EXPLODE:
				explode(obj);
				break;
			case STATE::KILL:
			case STATE::DEACTIVATE:
				m_data.removeAt(dataID);
				obj.delete();
				break;
		}
	}
	protected void prepareWeaponProfile(::jjWEAPON@ weapon) const {
		weapon.comesFromGunCrates = false;
		weapon.defaultSample = false;
		weapon.gradualAim = false;
		weapon.maximum = 1;
		weapon.multiplier = 1;
		weapon.replacedByBubbles = false;
		weapon.spread = SPREAD::NORMAL;
		weapon.style = WEAPON::MISSILE;
	}
	protected void prepareBulletPreset(::jjOBJ@ preset, uint number) const {
		preset.behavior = @::jjVOIDFUNCOBJ(behave);
		preset.animSpeed = 50;
		preset.counterEnd = 140;
		preset.curAnim = preset.special = m_animSet + 2;
		preset.curFrame = ::jjAnimations[preset.curAnim];
		preset.deactivates = false;
		preset.direction = 1;
		preset.energy = preset.freeze = 0;
		preset.frameID = 0;
		preset.killAnim = m_animSet + 1;
		preset.lightType = LIGHT::POINT;
		preset.playerHandling = HANDLING::PARTICLE;
		preset.var[3] = number;
		preset.var[6] = 24;
		preset.xAcc = 0.f;
		preset.yAcc = 0.125f;
		preset.xSpeed = 11.f;
		preset.ySpeed = 0.f;
	}
	protected void preparePickupPreset(::jjOBJ@ preset, uint number) const {
		preset.behavior = @AmmoPickup(::jjAnimations[m_animSet], ::jjAnimations[m_animSet], 1);
		preset.curAnim = m_animSet;
		preset.direction = 1;
		preset.energy = 0;
		preset.frameID = 0;
		preset.killAnim = ::jjAnimSets[ANIM::PICKUPS] + 86;
		preset.playerHandling = HANDLING::PICKUP;
		preset.points = 1000;
		preset.var[2] = 0;
		preset.var[3] = number - 1;
		preset.determineCurFrame();
	}
	protected void processPacket(::jjSTREAM& packet, int) const {
		if (!::jjIsServer) {
			uint8 creatorID, warheadCount;
			if (packet.pop(creatorID) && packet.pop(warheadCount)) {
				int dataID = -1, maxCounter = -1;
				for (int i = m_data.length(); i-- != 0;) {
					const ::jjOBJ@ obj = @::jjObjects[m_data[i].objectID];
					if (m_data[i].isEmpty() && obj.isActive && obj.creatorID == creatorID && obj.counter > maxCounter) {
						maxCounter = obj.counter;
						dataID = i;
					}
				}
				if (dataID != -1) {
					while (warheadCount-- != 0) {
						float xSpeed, ySpeed;
						if (packet.pop(xSpeed) && packet.pop(ySpeed))
							m_data[dataID].addWarhead(xSpeed, ySpeed);
					}
				}
			}
		}
	}
	::jjANIMSET@ loadAnims(::jjANIMSET@ animSet) override {
		loadAnimSet(animSet, "SEminimirv.j2a", 0);
		return @animSet;
	}
	::array<bool>@ loadSamples(const ::array<SOUND::Sample>& samples) override {
		if (samples.length() != 2)
			return @::array<bool>(2, false);
		::array<bool> result = {loadSample(samples[0], "SEminimirv1.wav", 0), loadSample(samples[1], "SEminimirv2.wav", 1)};
		return @result;
	}
	uint getSampleCount() const override {
		return 1;
	}
	uint getTraits(bool) const override {
		return weapon_deals_damage | weapon_causes_splash_damage | weapon_is_super_weapon | weapon_is_effective_against_all_targets | weapon_works_in_all_modes | weapon_has_ammo_pickups;
	}
	uint getMaxDamage(bool) const override {
		return 5;
	}
	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]);
				@m_packetConstructor = @weaponHook.addPacketCallback(@PacketCallback(processPacket));
			}
			prepareWeaponProfile(@::jjWeapons[number]);
			prepareBulletPreset(@::jjObjectPresets[basic], number);
			if (basic != powered)
				prepareBulletPreset(@::jjObjectPresets[powered], number);
			if (ammo3 != 0)
				preparePickupPreset(@::jjObjectPresets[ammo3], number);
			if (ammo15 != 0)
				preparePickupPreset(@::jjObjectPresets[ammo15], number);
			preparePickupPreset(@::jjObjectPresets[powerup], number);
			return true;
		}
		return false;
	}
}
MiniMirvWeapon miniMirv;
}