Downloads containing salchaos.mut

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Chaos V1.1Featured Download sAlAmAnDeR Mutator 8.5 Download file

File preview

#pragma name "||C|H|A||O|S|"
#pragma require "SEpalwiz-1.1.asc"

#include "SEpalwiz-1.1.asc"

const bool DEBUG = false;

const uint SECOND = 70;
const uint TIMER_MAX = 15*SECOND;
const uint TIMER_MIN = 3*SECOND;
const uint TIMER_DECREMENT = .5*SECOND;
const uint TARGET_EVERYONE = 100;
const int TARGET_NOONE = -1;

int timerCurStart = TIMER_MAX;
uint time = timerCurStart;

se::colorEffect@ paletteEffect;
int paletteEffectTimer = -1;
bool psychadelic = false;
int freezeTimer = -1;
int freezeTarget = -1;
int antiGravTimer = -1;
int antiGravTarget = -1;
int animalTimer = -1;
int animalTarget = -1;
int canRunTimer = -1;
int noFireTimer = -1;
int noFireTarget = -1;
int waterTimer = -1;
int invisibleTimer = -1;
int invisibleTarget = -1;
int jumpTypesTimer = -1;
int jumpTypesTarget = -1;
int tunnelVisionTimer = -1;

enum PACKET_TYPE {
	TIMER_UPDATE,
	EVENT,
	JOIN
}

enum PALETTE_EFFECT {
	SEPIA,
	GREYSCALE,
	SMOG,
	SKETCH
}

enum EVENT_TYPE {
	FREEZE,
	SUGAR,
	ROAST,
	HEAL,
	POWERUP,
	LOSEAMMO,
	ONEHEALTH,
	GAINAMMO,
	ANTIGRAV,
	MORPH,
	WEATHER,
	SHIELD,
	NOFIRE,
	PSYCHADELIC,
	INVISIBILITY,
	HFK,
	MAXHEALTH,
	STONED,
	FRIENDLYFIRE,
	SCRAMBLE_SPREADS,
	WATER,
	JUMP_STRENGTH,
	CANRUN,
	SCRAMBLE_JUMPTYPES,
	NOBLINK,
	FROG,
	BIRD,
	JUMPHEIGHT,
	PALETTE_EFFECT,
	TEXTURE,
	SWAP_POSITIONS,
	TUNNELVISION,
	SPAWN_ENEMIES,
}

const array<EVENT_TYPE> positiveEffects = { EVENT_TYPE::SUGAR, 
											EVENT_TYPE::HEAL,
										    EVENT_TYPE::POWERUP,
											EVENT_TYPE::GAINAMMO,
											//EVENT_TYPE::SHIELD, //Disabled due to banning people
											EVENT_TYPE::JUMP_STRENGTH,
											EVENT_TYPE::INVISIBILITY};
											
const array<EVENT_TYPE> negativeEffects = {   EVENT_TYPE::FREEZE,
											  EVENT_TYPE::LOSEAMMO,
											  EVENT_TYPE::ONEHEALTH,
											  EVENT_TYPE::ANTIGRAV,
											  EVENT_TYPE::MORPH,
											  EVENT_TYPE::SCRAMBLE_SPREADS,
											  EVENT_TYPE::STONED,
											  EVENT_TYPE::FROG,
											  EVENT_TYPE::BIRD,
											  EVENT_TYPE::CANRUN,
											  EVENT_TYPE::NOFIRE,
											  EVENT_TYPE::WATER,
											  EVENT_TYPE::SCRAMBLE_JUMPTYPES,
											  EVENT_TYPE::TUNNELVISION};

const array<EVENT_TYPE> neutralEffects = { EVENT_TYPE::HFK,
										   EVENT_TYPE::MAXHEALTH,
										   EVENT_TYPE::PSYCHADELIC,
										   EVENT_TYPE::PALETTE_EFFECT,
										   //EVENT_TYPE::TEXTURE, //Disabled due to crashing servers with small layer 8
										   EVENT_TYPE::WEATHER,
										   EVENT_TYPE::NOBLINK,
										   EVENT_TYPE::FRIENDLYFIRE};

array<EVENT_TYPE> allEffects;

int randomRange(int min, int max) {return min + jjRandom() % (max - min + 1);}
int clamp(int min, int val, int max) {return val < min ? min : (val > max ? max : val);}
float linear(float time, float start, float end, float duration) {return ((end-start)/duration)*time + start;}
string chr(uint8 value) {string str="\0";str[0]=value;return str;}

array<EVENT_TYPE> addAll(array<EVENT_TYPE>& a1, array<EVENT_TYPE>& a2) {
	for(uint i = 0; i < a2.length; i++)
		a1.insertLast(a2[i]);
	return a1;
}

void sendTimerUpdate(uint time, int clientID) {
	if(DEBUG) jjDebug("SENDING TIMER UPDATE PACKET. TIME=" + time);
	jjSTREAM stream;
	stream.push(PACKET_TYPE::TIMER_UPDATE);
	stream.push(time);
	jjSendPacket(stream, clientID);
}

int generateRandomActivePlayer() {
	array<int> possiblePlayers;
	for(uint i = 0; i < 32; i++)
		if(jjPlayers[i].isInGame)
			possiblePlayers.insertLast(i);
	if(possiblePlayers.length == 0) 
		return TARGET_NOONE;
	uint playerIndex = possiblePlayers[jjRandom() % possiblePlayers.length];
	return playerIndex;
}

TEAM::Color generateRandomTeam() {
	array<TEAM::Color> enabledTeams;
	const array<TEAM::Color> possibleColors = {TEAM::RED, TEAM::BLUE, TEAM::YELLOW, TEAM::GREEN};
	for(uint i = 0; i < possibleColors.length; i++)
		if(jjEnabledTeams[possibleColors[i]])
			enabledTeams.insertLast(possibleColors[i]);
	return enabledTeams[jjRandom() % enabledTeams.length()];
}

TEXTURE::Style generateRandomTexture() {
	const array<TEXTURE::Style> possibleStyles = {TEXTURE::WARPHORIZON, TEXTURE::TUNNEL, /*TEXTURE::MENU,*/ TEXTURE::TILEMENU};
	return possibleStyles[jjRandom() % possibleStyles.length()];
}

class EventData {
	int target;
	EVENT_TYPE event;

	EventData(EVENT_TYPE event, int target) {
		this.event = event;
		this.target = target;
	}
}

EVENT_TYPE generateEvent(array<EVENT_TYPE> possibilities) {
	if(possibilities.length() == 0)
		if(DEBUG) jjDebug("GENERATE EVENT CALLED, NO POSSIBILITIES");
	return possibilities[jjRandom() % possibilities.length()];
}

jjSTREAM initEventPacket(EVENT_TYPE event) {
	jjSTREAM stream;
	stream.push(PACKET_TYPE::EVENT);
	stream.push(event);
	return stream;
}

int setEventTarget(EVENT_TYPE event, jjSTREAM& stream) {
	int target;
	if(event == EVENT_TYPE::PSYCHADELIC || 
	   event == EVENT_TYPE::PALETTE_EFFECT ||
	   event == EVENT_TYPE::WEATHER ||
	   event == EVENT_TYPE::TEXTURE)
		target = TARGET_EVERYONE;
	else if(jjGameMode == GAME::CTF)
		target = generateRandomTeam();
	else
		target = generateRandomActivePlayer();
	stream.push(target);
	return target;
}

void sendEventPacket(jjSTREAM stream, int target) {
	if(DEBUG) jjDebug("SENDING EVENT PACKET");
	if(target == TARGET_EVERYONE) {
			jjSendPacket(stream, 0);
			onReceive(stream,0);
	} else if(jjGameMode == GAME::CTF) {
		for(uint i = 0; i < 32; i++)
			if(jjPlayers[i].isActive && jjPlayers[i].team == target)
				jjSendPacket(stream, jjPlayers[i].clientID);
		if(jjPlayers[0].team == target)
			onReceive(stream,0);
	} else {
		if(target == 0)
			onReceive(stream,0);
		else
			jjSendPacket(stream, jjPlayers[target].clientID);
	}
}

string stringifyEventTarget(int target) {
	if(jjGameMode == GAME::CTF) {
		if(target == TEAM::BLUE)         return "|||||BLUE TEAM";
		else if(target == TEAM::RED)     return "||||RED TEAM";
		else if(target == TEAM::YELLOW)  return "||||||YELLOW TEAM";
		else 						     return "|||GREEN TEAM";
	} else 
		return jjPlayers[target].name;
}

string stringifyWeapon(uint weapon) {
	if(weapon == 1) return "BLASTER";
	else if(weapon == 2) return "BOUNCER";
	else if(weapon == 3) return "ICE";
	else if(weapon == 4) return "SEEKER";
	else if(weapon == 5) return "RF";
	else if(weapon == 6) return "TOASTER";
	else if(weapon == 7) return "TNT";
	else if(weapon == 8) {
		if(jjAllowsFireball) return "FIREBALL";
		else return "PEPPERSPRAY";
	} else if(weapon == 9) return "ELECTROBLASTER";
	else return "UNKNOWN WEAPON";
}

void generateEffect(array<EVENT_TYPE> possibleEffects) {
	EVENT_TYPE event = generateEvent(possibleEffects);
	jjSTREAM stream = initEventPacket(event);
	int target = setEventTarget(event, stream);
	if(target == TARGET_NOONE) {
		if(DEBUG) jjDebug("FAILED TO FIND A TARGET");
		return;
	}
	string targetString = stringifyEventTarget(target);
	//POSITIVE
	if(event == EVENT_TYPE::SUGAR)   		sendMessage(targetString + " receives a SUGAR RUSH");
	else if(event == EVENT_TYPE::HEAL)      sendMessage(targetString + " is FULLY HEALED");
	else if(event == EVENT_TYPE::SHIELD)	sendMessage(targetString + " gets a random SHIELD");
	else if(event == EVENT_TYPE::GAINAMMO) {
		sendMessage(targetString + " gains ALL AMMO");
	}
	else if(event == EVENT_TYPE::POWERUP) {
		uint weapon = 1 + (jjRandom() % 9);
		stream.push(weapon);
		sendMessage(targetString + " receives a " + stringifyWeapon(weapon) + " POWER UP");
	}
	else if(event == EVENT_TYPE::JUMP_STRENGTH)     sendMessage(targetString + "\'s JUMP STRENGTH changes");
	else if(event == EVENT_TYPE::INVISIBILITY)		sendMessage(targetString + " is INVISIBILE");
	//NEGATIVE
	else if(event == EVENT_TYPE::FREEZE)     		sendMessage(targetString + " is FROZEN");
	else if(event == EVENT_TYPE::ROAST)      		sendMessage(targetString + " is ROASTED");
	else if(event == EVENT_TYPE::LOSEAMMO)   		sendMessage(targetString + " loses ALL AMMO");
	else if(event == EVENT_TYPE::ONEHEALTH)  		sendMessage(targetString + "\'s health is now ONE");
	else if(event == EVENT_TYPE::ANTIGRAV)   		sendMessage(targetString + " receives ANTIGRAV");
	else if(event == EVENT_TYPE::SCRAMBLE_SPREADS)  sendMessage(targetString + "\'s spreads are SCRAMBLED");
	else if(event == EVENT_TYPE::MORPH) 			sendMessage(targetString + " MORPHED");
	else if(event == EVENT_TYPE::STONED) 			sendMessage(targetString + " is STONED");
	else if(event == EVENT_TYPE::FROG) 				sendMessage(targetString + " turns into a FROG");
	else if(event == EVENT_TYPE::BIRD) 				sendMessage(targetString + " turns into a BIRD");
	else if(event == EVENT_TYPE::CANRUN)			sendMessage(targetString + " can't RUN");
	else if(event == EVENT_TYPE::NOFIRE)			sendMessage(targetString + " can't FIRE");
	else if(event == EVENT_TYPE::WATER)				sendMessage(targetString + " is SWIMMING");
	else if(event == EVENT_TYPE::SCRAMBLE_JUMPTYPES)sendMessage(targetString + "\'s jumps are SWITCHED");
	else if(event == EVENT_TYPE::TUNNELVISION)      sendMessage(targetString + " has TUNNEL VISION");
	//NEUTRAL
	else if(event == EVENT_TYPE::HFK) { 
		bool enabled = jjRandom() % 2 == 0 ? true : false;
		sendMessage("HFK is " + (enabled ? "enabled" : "disabled"));
		if(enabled) jjChat("/hfk on");
		else jjChat("/hfk off");
	} else if(event == EVENT_TYPE::MAXHEALTH) {
		int health = 1 + jjRandom() % 6;
		jjChat("/maxhealth " + health);
		sendMessage("MAXHEALTH is now " + health);
	} else if(event == EVENT_TYPE::PSYCHADELIC) {
		sendMessage("|P|S|Y|C|H|E|D|E|L|I|C");
	} else if(event == EVENT_TYPE::PALETTE_EFFECT) {
		PALETTE_EFFECT effect = generateRandomPaletteEffect();
		stream.push(effect);
		sendMessage(stringifyPaletteEffect(effect));
	}  else if(event == EVENT_TYPE::TEXTURE) {
		TEXTURE::Style style = generateRandomTexture();
		stream.push(style);
		sendMessage(stringifyTexture(style) + " BACKGROUND");
	} else if(event == EVENT_TYPE::WEATHER) {
		SNOWING::Type snowType = generateRandomWeatherType();
		stream.push(snowType);
		sendMessage(stringifyWeatherType(snowType));
	} else if(event == EVENT_TYPE::NOBLINK) {
		bool enabled = !jjNoBlink;
		sendMessage("NOBLINK is " + (enabled ? "enabled" : "disabled"));
		if(enabled) jjChat("/noblink on");
		else jjChat("/noblink off");
	} else if(event == EVENT_TYPE::NOBLINK) {
		bool enabled = !jjFriendlyFire;
		sendMessage("FRIENDLY FIRE is " + (enabled ? "enabled" : "disabled"));
		if(enabled) jjChat("/friendlyfire on");
		else jjChat("/friendlyfire off");
	}
	
	sendEventPacket(stream, target);
}

void onReceive(jjSTREAM& stream, int clientID) {
	int type;
	stream.pop(type);
	if(type == PACKET_TYPE::TIMER_UPDATE) {
		if(DEBUG) jjDebug("RECEIVED TIMER UPDATE PACKET. TIME="+ time);
		stream.pop(time);
	} else if(type == PACKET_TYPE::JOIN) {
		if(DEBUG) jjDebug("RECEIVED JOIN PACKET");
		if(jjIsServer) sendTimerUpdate(time, clientID);
	} else if(type == PACKET_TYPE::EVENT) {
		if(DEBUG) jjDebug("RECEIVED EVENT PACKET");
		int event;
		int target;
		stream.pop(event);
		stream.pop(target);
		if(event == EVENT_TYPE::ROAST) {
			if(DEBUG) jjDebug("EVENT_TYPE=ROAST");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].kill();
		} else if(event == EVENT_TYPE::SUGAR) {
			if(DEBUG) jjDebug("EVENT_TYPE=SUGAR RUSH");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].startSugarRush();
		} else if(event == EVENT_TYPE::LOSEAMMO) {
			if(DEBUG) jjDebug("EVENT_TYPE=LOSE AMMO");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++) {
				for(uint j = 1; j <= 9; j++) {
					affectedPlayers[i].ammo[j] = 0;
					affectedPlayers[i].powerup[j] = false;
				}
				affectedPlayers[i].currWeapon = WEAPON::BLASTER;
			}
		} else if(event == EVENT_TYPE::ONEHEALTH) {
			if(DEBUG) jjDebug("EVENT_TYPE=ONE HEALTH");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].health = 1;
		} else if(event == EVENT_TYPE::FREEZE) {
			if(DEBUG) jjDebug("EVENT_TYPE=FREEZE");
			freezeTarget = target;
			freezeTimer = 10*SECOND;
		} else if(event == EVENT_TYPE::POWERUP) {
			if(DEBUG) jjDebug("EVENT_TYPE=POWERUP");
			uint weapon;
			stream.pop(weapon);
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++) {
				affectedPlayers[i].powerup[weapon] = true;
				affectedPlayers[i].currWeapon = weapon;
				affectedPlayers[i].ammo[weapon] = jjWeapons[weapon].maximum;
			}
		} else if(event == EVENT_TYPE::HEAL) {
			if(DEBUG) jjDebug("EVENT_TYPE=HEAL");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].health = jjMaxHealth;
		} else if(event == EVENT_TYPE::ANTIGRAV) {
			if(DEBUG) jjDebug("EVENT_TYPE=ANTIGRAV");
			antiGravTarget = target;
			antiGravTimer = 15*SECOND;
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].antiGrav = true;
		} else if(event == EVENT_TYPE::SCRAMBLE_SPREADS) {
			if(DEBUG) jjDebug("EVENT_TYPE=SCRAMBLE_SPREADS");
			for(uint i = 1; i <= 9; i++)
				jjWeapons[i].spread = generateRandomSpread();
		} else if(event == EVENT_TYPE::MORPH) {
			if(DEBUG) jjDebug("EVENT_TYPE=MORPH");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].morphTo(generateRandomRabbit(affectedPlayers[i].charCurr));
		} else if(event == EVENT_TYPE::STONED) {
			if(DEBUG) jjDebug("EVENT_TYPE=STONED");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].stoned = 10*SECOND;
		} else if(event == EVENT_TYPE::FROG) {
			if(DEBUG) jjDebug("EVENT_TYPE=FROG");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].morphTo(CHAR::FROG);
			animalTarget = target;
			animalTimer = 20*SECOND;
		} else if(event == EVENT_TYPE::BIRD) {
			if(DEBUG) jjDebug("EVENT_TYPE=BIRD");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++)
				affectedPlayers[i].morphTo(generateRandomBird());
			animalTarget = target;
			animalTimer = 20*SECOND;
		} else if(event == EVENT_TYPE::GAINAMMO) {
			if(DEBUG) jjDebug("EVENT_TYPE=GAIN AMMO");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++) {
				for(uint j = 1; j <= 9; j++)
					affectedPlayers[i].ammo[j] = jjWeapons[j].maximum;
			}
		} else if(event == EVENT_TYPE::PSYCHADELIC) {
			if(DEBUG) jjDebug("EVENT_TYPE=PSYCHADELIC");
			psychadelic=true;
			paletteEffectTimer = 15*SECOND;
		} else if(event == EVENT_TYPE::SEPIA) {
			if(DEBUG) jjDebug("EVENT_TYPE=SEPIA");
			psychadelic = false;
			jjBackupPalette.apply();
			if(jjLocalPlayers[0].isInGame) {
				@paletteEffect = @se::colorSepia();
				applyColorEffect(paletteEffect);
			}
		} else if(event == EVENT_TYPE::PALETTE_EFFECT) {
			if(DEBUG) jjDebug("EVENT_TYPE=PALETTE_EFFECT");
			psychadelic = false;
			jjBackupPalette.apply();
			int effect;
			stream.pop(effect);
			if(jjLocalPlayers[0].isInGame) {
				@paletteEffect = getPaletteEffect(PALETTE_EFFECT(effect));
				paletteEffectTimer = 20*SECOND;
				applyColorEffect(paletteEffect);
			}
		} else if(event == EVENT_TYPE::TEXTURE) {
			if(DEBUG) jjDebug("EVENT_TYPE=TEXTURE");
			if(jjLocalPlayers[0].isInGame) {
				int style;
				stream.pop(style);
				jjTexturedBGStyle = TEXTURE::Style(style);
				jjTexturedBGUsed = true;
				jjTexturedBGStars = false;
			}
		} else if(event == EVENT_TYPE::SHIELD) {
			if(DEBUG) jjDebug("EVENT_TYPE=SHIELD");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++) {
				affectedPlayers[i].shieldTime = 10*SECOND;
				affectedPlayers[i].shieldType = generateRandomShield();
			}
		} else if(event == EVENT_TYPE::CANRUN) {
			if(DEBUG) jjDebug("EVENT_TYPE=CANRUN");
			if(jjLocalPlayers[0].isInGame) {
				canRun(false);
				canRunTimer = 20*SECOND;
			}
		} else if(event == EVENT_TYPE::NOFIRE) {
			if(DEBUG) jjDebug("EVENT_TYPE=NOFIRE");
			if(jjLocalPlayers[0].isInGame) {
				noFireTarget = target;
				noFireTimer = 20*SECOND;
				array<jjPLAYER@> affectedPlayers = getAffectedPlayers(noFireTarget);
				for(uint i = 0; i < affectedPlayers.length; i++) {
					affectedPlayers[i].noFire = true;
				}
			}
		} else if(event == EVENT_TYPE::WEATHER) {
			if(DEBUG) jjDebug("EVENT_TYPE=WEATHER");
			if(jjLocalPlayers[0].isInGame) {
				jjIsSnowing = true;
				int snowType;
				stream.pop(snowType);
				jjSnowingType = SNOWING::Type(snowType);
			}
		} else if(event == EVENT_TYPE::WATER) {
			if(DEBUG) jjDebug("EVENT_TYPE=WATER");
			if(jjLocalPlayers[0].isInGame) {
				jjSetWaterLevel(0,true);
				waterTimer = 1*SECOND;
			}
		} else if(event == EVENT_TYPE::JUMP_STRENGTH) {
			if(DEBUG) jjDebug("EVENT_TYPE=JUMP_STRENGTH");
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(target);
			for(uint i = 0; i < affectedPlayers.length; i++) {
				affectedPlayers[i].jumpStrength = -(jjRandom() % 40 + 10);
			}
		} else if(event == EVENT_TYPE::INVISIBILITY) {
			if(DEBUG) jjDebug("EVENT_TYPE=INVISIBILITY");
			invisibleTimer = 30*SECOND;
			invisibleTarget = target;
			array<jjPLAYER@> affectedPlayers = getAffectedPlayers(invisibleTarget);
			for(uint i = 0; i < affectedPlayers.length; i++) {
				affectedPlayers[i].invisibility = true;
			}
		} else if(event == EVENT_TYPE::SCRAMBLE_JUMPTYPES) {
			if(DEBUG) jjDebug("EVENT_TYPE=SCRAMBLE_JUMPTYPES");
			jumpTypesTimer = 30*SECOND;
			scrambleJumpTypes();
		} else if(event == EVENT_TYPE::TUNNELVISION) {
			if(DEBUG) jjDebug("EVENT_TYPE=TUNNELVISION");
			if(jjLocalPlayers[0].isInGame) {
				tunnelVisionTimer = 30*SECOND;
			}
		}
	}
}

array<jjPLAYER@> getAffectedPlayers(int target) {
	array<jjPLAYER@> players;
	if(jjGameMode == GAME::CTF) {
		for(int i = 0; i < jjLocalPlayerCount; i++) 
			if(jjLocalPlayers[i].team == target && jjLocalPlayers[i].isInGame)
				players.insertLast(jjLocalPlayers[i]);
	} else {
		//Assumes target refers to a local player
		if(jjPlayers[target].isInGame)
			players.insertLast(jjPlayers[target]);
	}
	return players;
}

SNOWING::Type generateRandomWeatherType() {
	const array<SNOWING::Type> possibleSnow = {SNOWING::SNOW, SNOWING::FLOWER, SNOWING::RAIN, SNOWING::LEAF};
	return possibleSnow[jjRandom() % possibleSnow.length()];
}

string stringifyWeatherType(SNOWING::Type snowType) {
	if(snowType == SNOWING::SNOW) return "SNOW";
	if(snowType == SNOWING::FLOWER) return "FLOWERFALL";
	if(snowType == SNOWING::RAIN) return "RAIN";
	if(snowType == SNOWING::LEAF) return "LEAVES";
	return "UNKNOWN WEATHER TYPE";
}

string stringifyTexture(TEXTURE::Style style) {
	if(style == TEXTURE::TUNNEL) return "TUNNEL";
	if(style == TEXTURE::WARPHORIZON) return "WARPHORIZON";
	if(style == TEXTURE::TILEMENU) return "TILEMENU";
	if(style == TEXTURE::MENU) return "MENU";
	return "UNKNOWN";
}

SHIELD::Shield generateRandomShield() {
	array<SHIELD::Shield> possibleShields = {SHIELD::FIRE, SHIELD::BUBBLE, SHIELD::PLASMA};
	return possibleShields[jjRandom() % possibleShields.length()];
}

PALETTE_EFFECT generateRandomPaletteEffect() {
	array<PALETTE_EFFECT> possibleEffects = {PALETTE_EFFECT::GREYSCALE, PALETTE_EFFECT::SKETCH, PALETTE_EFFECT::SMOG, PALETTE_EFFECT::SEPIA};
	return possibleEffects[jjRandom() % possibleEffects.length()];
}

string stringifyPaletteEffect(PALETTE_EFFECT effect) {
	if(effect == PALETTE_EFFECT::GREYSCALE) return "GREYSCALE";
	if(effect == PALETTE_EFFECT::SKETCH) return "SKETCH";
	if(effect == PALETTE_EFFECT::SMOG) return "SMOG";
	if(effect == PALETTE_EFFECT::SEPIA) return "SEPIA";
	return "UNKNOWN PALETTE EFFECT";
}

se::colorEffect@ getPaletteEffect(PALETTE_EFFECT effect) {
	if(effect == PALETTE_EFFECT::GREYSCALE) return @se::colorGrayscale();
	if(effect == PALETTE_EFFECT::SKETCH) return @se::colorSketch(40);
	if(effect == PALETTE_EFFECT::SMOG) return @se::colorContrast(0.05);
	if(effect == PALETTE_EFFECT::SEPIA) return @se::colorSepia();
	return @null;
}

CHAR::Char generateRandomBird() {
	array<CHAR::Char> possibleBirds = {CHAR::BIRD, CHAR::BIRD2};
	return possibleBirds[jjRandom() % possibleBirds.length()];
}

CHAR::Char generateRandomRabbit() {
	array<CHAR::Char> possibleRabbits = {CHAR::JAZZ, CHAR::SPAZ, CHAR::LORI};
	if(!jjIsTSF)
		possibleRabbits.removeAt(2);
	return possibleRabbits[jjRandom() % possibleRabbits.length()];
}

CHAR::Char generateRandomRabbit(CHAR::Char exclude) {
	array<CHAR::Char> possibleRabbits = {CHAR::JAZZ, CHAR::SPAZ, CHAR::LORI};
	if(!jjIsTSF)
		possibleRabbits.removeAt(2);
	for(uint i = 0; i < possibleRabbits.length; i++)
		if(possibleRabbits[i] == exclude) 
			possibleRabbits.removeAt(i);
	return possibleRabbits[jjRandom() % possibleRabbits.length()];
}

SPREAD::Spread generateRandomSpread() {
	const array<SPREAD::Spread> possibleSpreads = {SPREAD::NORMAL, SPREAD::ICEPU, SPREAD::ICE, SPREAD::RFNORMAL, SPREAD::RFPU, SPREAD::RF, SPREAD::TOASTER};
	return possibleSpreads[jjRandom() % possibleSpreads.length()];
}

AIR::Jump generateRandomJumpType() {
	const array<AIR::Jump> possibleJumps = {AIR::HELICOPTER, AIR::DOUBLEJUMP};
	return possibleJumps[jjRandom() % possibleJumps.length()];
}

void scrambleJumpTypes() {
	jjCharacters[CHAR::JAZZ].airJump = AIR::DOUBLEJUMP;
	jjCharacters[CHAR::LORI].airJump = AIR::DOUBLEJUMP;
	jjCharacters[CHAR::SPAZ].airJump = AIR::HELICOPTER;
}

void restoreJumpTypes() {
	jjCharacters[CHAR::JAZZ].airJump = AIR::HELICOPTER;
	jjCharacters[CHAR::LORI].airJump = AIR::HELICOPTER;
	jjCharacters[CHAR::SPAZ].airJump = AIR::DOUBLEJUMP;
}

string timeFormat(uint time) {
	return time/SECOND + ":" + time%SECOND;
}

bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) {
	if(time > 0) {
		STRING::Size size = (time < 5*SECOND ? STRING::LARGE : STRING::MEDIUM);
		string text = (time > 5*SECOND ? "|" : (jjGameTicks/10 % 2 == 0 ? "||" : "")) + timeFormat(time);
		canvas.drawString(jjSubscreenWidth/2-50,20,text,size);
	}
	return false;
}

void sendMessage(string message) {
	jjAlert("|||||" + message,true,STRING::MEDIUM);
}

void onLevelLoad() {
	jjAnimSets[ANIM::SNOW].load();
	jjAnimSets[ANIM::PLUS_SCENERY].load();
	jjSugarRushAllowed = true;
}

void onLevelBegin() {
	for(uint i = 1; i <= 9; i++) {
		jjWeapons[i].allowed = true;
		jjWeapons[i].allowedPowerup = true;
	}
	jjSugarRushAllowed = true;
	jjCharacters[CHAR::JAZZ].doubleJumpCountMax = 1;
	jjCharacters[CHAR::LORI].doubleJumpCountMax = 1;
	jjCharacters[CHAR::JAZZ].doubleJumpYSpeed = -8;
	jjCharacters[CHAR::LORI].doubleJumpYSpeed = -8;
	jjCharacters[CHAR::FROG].canHurt = true;
	jjCharacters[CHAR::BIRD].canHurt = true;
	addAll(allEffects,positiveEffects);
	addAll(allEffects,negativeEffects);
	addAll(allEffects,neutralEffects);
	for(uint i = 1; i <= 9; i++)
		jjWeapons[i].maximum = 50;
	if(jjIsServer) {
		jjAlert("|C|H|A||O|S| ENABLED!",true,STRING::SMALL);
	} else {
		jjSTREAM stream;
		stream.push(PACKET_TYPE::JOIN);
		jjSendPacket(stream);
	}
}

void applyColorEffect(se::colorEffect@ effect) {
	jjPAL pal;
	for(uint i = 1; i < 256; i++)
		pal.color[i] = effect.getResult(jjBackupPalette.color[i]);
	pal.apply();
}

void timerReset() {
	timerCurStart = clamp(TIMER_MIN,timerCurStart-TIMER_DECREMENT,TIMER_MAX);
	sendTimerUpdate(timerCurStart,0);
	time = timerCurStart;
	generateEffect(allEffects);
}

void canRun(bool run) {
	jjCharacters[CHAR::JAZZ].canRun = run;
	jjCharacters[CHAR::SPAZ].canRun = run;
	jjCharacters[CHAR::LORI].canRun = run;
}

void onMain() {
	if(time > 0) {
		time--;
		if(time % (5*SECOND) == 1 && jjIsServer) sendTimerUpdate(time,0);
	} else if(time == 0) {
		if(jjIsServer) timerReset();
	}
	if(freezeTimer >= 0) {
		freezeTimer--;
		array<jjPLAYER@> affectedPlayers = getAffectedPlayers(freezeTarget);
		for(uint i = 0; i < affectedPlayers.length; i++)
			affectedPlayers[i].frozen = min(freezeTimer,255);
	}
	if(antiGravTimer >= 0)
		antiGravTimer--;
	if(antiGravTimer == 0) {
		array<jjPLAYER@> affectedPlayers = getAffectedPlayers(antiGravTarget);
		for(uint i = 0; i < affectedPlayers.length; i++) {
			affectedPlayers[i].antiGrav = false;
		}
	}
	if(animalTimer >= 0)
		animalTimer--;
	if(animalTimer == 0) {
		array<jjPLAYER@> affectedPlayers = getAffectedPlayers(animalTarget);
		for(uint i = 0; i < affectedPlayers.length; i++) {
			affectedPlayers[i].morphTo(generateRandomRabbit());
		}
	}
	if(paletteEffectTimer >= 0)
		paletteEffectTimer--;
	if(paletteEffectTimer > 0) {	
		if(jjLocalPlayers[0].isInGame) {
			if(psychadelic) {
				if(jjGameTicks % 2 == 0) { // To improve performance
					se::colorEffect@ effect = se::colorShiftHue(uint(linear(jjGameTicks,0,255,255)));
					applyColorEffect(effect);
				}
			} 
		}
	} else if(paletteEffectTimer == 0) {
		jjBackupPalette.apply();
		psychadelic = false;
	}
	if(canRunTimer >= 0)
		canRunTimer--;
	if(canRunTimer == 0)
		canRun(true);
	if(noFireTimer >= 0)
		noFireTimer--;
	if(noFireTimer == 0) {
		array<jjPLAYER@> affectedPlayers = getAffectedPlayers(noFireTarget);
		for(uint i = 0; i < affectedPlayers.length; i++) {
			affectedPlayers[i].noFire = false;
		}
	}
	if(waterTimer >= 0)
		waterTimer--;
	if(waterTimer == 0) {
		jjSetWaterLevel(jjLayerHeight[4]*32,false);
	}
	if(invisibleTimer >= 0)
		invisibleTimer--;
	if(invisibleTimer == 0) {
		array<jjPLAYER@> affectedPlayers = getAffectedPlayers(invisibleTarget);
		for(uint i = 0; i < affectedPlayers.length; i++) {
			affectedPlayers[i].invisibility = false;
		}
	}
	if(jumpTypesTimer >= 0)
		jumpTypesTimer--;
	if(jumpTypesTimer == 0) {
		array<jjPLAYER@> affectedPlayers = getAffectedPlayers(jumpTypesTarget);
		for(uint i = 0; i < affectedPlayers.length; i++) {
			restoreJumpTypes();
		}
	}
	if(tunnelVisionTimer >= 0) {
		tunnelVisionTimer--;
		jjDrawRectangle(p.xPos+jjSubscreenWidth/4 + jjSubscreenWidth/8*jjSin(jjGameTicks),p.yPos-jjSubscreenHeight, jjSubscreenWidth, jjSubscreenHeight*2, 0, SPRITE::NORMAL, 0, 1);
		
		jjDrawRectangle(p.xPos-jjSubscreenWidth,p.yPos+jjSubscreenHeight/4 - jjSubscreenHeight/8*jjSin(jjGameTicks), jjSubscreenWidth*2, jjSubscreenHeight*2, 0, SPRITE::NORMAL, 0, 1);
		
		jjDrawRectangle(p.xPos-jjSubscreenWidth*1.25 + jjSubscreenWidth/8*jjSin(jjGameTicks),p.yPos-jjSubscreenHeight, jjSubscreenWidth, jjSubscreenHeight*2, 0, SPRITE::NORMAL, 0, 1);
		
		jjDrawRectangle(p.xPos-jjSubscreenWidth,p.yPos-jjSubscreenHeight*1.25+ jjSubscreenHeight/8*jjSin(jjGameTicks), jjSubscreenWidth*2, jjSubscreenHeight, 0, SPRITE::NORMAL, 0, 1);
	}
}